blob: 939e2f76b9596203ab68276a59aad6fd8c36981e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchad7a2922008-02-07 23:25:02 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Igor Mammedovfec45852008-05-16 13:06:30 +040084/* Allocates buffer into dst and copies smb string from src to it.
85 * caller is responsible for freeing dst if function returned 0.
86 * returns:
87 * on success - 0
88 * on failure - errno
89 */
90static int
91cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
92 const bool is_unicode, const struct nls_table *nls_codepage)
93{
94 int plen;
95
96 if (is_unicode) {
97 plen = UniStrnlen((wchar_t *)src, maxlen);
98 *dst = kmalloc(plen + 2, GFP_KERNEL);
99 if (!*dst)
100 goto cifs_strncpy_to_host_ErrExit;
101 cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
102 } else {
103 plen = strnlen(src, maxlen);
104 *dst = kmalloc(plen + 2, GFP_KERNEL);
105 if (!*dst)
106 goto cifs_strncpy_to_host_ErrExit;
107 strncpy(*dst, src, plen);
108 }
109 (*dst)[plen] = 0;
Steve Frencha1fe78f2008-05-16 18:48:38 +0000110 (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
Igor Mammedovfec45852008-05-16 13:06:30 +0400111 return 0;
112
113cifs_strncpy_to_host_ErrExit:
114 cERROR(1, ("Failed to allocate buffer for string\n"));
115 return -ENOMEM;
116}
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/* Mark as invalid, all open files on tree connections since they
120 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +0000121static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000124 struct list_head *tmp;
125 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127/* list all files open on tree connection and mark them invalid */
128 write_lock(&GlobalSMBSeslock);
129 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000130 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000131 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700134 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
135 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Steve Frenchad7a2922008-02-07 23:25:02 +0000138/* Allocate and return pointer to an SMB request buffer, and set basic
139 SMB information in the SMB header. If the return code is zero, this
140 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int
142small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000143 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 int rc = 0;
146
147 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
148 check for tcp and smb session status done differently
149 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000150 if (tcon) {
151 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800152 /* only tree disconnect, open, and write,
153 (and ulogoff which does not have tcon)
154 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000155 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000156 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800157 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000158 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800159 smb_command));
160 return -ENODEV;
161 }
162 }
Steve French790fe572007-07-07 19:25:05 +0000163 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000164 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000166 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700167 reconnect, should be greater than cifs socket
168 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000169 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000170 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000172 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000173 CifsGood), 10 * HZ);
174 if (tcon->ses->server->tcpStatus ==
175 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000177 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000179 cFYI(1, ("gave up waiting on "
180 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700182 } /* else "hard" mount - keep retrying
183 until process is killed or server
184 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 } else /* TCP session is reestablished now */
186 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 }
Steve French50c2f752007-07-13 00:33:32 +0000188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 nls_codepage = load_nls_default();
190 /* need to prevent multiple threads trying to
191 simultaneously reconnect the same SMB session */
192 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000193 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000194 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700195 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000196 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000198 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000199 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700201 /* BB FIXME add code to check if wsize needs
202 update due to negotiated smb buffer size
203 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000204 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000206 /* tell server Unix caps we support */
207 if (tcon->ses->capabilities & CAP_UNIX)
208 reset_cifs_unix_caps(
209 0 /* no xid */,
210 tcon,
211 NULL /* we do not know sb */,
212 NULL /* no vol info */);
213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000216 /* Removed call to reopen open files here.
217 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700218 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Steve French50c2f752007-07-13 00:33:32 +0000220 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700221 know whether we can continue or not without
222 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000223 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 case SMB_COM_READ_ANDX:
225 case SMB_COM_WRITE_ANDX:
226 case SMB_COM_CLOSE:
227 case SMB_COM_FIND_CLOSE2:
228 case SMB_COM_LOCKING_ANDX: {
229 unload_nls(nls_codepage);
230 return -EAGAIN;
231 }
232 }
233 } else {
234 up(&tcon->ses->sesSem);
235 }
236 unload_nls(nls_codepage);
237
238 } else {
239 return -EIO;
240 }
241 }
Steve French790fe572007-07-07 19:25:05 +0000242 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 return rc;
244
245 *request_buf = cifs_small_buf_get();
246 if (*request_buf == NULL) {
247 /* BB should we add a retry in here if not a writepage? */
248 return -ENOMEM;
249 }
250
Steve French63135e02007-07-17 17:34:02 +0000251 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000252 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Steve French790fe572007-07-07 19:25:05 +0000254 if (tcon != NULL)
255 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000258}
259
Steve French12b3b8f2006-02-09 21:12:47 +0000260int
Steve French50c2f752007-07-13 00:33:32 +0000261small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000262 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000263{
264 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000265 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000266
Steve French5815449d2006-02-14 01:36:20 +0000267 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000268 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 return rc;
270
Steve French04fdabe2006-02-10 05:52:50 +0000271 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000272 buffer->Mid = GetNextMid(ses->server);
273 if (ses->capabilities & CAP_UNICODE)
274 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000275 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000276 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
277
278 /* uid, tid can stay at zero as set in header assemble */
279
Steve French50c2f752007-07-13 00:33:32 +0000280 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000281 this function is used after 1st of session setup requests */
282
283 return rc;
284}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286/* If the return code is zero, this function must fill in request_buf pointer */
287static int
288smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
289 void **request_buf /* returned */ ,
290 void **response_buf /* returned */ )
291{
292 int rc = 0;
293
294 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
295 check for tcp and smb session status done differently
296 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000297 if (tcon) {
Steve Frenchbfb598202008-11-18 16:33:48 +0000298 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800299 /* only tree disconnect, open, and write,
300 (and ulogoff which does not have tcon)
301 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000302 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800303 (smb_command != SMB_COM_OPEN_ANDX) &&
304 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000305 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800306 smb_command));
307 return -ENODEV;
308 }
309 }
310
Steve French790fe572007-07-07 19:25:05 +0000311 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000312 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700314 /* Give Demultiplex thread up to 10 seconds to
315 reconnect, should be greater than cifs socket
316 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000317 while (tcon->ses->server->tcpStatus ==
318 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000320 (tcon->ses->server->tcpStatus ==
321 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000322 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700323 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000325 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000327 cFYI(1, ("gave up waiting on "
328 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700330 } /* else "hard" mount - keep retrying
331 until process is killed or server
332 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 } else /* TCP session is reestablished now */
334 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 nls_codepage = load_nls_default();
337 /* need to prevent multiple threads trying to
338 simultaneously reconnect the same SMB session */
339 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000340 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000341 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700342 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000343 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700345 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
346 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700348 /* BB FIXME add code to check if wsize needs
349 update due to negotiated smb buffer size
350 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000351 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000353 /* tell server Unix caps we support */
354 if (tcon->ses->capabilities & CAP_UNIX)
355 reset_cifs_unix_caps(
356 0 /* no xid */,
357 tcon,
358 NULL /* do not know sb */,
359 NULL /* no vol info */);
360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000363 /* Removed call to reopen open files here.
364 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700365 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Steve French50c2f752007-07-13 00:33:32 +0000367 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700368 know whether we can continue or not without
369 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000370 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 case SMB_COM_READ_ANDX:
372 case SMB_COM_WRITE_ANDX:
373 case SMB_COM_CLOSE:
374 case SMB_COM_FIND_CLOSE2:
375 case SMB_COM_LOCKING_ANDX: {
376 unload_nls(nls_codepage);
377 return -EAGAIN;
378 }
379 }
380 } else {
381 up(&tcon->ses->sesSem);
382 }
383 unload_nls(nls_codepage);
384
385 } else {
386 return -EIO;
387 }
388 }
Steve French790fe572007-07-07 19:25:05 +0000389 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return rc;
391
392 *request_buf = cifs_buf_get();
393 if (*request_buf == NULL) {
394 /* BB should we add a retry in here if not a writepage? */
395 return -ENOMEM;
396 }
397 /* Although the original thought was we needed the response buf for */
398 /* potential retries of smb operations it turns out we can determine */
399 /* from the mid flags when the request buffer can be resent without */
400 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000401 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000402 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000405 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Steve French790fe572007-07-07 19:25:05 +0000407 if (tcon != NULL)
408 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return rc;
411}
412
Steve French50c2f752007-07-13 00:33:32 +0000413static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
415 int rc = -EINVAL;
416 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000417 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /* check for plausible wct, bcc and t2 data and parm sizes */
420 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000421 if (pSMB->hdr.WordCount >= 10) {
422 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
424 /* check that bcc is at least as big as parms + data */
425 /* check that bcc is less than negotiated smb buffer */
426 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000427 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000428 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000429 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000431 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700432 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000434 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000435 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
437 return 0;
438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440 }
441 }
Steve French50c2f752007-07-13 00:33:32 +0000442 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 sizeof(struct smb_t2_rsp) + 16);
444 return rc;
445}
446int
447CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
448{
449 NEGOTIATE_REQ *pSMB;
450 NEGOTIATE_RSP *pSMBr;
451 int rc = 0;
452 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000453 int i;
Steve French50c2f752007-07-13 00:33:32 +0000454 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000456 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100457 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Steve French790fe572007-07-07 19:25:05 +0000459 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 server = ses->server;
461 else {
462 rc = -EIO;
463 return rc;
464 }
465 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
466 (void **) &pSMB, (void **) &pSMBr);
467 if (rc)
468 return rc;
Steve French750d1152006-06-27 06:28:30 +0000469
470 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000471 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000472 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000473 else /* if override flags set only sign/seal OR them with global auth */
474 secFlags = extended_security | ses->overrideSecFlg;
475
Steve French762e5ab2007-06-28 18:41:42 +0000476 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000477
Steve French1982c342005-08-17 12:38:22 -0700478 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000479 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000480
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000481 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000482 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000483 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
484 cFYI(1, ("Kerberos only mechanism, enable extended security"));
485 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
486 }
Steve French50c2f752007-07-13 00:33:32 +0000487
Steve French39798772006-05-31 22:40:51 +0000488 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000489 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000490 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
491 count += strlen(protocols[i].name) + 1;
492 /* null at end of source and target buffers anyway */
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 pSMB->hdr.smb_buf_length += count;
495 pSMB->ByteCount = cpu_to_le16(count);
496
497 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000499 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000500 goto neg_err_exit;
501
Al Viro733f99a2006-10-14 16:48:26 +0100502 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000503 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000504 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000505 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000506 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000507 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000508 could not negotiate a common dialect */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000511#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000512 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100513 && ((dialect == LANMAN_PROT)
514 || (dialect == LANMAN2_PROT))) {
Steve 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 Frencheca6acf2009-02-20 05:43:09 +0000531 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000532 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
533 /* even though we do not use raw we might as well set this
534 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000535 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000536 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000537 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
538 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000539 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000540 server->capabilities = CAP_MPX_MODE;
541 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000542 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000543 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000544 /* OS/2 often does not set timezone therefore
545 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000546 * Could deviate slightly from the right zone.
547 * Smallest defined timezone difference is 15 minutes
548 * (i.e. Nepal). Rounding up/down is done to match
549 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000550 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000551 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000552 struct timespec ts, utc;
553 utc = CURRENT_TIME;
554 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
555 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000556 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
557 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000558 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000559 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000560 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000561 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000562 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000563 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000564 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000565 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000566 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000567 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000568 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000569 server->timeAdj = (int)tmp;
570 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000571 }
Steve French790fe572007-07-07 19:25:05 +0000572 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000573
Steve French39798772006-05-31 22:40:51 +0000574
Steve French254e55e2006-06-04 05:53:15 +0000575 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000576 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000577
Steve French50c2f752007-07-13 00:33:32 +0000578 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000579 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000580 memcpy(server->cryptKey, rsp->EncryptionKey,
581 CIFS_CRYPTO_KEY_SIZE);
582 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
583 rc = -EIO; /* need cryptkey unless plain text */
584 goto neg_err_exit;
585 }
Steve French39798772006-05-31 22:40:51 +0000586
Steve French790fe572007-07-07 19:25:05 +0000587 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000588 /* we will not end up setting signing flags - as no signing
589 was in LANMAN and server did not return the flags on */
590 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000591#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000592 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000593 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000594 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000595 rc = -EOPNOTSUPP;
596#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000597 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000598 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000599 /* unknown wct */
600 rc = -EOPNOTSUPP;
601 goto neg_err_exit;
602 }
603 /* else wct == 17 NTLM */
604 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000605 if ((server->secMode & SECMODE_USER) == 0)
606 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000607
Steve French790fe572007-07-07 19:25:05 +0000608 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000609#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000610 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000611#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000612 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000613 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000614
Steve French790fe572007-07-07 19:25:05 +0000615 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000616 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000617 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000618 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000619 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000620 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000621 else if (secFlags & CIFSSEC_MAY_KRB5)
622 server->secType = Kerberos;
623 else if (secFlags & CIFSSEC_MAY_LANMAN)
624 server->secType = LANMAN;
625/* #ifdef CONFIG_CIFS_EXPERIMENTAL
626 else if (secFlags & CIFSSEC_MAY_PLNTXT)
627 server->secType = ??
628#endif */
629 else {
630 rc = -EOPNOTSUPP;
631 cERROR(1, ("Invalid security type"));
632 goto neg_err_exit;
633 }
634 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000635
Steve French254e55e2006-06-04 05:53:15 +0000636 /* one byte, so no need to convert this or EncryptionKeyLen from
637 little endian */
638 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
639 /* probably no need to store and check maxvcs */
640 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000642 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000643 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000644 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
645 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000646 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
647 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000648 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
649 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
650 CIFS_CRYPTO_KEY_SIZE);
651 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
652 && (pSMBr->EncryptionKeyLength == 0)) {
653 /* decode security blob */
654 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
655 rc = -EIO; /* no crypt key only if plain text pwd */
656 goto neg_err_exit;
657 }
658
659 /* BB might be helpful to save off the domain of server here */
660
Steve French50c2f752007-07-13 00:33:32 +0000661 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000662 (server->capabilities & CAP_EXTENDED_SECURITY)) {
663 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000664 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000666 goto neg_err_exit;
667 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500668 read_lock(&cifs_tcp_ses_lock);
669 if (server->srv_count > 1) {
670 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000671 if (memcmp(server->server_GUID,
672 pSMBr->u.extended_response.
673 GUID, 16) != 0) {
674 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000675 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000676 pSMBr->u.extended_response.GUID,
677 16);
678 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500679 } else {
680 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000681 memcpy(server->server_GUID,
682 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500683 }
Jeff Laytone187e442007-10-16 17:10:44 +0000684
685 if (count == 16) {
686 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000687 } else {
688 rc = decode_negTokenInit(pSMBr->u.extended_response.
689 SecurityBlob,
690 count - 16,
691 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000692 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000693 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000694 else
Steve French254e55e2006-06-04 05:53:15 +0000695 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 }
Steve French254e55e2006-06-04 05:53:15 +0000697 } else
698 server->capabilities &= ~CAP_EXTENDED_SECURITY;
699
Steve French6344a422006-06-12 04:18:35 +0000700#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000701signing_check:
Steve French6344a422006-06-12 04:18:35 +0000702#endif
Steve French762e5ab2007-06-28 18:41:42 +0000703 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
704 /* MUST_SIGN already includes the MAY_SIGN FLAG
705 so if this is zero it means that signing is disabled */
706 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000707 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000708 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000709 "packet signing to be enabled in "
710 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000711 rc = -EOPNOTSUPP;
712 }
Steve French50c2f752007-07-13 00:33:32 +0000713 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000714 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000715 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
716 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000717 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000718 if ((server->secMode &
719 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
720 cERROR(1,
721 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000722 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000723 } else
724 server->secMode |= SECMODE_SIGN_REQUIRED;
725 } else {
726 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000727 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000728 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000729 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
Steve French50c2f752007-07-13 00:33:32 +0000731
732neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700733 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000734
Steve French790fe572007-07-07 19:25:05 +0000735 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 return rc;
737}
738
739int
740CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
741{
742 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500746
747 /* BB: do we need to check this? These should never be NULL. */
748 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
749 return -EIO;
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500752 * No need to return error on this operation if tid invalidated and
753 * closed on server already e.g. due to tcp session crashing. Also,
754 * the tcon is no longer on the list, so no need to take lock before
755 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 */
Jeff Laytonf1987b42008-11-15 11:12:47 -0500757 if (tcon->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000758 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Steve French50c2f752007-07-13 00:33:32 +0000760 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700761 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500762 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return rc;
Steve French133672e2007-11-13 22:41:37 +0000764
765 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700767 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Steve French50c2f752007-07-13 00:33:32 +0000769 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500770 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 if (rc == -EAGAIN)
772 rc = 0;
773
774 return rc;
775}
776
777int
778CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
779{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 LOGOFF_ANDX_REQ *pSMB;
781 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500784
785 /*
786 * BB: do we need to check validity of ses and server? They should
787 * always be valid since we have an active reference. If not, that
788 * should probably be a BUG()
789 */
790 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 return -EIO;
792
Jeff Layton14fbf502008-11-14 13:53:46 -0500793 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000794 if (ses->need_reconnect)
795 goto session_already_dead; /* no need to send SMBlogoff if uid
796 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
798 if (rc) {
799 up(&ses->sesSem);
800 return rc;
801 }
802
Steve French3b795212008-11-13 19:45:32 +0000803 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700804
Steve French3b795212008-11-13 19:45:32 +0000805 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
807 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
809 pSMB->hdr.Uid = ses->Suid;
810
811 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000812 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000813session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700814 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000817 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 error */
819 if (rc == -EAGAIN)
820 rc = 0;
821 return rc;
822}
823
824int
Steve French2d785a52007-07-15 01:48:57 +0000825CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
826 __u16 type, const struct nls_table *nls_codepage, int remap)
827{
828 TRANSACTION2_SPI_REQ *pSMB = NULL;
829 TRANSACTION2_SPI_RSP *pSMBr = NULL;
830 struct unlink_psx_rq *pRqD;
831 int name_len;
832 int rc = 0;
833 int bytes_returned = 0;
834 __u16 params, param_offset, offset, byte_count;
835
836 cFYI(1, ("In POSIX delete"));
837PsxDelete:
838 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
839 (void **) &pSMBr);
840 if (rc)
841 return rc;
842
843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
844 name_len =
845 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
846 PATH_MAX, nls_codepage, remap);
847 name_len++; /* trailing null */
848 name_len *= 2;
849 } else { /* BB add path length overrun check */
850 name_len = strnlen(fileName, PATH_MAX);
851 name_len++; /* trailing null */
852 strncpy(pSMB->FileName, fileName, name_len);
853 }
854
855 params = 6 + name_len;
856 pSMB->MaxParameterCount = cpu_to_le16(2);
857 pSMB->MaxDataCount = 0; /* BB double check this with jra */
858 pSMB->MaxSetupCount = 0;
859 pSMB->Reserved = 0;
860 pSMB->Flags = 0;
861 pSMB->Timeout = 0;
862 pSMB->Reserved2 = 0;
863 param_offset = offsetof(struct smb_com_transaction2_spi_req,
864 InformationLevel) - 4;
865 offset = param_offset + params;
866
867 /* Setup pointer to Request Data (inode type) */
868 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
869 pRqD->type = cpu_to_le16(type);
870 pSMB->ParameterOffset = cpu_to_le16(param_offset);
871 pSMB->DataOffset = cpu_to_le16(offset);
872 pSMB->SetupCount = 1;
873 pSMB->Reserved3 = 0;
874 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
875 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
876
877 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
878 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
879 pSMB->ParameterCount = cpu_to_le16(params);
880 pSMB->TotalParameterCount = pSMB->ParameterCount;
881 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
882 pSMB->Reserved4 = 0;
883 pSMB->hdr.smb_buf_length += byte_count;
884 pSMB->ByteCount = cpu_to_le16(byte_count);
885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000887 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000888 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000889 cifs_buf_release(pSMB);
890
891 cifs_stats_inc(&tcon->num_deletes);
892
893 if (rc == -EAGAIN)
894 goto PsxDelete;
895
896 return rc;
897}
898
899int
Steve French737b7582005-04-28 22:41:06 -0700900CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
901 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902{
903 DELETE_FILE_REQ *pSMB = NULL;
904 DELETE_FILE_RSP *pSMBr = NULL;
905 int rc = 0;
906 int bytes_returned;
907 int name_len;
908
909DelFileRetry:
910 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
911 (void **) &pSMBr);
912 if (rc)
913 return rc;
914
915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
916 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000917 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700918 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 name_len++; /* trailing null */
920 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700921 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 name_len = strnlen(fileName, PATH_MAX);
923 name_len++; /* trailing null */
924 strncpy(pSMB->fileName, fileName, name_len);
925 }
926 pSMB->SearchAttributes =
927 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
928 pSMB->BufferFormat = 0x04;
929 pSMB->hdr.smb_buf_length += name_len + 1;
930 pSMB->ByteCount = cpu_to_le16(name_len + 1);
931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700933 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000934 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936
937 cifs_buf_release(pSMB);
938 if (rc == -EAGAIN)
939 goto DelFileRetry;
940
941 return rc;
942}
943
944int
Steve French50c2f752007-07-13 00:33:32 +0000945CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700946 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
948 DELETE_DIRECTORY_REQ *pSMB = NULL;
949 DELETE_DIRECTORY_RSP *pSMBr = NULL;
950 int rc = 0;
951 int bytes_returned;
952 int name_len;
953
954 cFYI(1, ("In CIFSSMBRmDir"));
955RmDirRetry:
956 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
957 (void **) &pSMBr);
958 if (rc)
959 return rc;
960
961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700962 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 name_len++; /* trailing null */
965 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700966 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 name_len = strnlen(dirName, PATH_MAX);
968 name_len++; /* trailing null */
969 strncpy(pSMB->DirName, dirName, name_len);
970 }
971
972 pSMB->BufferFormat = 0x04;
973 pSMB->hdr.smb_buf_length += name_len + 1;
974 pSMB->ByteCount = cpu_to_le16(name_len + 1);
975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700977 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000978 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 cifs_buf_release(pSMB);
982 if (rc == -EAGAIN)
983 goto RmDirRetry;
984 return rc;
985}
986
987int
988CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700989 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 int rc = 0;
992 CREATE_DIRECTORY_REQ *pSMB = NULL;
993 CREATE_DIRECTORY_RSP *pSMBr = NULL;
994 int bytes_returned;
995 int name_len;
996
997 cFYI(1, ("In CIFSSMBMkDir"));
998MkDirRetry:
999 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1000 (void **) &pSMBr);
1001 if (rc)
1002 return rc;
1003
1004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001005 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 name_len++; /* trailing null */
1008 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001009 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 name_len = strnlen(name, PATH_MAX);
1011 name_len++; /* trailing null */
1012 strncpy(pSMB->DirName, name, name_len);
1013 }
1014
1015 pSMB->BufferFormat = 0x04;
1016 pSMB->hdr.smb_buf_length += name_len + 1;
1017 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001020 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001021 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 cifs_buf_release(pSMB);
1025 if (rc == -EAGAIN)
1026 goto MkDirRetry;
1027 return rc;
1028}
1029
Steve French2dd29d32007-04-23 22:07:35 +00001030int
1031CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001032 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001033 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001034 const struct nls_table *nls_codepage, int remap)
1035{
1036 TRANSACTION2_SPI_REQ *pSMB = NULL;
1037 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1038 int name_len;
1039 int rc = 0;
1040 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001041 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001042 OPEN_PSX_REQ *pdata;
1043 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001044
1045 cFYI(1, ("In POSIX Create"));
1046PsxCreat:
1047 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1048 (void **) &pSMBr);
1049 if (rc)
1050 return rc;
1051
1052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1053 name_len =
1054 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1055 PATH_MAX, nls_codepage, remap);
1056 name_len++; /* trailing null */
1057 name_len *= 2;
1058 } else { /* BB improve the check for buffer overruns BB */
1059 name_len = strnlen(name, PATH_MAX);
1060 name_len++; /* trailing null */
1061 strncpy(pSMB->FileName, name, name_len);
1062 }
1063
1064 params = 6 + name_len;
1065 count = sizeof(OPEN_PSX_REQ);
1066 pSMB->MaxParameterCount = cpu_to_le16(2);
1067 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1068 pSMB->MaxSetupCount = 0;
1069 pSMB->Reserved = 0;
1070 pSMB->Flags = 0;
1071 pSMB->Timeout = 0;
1072 pSMB->Reserved2 = 0;
1073 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001074 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001075 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001076 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001077 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001078 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001079 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001080 pdata->OpenFlags = cpu_to_le32(*pOplock);
1081 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1082 pSMB->DataOffset = cpu_to_le16(offset);
1083 pSMB->SetupCount = 1;
1084 pSMB->Reserved3 = 0;
1085 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1086 byte_count = 3 /* pad */ + params + count;
1087
1088 pSMB->DataCount = cpu_to_le16(count);
1089 pSMB->ParameterCount = cpu_to_le16(params);
1090 pSMB->TotalDataCount = pSMB->DataCount;
1091 pSMB->TotalParameterCount = pSMB->ParameterCount;
1092 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1093 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001094 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001095 pSMB->ByteCount = cpu_to_le16(byte_count);
1096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1098 if (rc) {
1099 cFYI(1, ("Posix create returned %d", rc));
1100 goto psx_create_err;
1101 }
1102
Steve French790fe572007-07-07 19:25:05 +00001103 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001104 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1105
1106 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1107 rc = -EIO; /* bad smb */
1108 goto psx_create_err;
1109 }
1110
1111 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001112 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001113 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001114
Steve French2dd29d32007-04-23 22:07:35 +00001115 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001116 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001117 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1118 /* Let caller know file was created so we can set the mode. */
1119 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001120 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001121 *pOplock |= CIFS_CREATE_ACTION;
1122 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001123 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1124 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001125 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001126 } else {
Steve French790fe572007-07-07 19:25:05 +00001127 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001128 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001129 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001130 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001131 goto psx_create_err;
1132 }
Steve French50c2f752007-07-13 00:33:32 +00001133 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001134 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001135 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001136 }
Steve French2dd29d32007-04-23 22:07:35 +00001137
1138psx_create_err:
1139 cifs_buf_release(pSMB);
1140
1141 cifs_stats_inc(&tcon->num_mkdirs);
1142
1143 if (rc == -EAGAIN)
1144 goto PsxCreat;
1145
Steve French50c2f752007-07-13 00:33:32 +00001146 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001147}
1148
Steve Frencha9d02ad2005-08-24 23:06:05 -07001149static __u16 convert_disposition(int disposition)
1150{
1151 __u16 ofun = 0;
1152
1153 switch (disposition) {
1154 case FILE_SUPERSEDE:
1155 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1156 break;
1157 case FILE_OPEN:
1158 ofun = SMBOPEN_OAPPEND;
1159 break;
1160 case FILE_CREATE:
1161 ofun = SMBOPEN_OCREATE;
1162 break;
1163 case FILE_OPEN_IF:
1164 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1165 break;
1166 case FILE_OVERWRITE:
1167 ofun = SMBOPEN_OTRUNC;
1168 break;
1169 case FILE_OVERWRITE_IF:
1170 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1171 break;
1172 default:
Steve French790fe572007-07-07 19:25:05 +00001173 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 ofun = SMBOPEN_OAPPEND; /* regular open */
1175 }
1176 return ofun;
1177}
1178
Jeff Layton35fc37d2008-05-14 10:22:03 -07001179static int
1180access_flags_to_smbopen_mode(const int access_flags)
1181{
1182 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1183
1184 if (masked_flags == GENERIC_READ)
1185 return SMBOPEN_READ;
1186 else if (masked_flags == GENERIC_WRITE)
1187 return SMBOPEN_WRITE;
1188
1189 /* just go for read/write */
1190 return SMBOPEN_READWRITE;
1191}
1192
Steve Frencha9d02ad2005-08-24 23:06:05 -07001193int
1194SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1195 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001196 const int access_flags, const int create_options, __u16 *netfid,
1197 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001198 const struct nls_table *nls_codepage, int remap)
1199{
1200 int rc = -EACCES;
1201 OPENX_REQ *pSMB = NULL;
1202 OPENX_RSP *pSMBr = NULL;
1203 int bytes_returned;
1204 int name_len;
1205 __u16 count;
1206
1207OldOpenRetry:
1208 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1209 (void **) &pSMBr);
1210 if (rc)
1211 return rc;
1212
1213 pSMB->AndXCommand = 0xFF; /* none */
1214
1215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1216 count = 1; /* account for one byte pad to word boundary */
1217 name_len =
1218 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1219 fileName, PATH_MAX, nls_codepage, remap);
1220 name_len++; /* trailing null */
1221 name_len *= 2;
1222 } else { /* BB improve check for buffer overruns BB */
1223 count = 0; /* no pad */
1224 name_len = strnlen(fileName, PATH_MAX);
1225 name_len++; /* trailing null */
1226 strncpy(pSMB->fileName, fileName, name_len);
1227 }
1228 if (*pOplock & REQ_OPLOCK)
1229 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001230 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001232
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001234 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001235 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1236 /* set file as system file if special file such
1237 as fifo and server expecting SFU style and
1238 no Unix extensions */
1239
Steve French790fe572007-07-07 19:25:05 +00001240 if (create_options & CREATE_OPTION_SPECIAL)
1241 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001242 else /* BB FIXME BB */
1243 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244
Jeff Layton67750fb2008-05-09 22:28:02 +00001245 if (create_options & CREATE_OPTION_READONLY)
1246 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247
1248 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001249/* pSMB->CreateOptions = cpu_to_le32(create_options &
1250 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001252
1253 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001254 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 count += name_len;
1256 pSMB->hdr.smb_buf_length += count;
1257
1258 pSMB->ByteCount = cpu_to_le16(count);
1259 /* long_op set to 1 to allow for oplock break timeouts */
1260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001261 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262 cifs_stats_inc(&tcon->num_opens);
1263 if (rc) {
1264 cFYI(1, ("Error in Open = %d", rc));
1265 } else {
1266 /* BB verify if wct == 15 */
1267
Steve French582d21e2008-05-13 04:54:12 +00001268/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269
1270 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1271 /* Let caller know file was created so we can set the mode. */
1272 /* Do we care about the CreateAction in any other cases? */
1273 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001274/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 *pOplock |= CIFS_CREATE_ACTION; */
1276 /* BB FIXME END */
1277
Steve French790fe572007-07-07 19:25:05 +00001278 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001279 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1280 pfile_info->LastAccessTime = 0; /* BB fixme */
1281 pfile_info->LastWriteTime = 0; /* BB fixme */
1282 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001283 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001284 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001285 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001286 pfile_info->AllocationSize =
1287 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1288 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001289 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001290 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001291 }
1292 }
1293
1294 cifs_buf_release(pSMB);
1295 if (rc == -EAGAIN)
1296 goto OldOpenRetry;
1297 return rc;
1298}
1299
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300int
1301CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1302 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001303 const int access_flags, const int create_options, __u16 *netfid,
1304 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001305 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
1307 int rc = -EACCES;
1308 OPEN_REQ *pSMB = NULL;
1309 OPEN_RSP *pSMBr = NULL;
1310 int bytes_returned;
1311 int name_len;
1312 __u16 count;
1313
1314openRetry:
1315 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1316 (void **) &pSMBr);
1317 if (rc)
1318 return rc;
1319
1320 pSMB->AndXCommand = 0xFF; /* none */
1321
1322 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1323 count = 1; /* account for one byte pad to word boundary */
1324 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001325 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001326 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 name_len++; /* trailing null */
1328 name_len *= 2;
1329 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001330 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 count = 0; /* no pad */
1332 name_len = strnlen(fileName, PATH_MAX);
1333 name_len++; /* trailing null */
1334 pSMB->NameLength = cpu_to_le16(name_len);
1335 strncpy(pSMB->fileName, fileName, name_len);
1336 }
1337 if (*pOplock & REQ_OPLOCK)
1338 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001339 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1342 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001343 /* set file as system file if special file such
1344 as fifo and server expecting SFU style and
1345 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001346 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001347 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1348 else
1349 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001350
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 /* XP does not handle ATTR_POSIX_SEMANTICS */
1352 /* but it helps speed up case sensitive checks for other
1353 servers such as Samba */
1354 if (tcon->ses->capabilities & CAP_UNIX)
1355 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1356
Jeff Layton67750fb2008-05-09 22:28:02 +00001357 if (create_options & CREATE_OPTION_READONLY)
1358 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1359
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1361 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001362 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001363 /* BB Expirement with various impersonation levels and verify */
1364 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 pSMB->SecurityFlags =
1366 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1367
1368 count += name_len;
1369 pSMB->hdr.smb_buf_length += count;
1370
1371 pSMB->ByteCount = cpu_to_le16(count);
1372 /* long_op set to 1 to allow for oplock break timeouts */
1373 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001374 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001375 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (rc) {
1377 cFYI(1, ("Error in Open = %d", rc));
1378 } else {
Steve French09d1db52005-04-28 22:41:08 -07001379 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1381 /* Let caller know file was created so we can set the mode. */
1382 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001383 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001384 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001385 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001386 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1387 36 /* CreationTime to Attributes */);
1388 /* the file_info buf is endian converted by caller */
1389 pfile_info->AllocationSize = pSMBr->AllocationSize;
1390 pfile_info->EndOfFile = pSMBr->EndOfFile;
1391 pfile_info->NumberOfLinks = cpu_to_le32(1);
1392 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001395
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 cifs_buf_release(pSMB);
1397 if (rc == -EAGAIN)
1398 goto openRetry;
1399 return rc;
1400}
1401
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402int
Steve French50c2f752007-07-13 00:33:32 +00001403CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1404 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1405 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406{
1407 int rc = -EACCES;
1408 READ_REQ *pSMB = NULL;
1409 READ_RSP *pSMBr = NULL;
1410 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001411 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001412 int resp_buf_type = 0;
1413 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
Steve French790fe572007-07-07 19:25:05 +00001415 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1416 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001417 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001418 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001419 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001420 if ((lseek >> 32) > 0) {
1421 /* can not handle this big offset for old */
1422 return -EIO;
1423 }
1424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001427 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 if (rc)
1429 return rc;
1430
1431 /* tcon and ses pointer are checked in smb_init */
1432 if (tcon->ses->server == NULL)
1433 return -ECONNABORTED;
1434
Steve Frenchec637e32005-12-12 20:53:18 -08001435 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 pSMB->Fid = netfid;
1437 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001438 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001439 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001440
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 pSMB->Remaining = 0;
1442 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1443 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001444 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001445 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1446 else {
1447 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001448 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001449 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001450 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001451 }
Steve Frenchec637e32005-12-12 20:53:18 -08001452
1453 iov[0].iov_base = (char *)pSMB;
1454 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001455 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001456 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001457 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001458 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 if (rc) {
1460 cERROR(1, ("Send error in read = %d", rc));
1461 } else {
1462 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1463 data_length = data_length << 16;
1464 data_length += le16_to_cpu(pSMBr->DataLength);
1465 *nbytes = data_length;
1466
1467 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001468 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001470 cFYI(1, ("bad length %d for count %d",
1471 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 rc = -EIO;
1473 *nbytes = 0;
1474 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001475 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001476 le16_to_cpu(pSMBr->DataOffset);
1477/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001478 cERROR(1,("Faulting on read rc = %d",rc));
1479 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001480 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001481 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001482 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 }
1484 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
Steve French4b8f9302006-02-26 16:41:18 +00001486/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001487 if (*buf) {
1488 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001489 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001490 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001491 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001492 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001493 /* return buffer to caller to free */
1494 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001495 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001496 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001497 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001498 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001499 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001500
1501 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 since file handle passed in no longer valid */
1503 return rc;
1504}
1505
Steve Frenchec637e32005-12-12 20:53:18 -08001506
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507int
1508CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1509 const int netfid, const unsigned int count,
1510 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001511 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512{
1513 int rc = -EACCES;
1514 WRITE_REQ *pSMB = NULL;
1515 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001516 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 __u32 bytes_sent;
1518 __u16 byte_count;
1519
Steve French61de8002008-10-30 20:15:22 +00001520 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001521 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001522 return -ECONNABORTED;
1523
Steve French790fe572007-07-07 19:25:05 +00001524 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001525 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001526 else {
Steve French1c955182005-08-30 20:58:07 -07001527 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001528 if ((offset >> 32) > 0) {
1529 /* can not handle big offset for old srv */
1530 return -EIO;
1531 }
1532 }
Steve French1c955182005-08-30 20:58:07 -07001533
1534 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 (void **) &pSMBr);
1536 if (rc)
1537 return rc;
1538 /* tcon and ses pointer are checked in smb_init */
1539 if (tcon->ses->server == NULL)
1540 return -ECONNABORTED;
1541
1542 pSMB->AndXCommand = 0xFF; /* none */
1543 pSMB->Fid = netfid;
1544 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001545 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001546 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001547
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 pSMB->Reserved = 0xFFFFFFFF;
1549 pSMB->WriteMode = 0;
1550 pSMB->Remaining = 0;
1551
Steve French50c2f752007-07-13 00:33:32 +00001552 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 can send more if LARGE_WRITE_X capability returned by the server and if
1554 our buffer is big enough or if we convert to iovecs on socket writes
1555 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001556 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1558 } else {
1559 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1560 & ~0xFF;
1561 }
1562
1563 if (bytes_sent > count)
1564 bytes_sent = count;
1565 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001566 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001567 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001568 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001569 else if (ubuf) {
1570 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 cifs_buf_release(pSMB);
1572 return -EFAULT;
1573 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001574 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 /* No buffer */
1576 cifs_buf_release(pSMB);
1577 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001578 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001579 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001580 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001581 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001582 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001583
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1585 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001586 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001587
Steve French790fe572007-07-07 19:25:05 +00001588 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001589 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001590 else { /* old style write has byte count 4 bytes earlier
1591 so 4 bytes pad */
1592 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001593 (struct smb_com_writex_req *)pSMB;
1594 pSMBW->ByteCount = cpu_to_le16(byte_count);
1595 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
1597 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1598 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001599 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 if (rc) {
1601 cFYI(1, ("Send error in write = %d", rc));
1602 *nbytes = 0;
1603 } else {
1604 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1605 *nbytes = (*nbytes) << 16;
1606 *nbytes += le16_to_cpu(pSMBr->Count);
1607 }
1608
1609 cifs_buf_release(pSMB);
1610
Steve French50c2f752007-07-13 00:33:32 +00001611 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 since file handle passed in no longer valid */
1613
1614 return rc;
1615}
1616
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001617int
1618CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001620 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1621 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622{
1623 int rc = -EACCES;
1624 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001625 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001626 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001627 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628
Steve French790fe572007-07-07 19:25:05 +00001629 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001630
Steve French4c3130e2008-12-09 00:28:16 +00001631 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001632 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001633 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001634 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001635 if ((offset >> 32) > 0) {
1636 /* can not handle big offset for old srv */
1637 return -EIO;
1638 }
1639 }
Steve French8cc64c62005-10-03 13:49:43 -07001640 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 if (rc)
1642 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 /* tcon and ses pointer are checked in smb_init */
1644 if (tcon->ses->server == NULL)
1645 return -ECONNABORTED;
1646
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001647 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 pSMB->Fid = netfid;
1649 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001650 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001651 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 pSMB->Reserved = 0xFFFFFFFF;
1653 pSMB->WriteMode = 0;
1654 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001657 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658
Steve French3e844692005-10-03 13:37:24 -07001659 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1660 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001661 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001662 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001663 pSMB->hdr.smb_buf_length += count+1;
1664 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001665 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1666 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001667 pSMB->ByteCount = cpu_to_le16(count + 1);
1668 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001669 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001670 (struct smb_com_writex_req *)pSMB;
1671 pSMBW->ByteCount = cpu_to_le16(count + 5);
1672 }
Steve French3e844692005-10-03 13:37:24 -07001673 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001674 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001675 iov[0].iov_len = smb_hdr_len + 4;
1676 else /* wct == 12 pad bigger by four bytes */
1677 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001678
Steve French3e844692005-10-03 13:37:24 -07001679
Steve Frenchec637e32005-12-12 20:53:18 -08001680 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001681 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001682 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001684 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001686 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001687 /* presumably this can not happen, but best to be safe */
1688 rc = -EIO;
1689 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001690 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001691 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001692 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1693 *nbytes = (*nbytes) << 16;
1694 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001695 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
Steve French4b8f9302006-02-26 16:41:18 +00001697/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001698 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001699 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001700 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001701 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
Steve French50c2f752007-07-13 00:33:32 +00001703 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 since file handle passed in no longer valid */
1705
1706 return rc;
1707}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001708
1709
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710int
1711CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1712 const __u16 smb_file_id, const __u64 len,
1713 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001714 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715{
1716 int rc = 0;
1717 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001718/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 int bytes_returned;
1720 int timeout = 0;
1721 __u16 count;
1722
Steve French4b18f2a2008-04-29 00:06:05 +00001723 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001724 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1725
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 if (rc)
1727 return rc;
1728
Steve French790fe572007-07-07 19:25:05 +00001729 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001730 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001732 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001733 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1735 } else {
1736 pSMB->Timeout = 0;
1737 }
1738
1739 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1740 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1741 pSMB->LockType = lockType;
1742 pSMB->AndXCommand = 0xFF; /* none */
1743 pSMB->Fid = smb_file_id; /* netfid stays le */
1744
Steve French790fe572007-07-07 19:25:05 +00001745 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1747 /* BB where to store pid high? */
1748 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1749 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1750 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1751 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1752 count = sizeof(LOCKING_ANDX_RANGE);
1753 } else {
1754 /* oplock break */
1755 count = 0;
1756 }
1757 pSMB->hdr.smb_buf_length += count;
1758 pSMB->ByteCount = cpu_to_le16(count);
1759
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001760 if (waitFlag) {
1761 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001762 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001763 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001764 } else {
Steve French133672e2007-11-13 22:41:37 +00001765 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1766 timeout);
1767 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001768 }
Steve Frencha4544342005-08-24 13:59:35 -07001769 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001770 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772
Steve French50c2f752007-07-13 00:33:32 +00001773 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 since file handle passed in no longer valid */
1775 return rc;
1776}
1777
1778int
Steve French08547b02006-02-28 22:39:25 +00001779CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1780 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001781 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001782 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001783{
1784 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1785 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001786 struct cifs_posix_lock *parm_data;
1787 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001788 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001789 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001790 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001791 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001792 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001793
1794 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001795
Steve French790fe572007-07-07 19:25:05 +00001796 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001797 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001798
Steve French08547b02006-02-28 22:39:25 +00001799 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1800
1801 if (rc)
1802 return rc;
1803
1804 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1805
Steve French50c2f752007-07-13 00:33:32 +00001806 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001807 pSMB->MaxSetupCount = 0;
1808 pSMB->Reserved = 0;
1809 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001810 pSMB->Reserved2 = 0;
1811 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1812 offset = param_offset + params;
1813
Steve French08547b02006-02-28 22:39:25 +00001814 count = sizeof(struct cifs_posix_lock);
1815 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001816 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001817 pSMB->SetupCount = 1;
1818 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001819 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001820 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1821 else
1822 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1823 byte_count = 3 /* pad */ + params + count;
1824 pSMB->DataCount = cpu_to_le16(count);
1825 pSMB->ParameterCount = cpu_to_le16(params);
1826 pSMB->TotalDataCount = pSMB->DataCount;
1827 pSMB->TotalParameterCount = pSMB->ParameterCount;
1828 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001829 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001830 (((char *) &pSMB->hdr.Protocol) + offset);
1831
1832 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001833 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001834 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001835 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001836 pSMB->Timeout = cpu_to_le32(-1);
1837 } else
1838 pSMB->Timeout = 0;
1839
Steve French08547b02006-02-28 22:39:25 +00001840 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001841 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001842 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001843
1844 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001845 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001846 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1847 pSMB->Reserved4 = 0;
1848 pSMB->hdr.smb_buf_length += byte_count;
1849 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001850 if (waitFlag) {
1851 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1852 (struct smb_hdr *) pSMBr, &bytes_returned);
1853 } else {
Steve French133672e2007-11-13 22:41:37 +00001854 iov[0].iov_base = (char *)pSMB;
1855 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1856 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1857 &resp_buf_type, timeout);
1858 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1859 not try to free it twice below on exit */
1860 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001861 }
1862
Steve French08547b02006-02-28 22:39:25 +00001863 if (rc) {
1864 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001865 } else if (get_flag) {
1866 /* lock structure can be returned on get */
1867 __u16 data_offset;
1868 __u16 data_count;
1869 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001870
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001871 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1872 rc = -EIO; /* bad smb */
1873 goto plk_err_exit;
1874 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001875 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1876 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001877 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001878 rc = -EIO;
1879 goto plk_err_exit;
1880 }
1881 parm_data = (struct cifs_posix_lock *)
1882 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001883 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001884 pLockData->fl_type = F_UNLCK;
1885 }
Steve French50c2f752007-07-13 00:33:32 +00001886
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001887plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001888 if (pSMB)
1889 cifs_small_buf_release(pSMB);
1890
Steve French133672e2007-11-13 22:41:37 +00001891 if (resp_buf_type == CIFS_SMALL_BUFFER)
1892 cifs_small_buf_release(iov[0].iov_base);
1893 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1894 cifs_buf_release(iov[0].iov_base);
1895
Steve French08547b02006-02-28 22:39:25 +00001896 /* Note: On -EAGAIN error only caller can retry on handle based calls
1897 since file handle passed in no longer valid */
1898
1899 return rc;
1900}
1901
1902
1903int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1905{
1906 int rc = 0;
1907 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 cFYI(1, ("In CIFSSMBClose"));
1909
1910/* do not retry on dead session on close */
1911 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001912 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 return 0;
1914 if (rc)
1915 return rc;
1916
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001918 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001920 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001921 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001923 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 /* EINTR is expected when user ctl-c to kill app */
1925 cERROR(1, ("Send error in Close = %d", rc));
1926 }
1927 }
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001930 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 rc = 0;
1932
1933 return rc;
1934}
1935
1936int
1937CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1938 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001939 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940{
1941 int rc = 0;
1942 RENAME_REQ *pSMB = NULL;
1943 RENAME_RSP *pSMBr = NULL;
1944 int bytes_returned;
1945 int name_len, name_len2;
1946 __u16 count;
1947
1948 cFYI(1, ("In CIFSSMBRename"));
1949renameRetry:
1950 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1951 (void **) &pSMBr);
1952 if (rc)
1953 return rc;
1954
1955 pSMB->BufferFormat = 0x04;
1956 pSMB->SearchAttributes =
1957 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1958 ATTR_DIRECTORY);
1959
1960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1961 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001962 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001963 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 name_len++; /* trailing null */
1965 name_len *= 2;
1966 pSMB->OldFileName[name_len] = 0x04; /* pad */
1967 /* protocol requires ASCII signature byte on Unicode string */
1968 pSMB->OldFileName[name_len + 1] = 0x00;
1969 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001970 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001971 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1973 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001974 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 name_len = strnlen(fromName, PATH_MAX);
1976 name_len++; /* trailing null */
1977 strncpy(pSMB->OldFileName, fromName, name_len);
1978 name_len2 = strnlen(toName, PATH_MAX);
1979 name_len2++; /* trailing null */
1980 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1981 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1982 name_len2++; /* trailing null */
1983 name_len2++; /* signature byte */
1984 }
1985
1986 count = 1 /* 1st signature byte */ + name_len + name_len2;
1987 pSMB->hdr.smb_buf_length += count;
1988 pSMB->ByteCount = cpu_to_le16(count);
1989
1990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001992 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001993 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 cifs_buf_release(pSMB);
1997
1998 if (rc == -EAGAIN)
1999 goto renameRetry;
2000
2001 return rc;
2002}
2003
Steve French50c2f752007-07-13 00:33:32 +00002004int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002005 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002006 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007{
2008 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2009 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002010 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 char *data_offset;
2012 char dummy_string[30];
2013 int rc = 0;
2014 int bytes_returned = 0;
2015 int len_of_str;
2016 __u16 params, param_offset, offset, count, byte_count;
2017
2018 cFYI(1, ("Rename to File by handle"));
2019 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2020 (void **) &pSMBr);
2021 if (rc)
2022 return rc;
2023
2024 params = 6;
2025 pSMB->MaxSetupCount = 0;
2026 pSMB->Reserved = 0;
2027 pSMB->Flags = 0;
2028 pSMB->Timeout = 0;
2029 pSMB->Reserved2 = 0;
2030 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2031 offset = param_offset + params;
2032
2033 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2034 rename_info = (struct set_file_rename *) data_offset;
2035 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002036 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 pSMB->SetupCount = 1;
2038 pSMB->Reserved3 = 0;
2039 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2040 byte_count = 3 /* pad */ + params;
2041 pSMB->ParameterCount = cpu_to_le16(params);
2042 pSMB->TotalParameterCount = pSMB->ParameterCount;
2043 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2044 pSMB->DataOffset = cpu_to_le16(offset);
2045 /* construct random name ".cifs_tmp<inodenum><mid>" */
2046 rename_info->overwrite = cpu_to_le32(1);
2047 rename_info->root_fid = 0;
2048 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002049 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002050 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2051 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002052 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002054 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002055 target_name, PATH_MAX, nls_codepage,
2056 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 }
2058 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002059 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 byte_count += count;
2061 pSMB->DataCount = cpu_to_le16(count);
2062 pSMB->TotalDataCount = pSMB->DataCount;
2063 pSMB->Fid = netfid;
2064 pSMB->InformationLevel =
2065 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2066 pSMB->Reserved4 = 0;
2067 pSMB->hdr.smb_buf_length += byte_count;
2068 pSMB->ByteCount = cpu_to_le16(byte_count);
2069 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002070 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002071 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002072 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002073 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002074
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 cifs_buf_release(pSMB);
2076
2077 /* Note: On -EAGAIN error only caller can retry on handle based calls
2078 since file handle passed in no longer valid */
2079
2080 return rc;
2081}
2082
2083int
Steve French50c2f752007-07-13 00:33:32 +00002084CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2085 const __u16 target_tid, const char *toName, const int flags,
2086 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087{
2088 int rc = 0;
2089 COPY_REQ *pSMB = NULL;
2090 COPY_RSP *pSMBr = NULL;
2091 int bytes_returned;
2092 int name_len, name_len2;
2093 __u16 count;
2094
2095 cFYI(1, ("In CIFSSMBCopy"));
2096copyRetry:
2097 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2098 (void **) &pSMBr);
2099 if (rc)
2100 return rc;
2101
2102 pSMB->BufferFormat = 0x04;
2103 pSMB->Tid2 = target_tid;
2104
2105 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2106
2107 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002108 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002109 fromName, PATH_MAX, nls_codepage,
2110 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 name_len++; /* trailing null */
2112 name_len *= 2;
2113 pSMB->OldFileName[name_len] = 0x04; /* pad */
2114 /* protocol requires ASCII signature byte on Unicode string */
2115 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002116 name_len2 =
2117 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002118 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2120 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002121 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 name_len = strnlen(fromName, PATH_MAX);
2123 name_len++; /* trailing null */
2124 strncpy(pSMB->OldFileName, fromName, name_len);
2125 name_len2 = strnlen(toName, PATH_MAX);
2126 name_len2++; /* trailing null */
2127 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2128 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2129 name_len2++; /* trailing null */
2130 name_len2++; /* signature byte */
2131 }
2132
2133 count = 1 /* 1st signature byte */ + name_len + name_len2;
2134 pSMB->hdr.smb_buf_length += count;
2135 pSMB->ByteCount = cpu_to_le16(count);
2136
2137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2139 if (rc) {
2140 cFYI(1, ("Send error in copy = %d with %d files copied",
2141 rc, le16_to_cpu(pSMBr->CopyCount)));
2142 }
Steve French0d817bc2008-05-22 02:02:03 +00002143 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
2145 if (rc == -EAGAIN)
2146 goto copyRetry;
2147
2148 return rc;
2149}
2150
2151int
2152CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2153 const char *fromName, const char *toName,
2154 const struct nls_table *nls_codepage)
2155{
2156 TRANSACTION2_SPI_REQ *pSMB = NULL;
2157 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2158 char *data_offset;
2159 int name_len;
2160 int name_len_target;
2161 int rc = 0;
2162 int bytes_returned = 0;
2163 __u16 params, param_offset, offset, byte_count;
2164
2165 cFYI(1, ("In Symlink Unix style"));
2166createSymLinkRetry:
2167 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2168 (void **) &pSMBr);
2169 if (rc)
2170 return rc;
2171
2172 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2173 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002174 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 /* find define for this maxpathcomponent */
2176 , nls_codepage);
2177 name_len++; /* trailing null */
2178 name_len *= 2;
2179
Steve French50c2f752007-07-13 00:33:32 +00002180 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 name_len = strnlen(fromName, PATH_MAX);
2182 name_len++; /* trailing null */
2183 strncpy(pSMB->FileName, fromName, name_len);
2184 }
2185 params = 6 + name_len;
2186 pSMB->MaxSetupCount = 0;
2187 pSMB->Reserved = 0;
2188 pSMB->Flags = 0;
2189 pSMB->Timeout = 0;
2190 pSMB->Reserved2 = 0;
2191 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002192 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 offset = param_offset + params;
2194
2195 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2196 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2197 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002198 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 /* find define for this maxpathcomponent */
2200 , nls_codepage);
2201 name_len_target++; /* trailing null */
2202 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002203 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 name_len_target = strnlen(toName, PATH_MAX);
2205 name_len_target++; /* trailing null */
2206 strncpy(data_offset, toName, name_len_target);
2207 }
2208
2209 pSMB->MaxParameterCount = cpu_to_le16(2);
2210 /* BB find exact max on data count below from sess */
2211 pSMB->MaxDataCount = cpu_to_le16(1000);
2212 pSMB->SetupCount = 1;
2213 pSMB->Reserved3 = 0;
2214 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2215 byte_count = 3 /* pad */ + params + name_len_target;
2216 pSMB->DataCount = cpu_to_le16(name_len_target);
2217 pSMB->ParameterCount = cpu_to_le16(params);
2218 pSMB->TotalDataCount = pSMB->DataCount;
2219 pSMB->TotalParameterCount = pSMB->ParameterCount;
2220 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2221 pSMB->DataOffset = cpu_to_le16(offset);
2222 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2223 pSMB->Reserved4 = 0;
2224 pSMB->hdr.smb_buf_length += byte_count;
2225 pSMB->ByteCount = cpu_to_le16(byte_count);
2226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2227 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002228 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002229 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002230 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Steve French0d817bc2008-05-22 02:02:03 +00002232 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
2234 if (rc == -EAGAIN)
2235 goto createSymLinkRetry;
2236
2237 return rc;
2238}
2239
2240int
2241CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2242 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002243 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244{
2245 TRANSACTION2_SPI_REQ *pSMB = NULL;
2246 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2247 char *data_offset;
2248 int name_len;
2249 int name_len_target;
2250 int rc = 0;
2251 int bytes_returned = 0;
2252 __u16 params, param_offset, offset, byte_count;
2253
2254 cFYI(1, ("In Create Hard link Unix style"));
2255createHardLinkRetry:
2256 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2257 (void **) &pSMBr);
2258 if (rc)
2259 return rc;
2260
2261 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002262 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002263 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 name_len++; /* trailing null */
2265 name_len *= 2;
2266
Steve French50c2f752007-07-13 00:33:32 +00002267 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 name_len = strnlen(toName, PATH_MAX);
2269 name_len++; /* trailing null */
2270 strncpy(pSMB->FileName, toName, name_len);
2271 }
2272 params = 6 + name_len;
2273 pSMB->MaxSetupCount = 0;
2274 pSMB->Reserved = 0;
2275 pSMB->Flags = 0;
2276 pSMB->Timeout = 0;
2277 pSMB->Reserved2 = 0;
2278 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002279 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 offset = param_offset + params;
2281
2282 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2283 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2284 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002285 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002286 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 name_len_target++; /* trailing null */
2288 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002289 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 name_len_target = strnlen(fromName, PATH_MAX);
2291 name_len_target++; /* trailing null */
2292 strncpy(data_offset, fromName, name_len_target);
2293 }
2294
2295 pSMB->MaxParameterCount = cpu_to_le16(2);
2296 /* BB find exact max on data count below from sess*/
2297 pSMB->MaxDataCount = cpu_to_le16(1000);
2298 pSMB->SetupCount = 1;
2299 pSMB->Reserved3 = 0;
2300 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2301 byte_count = 3 /* pad */ + params + name_len_target;
2302 pSMB->ParameterCount = cpu_to_le16(params);
2303 pSMB->TotalParameterCount = pSMB->ParameterCount;
2304 pSMB->DataCount = cpu_to_le16(name_len_target);
2305 pSMB->TotalDataCount = pSMB->DataCount;
2306 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2307 pSMB->DataOffset = cpu_to_le16(offset);
2308 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2309 pSMB->Reserved4 = 0;
2310 pSMB->hdr.smb_buf_length += byte_count;
2311 pSMB->ByteCount = cpu_to_le16(byte_count);
2312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002314 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002315 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
2318 cifs_buf_release(pSMB);
2319 if (rc == -EAGAIN)
2320 goto createHardLinkRetry;
2321
2322 return rc;
2323}
2324
2325int
2326CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2327 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002328 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329{
2330 int rc = 0;
2331 NT_RENAME_REQ *pSMB = NULL;
2332 RENAME_RSP *pSMBr = NULL;
2333 int bytes_returned;
2334 int name_len, name_len2;
2335 __u16 count;
2336
2337 cFYI(1, ("In CIFSCreateHardLink"));
2338winCreateHardLinkRetry:
2339
2340 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2341 (void **) &pSMBr);
2342 if (rc)
2343 return rc;
2344
2345 pSMB->SearchAttributes =
2346 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2347 ATTR_DIRECTORY);
2348 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2349 pSMB->ClusterCount = 0;
2350
2351 pSMB->BufferFormat = 0x04;
2352
2353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2354 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002355 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002356 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 name_len++; /* trailing null */
2358 name_len *= 2;
2359 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002360 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002362 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002363 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2365 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002366 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 name_len = strnlen(fromName, PATH_MAX);
2368 name_len++; /* trailing null */
2369 strncpy(pSMB->OldFileName, fromName, name_len);
2370 name_len2 = strnlen(toName, PATH_MAX);
2371 name_len2++; /* trailing null */
2372 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2373 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2374 name_len2++; /* trailing null */
2375 name_len2++; /* signature byte */
2376 }
2377
2378 count = 1 /* string type byte */ + name_len + name_len2;
2379 pSMB->hdr.smb_buf_length += count;
2380 pSMB->ByteCount = cpu_to_le16(count);
2381
2382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002384 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002385 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002387
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 cifs_buf_release(pSMB);
2389 if (rc == -EAGAIN)
2390 goto winCreateHardLinkRetry;
2391
2392 return rc;
2393}
2394
2395int
2396CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2397 const unsigned char *searchName,
2398 char *symlinkinfo, const int buflen,
2399 const struct nls_table *nls_codepage)
2400{
2401/* SMB_QUERY_FILE_UNIX_LINK */
2402 TRANSACTION2_QPI_REQ *pSMB = NULL;
2403 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2404 int rc = 0;
2405 int bytes_returned;
2406 int name_len;
2407 __u16 params, byte_count;
2408
2409 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2410
2411querySymLinkRetry:
2412 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2413 (void **) &pSMBr);
2414 if (rc)
2415 return rc;
2416
2417 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2418 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002419 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2420 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421 name_len++; /* trailing null */
2422 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002423 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 name_len = strnlen(searchName, PATH_MAX);
2425 name_len++; /* trailing null */
2426 strncpy(pSMB->FileName, searchName, name_len);
2427 }
2428
2429 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2430 pSMB->TotalDataCount = 0;
2431 pSMB->MaxParameterCount = cpu_to_le16(2);
2432 /* BB find exact max data count below from sess structure BB */
2433 pSMB->MaxDataCount = cpu_to_le16(4000);
2434 pSMB->MaxSetupCount = 0;
2435 pSMB->Reserved = 0;
2436 pSMB->Flags = 0;
2437 pSMB->Timeout = 0;
2438 pSMB->Reserved2 = 0;
2439 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002440 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 pSMB->DataCount = 0;
2442 pSMB->DataOffset = 0;
2443 pSMB->SetupCount = 1;
2444 pSMB->Reserved3 = 0;
2445 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2446 byte_count = params + 1 /* pad */ ;
2447 pSMB->TotalParameterCount = cpu_to_le16(params);
2448 pSMB->ParameterCount = pSMB->TotalParameterCount;
2449 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2450 pSMB->Reserved4 = 0;
2451 pSMB->hdr.smb_buf_length += byte_count;
2452 pSMB->ByteCount = cpu_to_le16(byte_count);
2453
2454 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2455 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2456 if (rc) {
2457 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2458 } else {
2459 /* decode response */
2460
2461 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2462 if (rc || (pSMBr->ByteCount < 2))
2463 /* BB also check enough total bytes returned */
2464 rc = -EIO; /* bad smb */
2465 else {
2466 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2467 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2468
2469 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2470 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002471 &pSMBr->hdr.Protocol + data_offset),
2472 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002473 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002475 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2476 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 name_len, nls_codepage);
2478 } else {
2479 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002480 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 data_offset,
2482 min_t(const int, buflen, count));
2483 }
2484 symlinkinfo[buflen] = 0;
2485 /* just in case so calling code does not go off the end of buffer */
2486 }
2487 }
2488 cifs_buf_release(pSMB);
2489 if (rc == -EAGAIN)
2490 goto querySymLinkRetry;
2491 return rc;
2492}
2493
Parag Warudkarc9489772007-10-23 18:09:48 +00002494#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002495/* Initialize NT TRANSACT SMB into small smb request buffer.
2496 This assumes that all NT TRANSACTS that we init here have
2497 total parm and data under about 400 bytes (to fit in small cifs
2498 buffer size), which is the case so far, it easily fits. NB:
2499 Setup words themselves and ByteCount
2500 MaxSetupCount (size of returned setup area) and
2501 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002502static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002503smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002504 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002505 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002506{
2507 int rc;
2508 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002509 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002510
2511 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2512 (void **)&pSMB);
2513 if (rc)
2514 return rc;
2515 *ret_buf = (void *)pSMB;
2516 pSMB->Reserved = 0;
2517 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2518 pSMB->TotalDataCount = 0;
2519 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2520 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2521 pSMB->ParameterCount = pSMB->TotalParameterCount;
2522 pSMB->DataCount = pSMB->TotalDataCount;
2523 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2524 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2525 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2526 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2527 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2528 pSMB->SubCommand = cpu_to_le16(sub_command);
2529 return 0;
2530}
2531
2532static int
Steve French50c2f752007-07-13 00:33:32 +00002533validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002534 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002535{
Steve French50c2f752007-07-13 00:33:32 +00002536 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002537 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002538 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002539
Steve French630f3f0c2007-10-25 21:17:17 +00002540 *pdatalen = 0;
2541 *pparmlen = 0;
2542
Steve French790fe572007-07-07 19:25:05 +00002543 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002544 return -EINVAL;
2545
2546 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2547
2548 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002549 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002550 (char *)&pSMBr->ByteCount;
2551
Steve French0a4b92c2006-01-12 15:44:21 -08002552 data_offset = le32_to_cpu(pSMBr->DataOffset);
2553 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002554 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002555 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2556
2557 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2558 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2559
2560 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002561 if (*ppparm > end_of_smb) {
2562 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002563 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002564 } else if (parm_count + *ppparm > end_of_smb) {
2565 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002566 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002567 } else if (*ppdata > end_of_smb) {
2568 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002569 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002570 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002571 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002572 *ppdata, data_count, (data_count + *ppdata),
2573 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002574 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002575 } else if (parm_count + data_count > pSMBr->ByteCount) {
2576 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002577 return -EINVAL;
2578 }
Steve French630f3f0c2007-10-25 21:17:17 +00002579 *pdatalen = data_count;
2580 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002581 return 0;
2582}
Parag Warudkarc9489772007-10-23 18:09:48 +00002583#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002584
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585int
2586CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2587 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002588 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 const struct nls_table *nls_codepage)
2590{
2591 int rc = 0;
2592 int bytes_returned;
2593 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002594 struct smb_com_transaction_ioctl_req *pSMB;
2595 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
2597 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2598 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2599 (void **) &pSMBr);
2600 if (rc)
2601 return rc;
2602
2603 pSMB->TotalParameterCount = 0 ;
2604 pSMB->TotalDataCount = 0;
2605 pSMB->MaxParameterCount = cpu_to_le32(2);
2606 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002607 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2608 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 pSMB->MaxSetupCount = 4;
2610 pSMB->Reserved = 0;
2611 pSMB->ParameterOffset = 0;
2612 pSMB->DataCount = 0;
2613 pSMB->DataOffset = 0;
2614 pSMB->SetupCount = 4;
2615 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2616 pSMB->ParameterCount = pSMB->TotalParameterCount;
2617 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2618 pSMB->IsFsctl = 1; /* FSCTL */
2619 pSMB->IsRootFlag = 0;
2620 pSMB->Fid = fid; /* file handle always le */
2621 pSMB->ByteCount = 0;
2622
2623 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2624 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2625 if (rc) {
2626 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2627 } else { /* decode response */
2628 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2629 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2630 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2631 /* BB also check enough total bytes returned */
2632 rc = -EIO; /* bad smb */
2633 else {
Steve French790fe572007-07-07 19:25:05 +00002634 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002635 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002636 pSMBr->ByteCount +
2637 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638
Steve French50c2f752007-07-13 00:33:32 +00002639 struct reparse_data *reparse_buf =
2640 (struct reparse_data *)
2641 ((char *)&pSMBr->hdr.Protocol
2642 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002643 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 rc = -EIO;
2645 goto qreparse_out;
2646 }
Steve French790fe572007-07-07 19:25:05 +00002647 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 reparse_buf->TargetNameOffset +
2649 reparse_buf->TargetNameLen) >
2650 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002651 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 rc = -EIO;
2653 goto qreparse_out;
2654 }
Steve French50c2f752007-07-13 00:33:32 +00002655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2657 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002658 (reparse_buf->LinkNamesBuf +
2659 reparse_buf->TargetNameOffset),
2660 min(buflen/2,
2661 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002663 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 reparse_buf->TargetNameOffset),
2665 name_len, nls_codepage);
2666 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002667 strncpy(symlinkinfo,
2668 reparse_buf->LinkNamesBuf +
2669 reparse_buf->TargetNameOffset,
2670 min_t(const int, buflen,
2671 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 }
2673 } else {
2674 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002675 cFYI(1, ("Invalid return data count on "
2676 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 }
2678 symlinkinfo[buflen] = 0; /* just in case so the caller
2679 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002680 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 }
2682 }
2683qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002684 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
2686 /* Note: On -EAGAIN error only caller can retry on handle based calls
2687 since file handle passed in no longer valid */
2688
2689 return rc;
2690}
2691
2692#ifdef CONFIG_CIFS_POSIX
2693
2694/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002695static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2696 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
2698 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002699 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2700 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2701 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2703
2704 return;
2705}
2706
2707/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002708static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2709 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710{
2711 int size = 0;
2712 int i;
2713 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002714 struct cifs_posix_ace *pACE;
2715 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2716 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717
2718 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2719 return -EOPNOTSUPP;
2720
Steve French790fe572007-07-07 19:25:05 +00002721 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 count = le16_to_cpu(cifs_acl->access_entry_count);
2723 pACE = &cifs_acl->ace_array[0];
2724 size = sizeof(struct cifs_posix_acl);
2725 size += sizeof(struct cifs_posix_ace) * count;
2726 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002727 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002728 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2729 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 return -EINVAL;
2731 }
Steve French790fe572007-07-07 19:25:05 +00002732 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 count = le16_to_cpu(cifs_acl->access_entry_count);
2734 size = sizeof(struct cifs_posix_acl);
2735 size += sizeof(struct cifs_posix_ace) * count;
2736/* skip past access ACEs to get to default ACEs */
2737 pACE = &cifs_acl->ace_array[count];
2738 count = le16_to_cpu(cifs_acl->default_entry_count);
2739 size += sizeof(struct cifs_posix_ace) * count;
2740 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002741 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 return -EINVAL;
2743 } else {
2744 /* illegal type */
2745 return -EINVAL;
2746 }
2747
2748 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002749 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002750 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002751 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 return -ERANGE;
2753 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002754 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002755 for (i = 0; i < count ; i++) {
2756 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2757 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 }
2759 }
2760 return size;
2761}
2762
Steve French50c2f752007-07-13 00:33:32 +00002763static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2764 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765{
2766 __u16 rc = 0; /* 0 = ACL converted ok */
2767
Steve Frenchff7feac2005-11-15 16:45:16 -08002768 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2769 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002771 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 /* Probably no need to le convert -1 on any arch but can not hurt */
2773 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002774 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002775 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002776 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 return rc;
2778}
2779
2780/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002781static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2782 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783{
2784 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002785 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2786 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 int count;
2788 int i;
2789
Steve French790fe572007-07-07 19:25:05 +00002790 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 return 0;
2792
2793 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002794 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002795 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002796 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002797 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002798 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002799 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 return 0;
2801 }
2802 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002803 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002804 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002805 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002806 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 else {
Steve French50c2f752007-07-13 00:33:32 +00002808 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 return 0;
2810 }
Steve French50c2f752007-07-13 00:33:32 +00002811 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2813 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002814 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 /* ACE not converted */
2816 break;
2817 }
2818 }
Steve French790fe572007-07-07 19:25:05 +00002819 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2821 rc += sizeof(struct cifs_posix_acl);
2822 /* BB add check to make sure ACL does not overflow SMB */
2823 }
2824 return rc;
2825}
2826
2827int
2828CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002829 const unsigned char *searchName,
2830 char *acl_inf, const int buflen, const int acl_type,
2831 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832{
2833/* SMB_QUERY_POSIX_ACL */
2834 TRANSACTION2_QPI_REQ *pSMB = NULL;
2835 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2836 int rc = 0;
2837 int bytes_returned;
2838 int name_len;
2839 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002840
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2842
2843queryAclRetry:
2844 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2845 (void **) &pSMBr);
2846 if (rc)
2847 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002848
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2850 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002851 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002852 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 name_len++; /* trailing null */
2854 name_len *= 2;
2855 pSMB->FileName[name_len] = 0;
2856 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002857 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 name_len = strnlen(searchName, PATH_MAX);
2859 name_len++; /* trailing null */
2860 strncpy(pSMB->FileName, searchName, name_len);
2861 }
2862
2863 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2864 pSMB->TotalDataCount = 0;
2865 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002866 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 pSMB->MaxDataCount = cpu_to_le16(4000);
2868 pSMB->MaxSetupCount = 0;
2869 pSMB->Reserved = 0;
2870 pSMB->Flags = 0;
2871 pSMB->Timeout = 0;
2872 pSMB->Reserved2 = 0;
2873 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002874 offsetof(struct smb_com_transaction2_qpi_req,
2875 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 pSMB->DataCount = 0;
2877 pSMB->DataOffset = 0;
2878 pSMB->SetupCount = 1;
2879 pSMB->Reserved3 = 0;
2880 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2881 byte_count = params + 1 /* pad */ ;
2882 pSMB->TotalParameterCount = cpu_to_le16(params);
2883 pSMB->ParameterCount = pSMB->TotalParameterCount;
2884 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2885 pSMB->Reserved4 = 0;
2886 pSMB->hdr.smb_buf_length += byte_count;
2887 pSMB->ByteCount = cpu_to_le16(byte_count);
2888
2889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002891 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 if (rc) {
2893 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2894 } else {
2895 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2898 if (rc || (pSMBr->ByteCount < 2))
2899 /* BB also check enough total bytes returned */
2900 rc = -EIO; /* bad smb */
2901 else {
2902 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2903 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2904 rc = cifs_copy_posix_acl(acl_inf,
2905 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002906 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 }
2908 }
2909 cifs_buf_release(pSMB);
2910 if (rc == -EAGAIN)
2911 goto queryAclRetry;
2912 return rc;
2913}
2914
2915int
2916CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002917 const unsigned char *fileName,
2918 const char *local_acl, const int buflen,
2919 const int acl_type,
2920 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921{
2922 struct smb_com_transaction2_spi_req *pSMB = NULL;
2923 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2924 char *parm_data;
2925 int name_len;
2926 int rc = 0;
2927 int bytes_returned = 0;
2928 __u16 params, byte_count, data_count, param_offset, offset;
2929
2930 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2931setAclRetry:
2932 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002933 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 if (rc)
2935 return rc;
2936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2937 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002938 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002939 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 name_len++; /* trailing null */
2941 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002942 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 name_len = strnlen(fileName, PATH_MAX);
2944 name_len++; /* trailing null */
2945 strncpy(pSMB->FileName, fileName, name_len);
2946 }
2947 params = 6 + name_len;
2948 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002949 /* BB find max SMB size from sess */
2950 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 pSMB->MaxSetupCount = 0;
2952 pSMB->Reserved = 0;
2953 pSMB->Flags = 0;
2954 pSMB->Timeout = 0;
2955 pSMB->Reserved2 = 0;
2956 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002957 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 offset = param_offset + params;
2959 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2960 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2961
2962 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002963 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
Steve French790fe572007-07-07 19:25:05 +00002965 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 rc = -EOPNOTSUPP;
2967 goto setACLerrorExit;
2968 }
2969 pSMB->DataOffset = cpu_to_le16(offset);
2970 pSMB->SetupCount = 1;
2971 pSMB->Reserved3 = 0;
2972 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2973 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2974 byte_count = 3 /* pad */ + params + data_count;
2975 pSMB->DataCount = cpu_to_le16(data_count);
2976 pSMB->TotalDataCount = pSMB->DataCount;
2977 pSMB->ParameterCount = cpu_to_le16(params);
2978 pSMB->TotalParameterCount = pSMB->ParameterCount;
2979 pSMB->Reserved4 = 0;
2980 pSMB->hdr.smb_buf_length += byte_count;
2981 pSMB->ByteCount = cpu_to_le16(byte_count);
2982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002984 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986
2987setACLerrorExit:
2988 cifs_buf_release(pSMB);
2989 if (rc == -EAGAIN)
2990 goto setAclRetry;
2991 return rc;
2992}
2993
Steve Frenchf654bac2005-04-28 22:41:04 -07002994/* BB fix tabs in this function FIXME BB */
2995int
2996CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002997 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002998{
Steve French50c2f752007-07-13 00:33:32 +00002999 int rc = 0;
3000 struct smb_t2_qfi_req *pSMB = NULL;
3001 struct smb_t2_qfi_rsp *pSMBr = NULL;
3002 int bytes_returned;
3003 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003004
Steve French790fe572007-07-07 19:25:05 +00003005 cFYI(1, ("In GetExtAttr"));
3006 if (tcon == NULL)
3007 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003008
3009GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003010 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3011 (void **) &pSMBr);
3012 if (rc)
3013 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003014
Steve Frenchad7a2922008-02-07 23:25:02 +00003015 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003016 pSMB->t2.TotalDataCount = 0;
3017 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3018 /* BB find exact max data count below from sess structure BB */
3019 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3020 pSMB->t2.MaxSetupCount = 0;
3021 pSMB->t2.Reserved = 0;
3022 pSMB->t2.Flags = 0;
3023 pSMB->t2.Timeout = 0;
3024 pSMB->t2.Reserved2 = 0;
3025 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3026 Fid) - 4);
3027 pSMB->t2.DataCount = 0;
3028 pSMB->t2.DataOffset = 0;
3029 pSMB->t2.SetupCount = 1;
3030 pSMB->t2.Reserved3 = 0;
3031 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3032 byte_count = params + 1 /* pad */ ;
3033 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3034 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3035 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3036 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003037 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003038 pSMB->hdr.smb_buf_length += byte_count;
3039 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003040
Steve French790fe572007-07-07 19:25:05 +00003041 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3042 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3043 if (rc) {
3044 cFYI(1, ("error %d in GetExtAttr", rc));
3045 } else {
3046 /* decode response */
3047 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3048 if (rc || (pSMBr->ByteCount < 2))
3049 /* BB also check enough total bytes returned */
3050 /* If rc should we check for EOPNOSUPP and
3051 disable the srvino flag? or in caller? */
3052 rc = -EIO; /* bad smb */
3053 else {
3054 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3055 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3056 struct file_chattr_info *pfinfo;
3057 /* BB Do we need a cast or hash here ? */
3058 if (count != 16) {
3059 cFYI(1, ("Illegal size ret in GetExtAttr"));
3060 rc = -EIO;
3061 goto GetExtAttrOut;
3062 }
3063 pfinfo = (struct file_chattr_info *)
3064 (data_offset + (char *) &pSMBr->hdr.Protocol);
3065 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003066 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003067 }
3068 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003069GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003070 cifs_buf_release(pSMB);
3071 if (rc == -EAGAIN)
3072 goto GetExtAttrRetry;
3073 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003074}
3075
Steve Frenchf654bac2005-04-28 22:41:04 -07003076#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
Steve French297647c2007-10-12 04:11:59 +00003078#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003079/* Get Security Descriptor (by handle) from remote server for a file or dir */
3080int
3081CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003082 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003083{
3084 int rc = 0;
3085 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003086 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003087 struct kvec iov[1];
3088
3089 cFYI(1, ("GetCifsACL"));
3090
Steve French630f3f0c2007-10-25 21:17:17 +00003091 *pbuflen = 0;
3092 *acl_inf = NULL;
3093
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003094 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003095 8 /* parm len */, tcon, (void **) &pSMB);
3096 if (rc)
3097 return rc;
3098
3099 pSMB->MaxParameterCount = cpu_to_le32(4);
3100 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3101 pSMB->MaxSetupCount = 0;
3102 pSMB->Fid = fid; /* file handle always le */
3103 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3104 CIFS_ACL_DACL);
3105 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3106 pSMB->hdr.smb_buf_length += 11;
3107 iov[0].iov_base = (char *)pSMB;
3108 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3109
Steve Frencha761ac52007-10-18 21:45:27 +00003110 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003111 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003112 cifs_stats_inc(&tcon->num_acl_get);
3113 if (rc) {
3114 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3115 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003116 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003117 __u32 parm_len;
3118 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003119 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003120 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003121
3122/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003123 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003124 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003125 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003126 goto qsec_out;
3127 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3128
Steve French630f3f0c2007-10-25 21:17:17 +00003129 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003130
3131 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3132 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003133 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003134 goto qsec_out;
3135 }
3136
3137/* BB check that data area is minimum length and as big as acl_len */
3138
Steve Frenchaf6f4612007-10-16 18:40:37 +00003139 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003140 if (acl_len != *pbuflen) {
3141 cERROR(1, ("acl length %d does not match %d",
3142 acl_len, *pbuflen));
3143 if (*pbuflen > acl_len)
3144 *pbuflen = acl_len;
3145 }
Steve French0a4b92c2006-01-12 15:44:21 -08003146
Steve French630f3f0c2007-10-25 21:17:17 +00003147 /* check if buffer is big enough for the acl
3148 header followed by the smallest SID */
3149 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3150 (*pbuflen >= 64 * 1024)) {
3151 cERROR(1, ("bad acl length %d", *pbuflen));
3152 rc = -EINVAL;
3153 *pbuflen = 0;
3154 } else {
3155 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3156 if (*acl_inf == NULL) {
3157 *pbuflen = 0;
3158 rc = -ENOMEM;
3159 }
3160 memcpy(*acl_inf, pdata, *pbuflen);
3161 }
Steve French0a4b92c2006-01-12 15:44:21 -08003162 }
3163qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003164 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003165 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003166 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003167 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003168/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003169 return rc;
3170}
Steve French97837582007-12-31 07:47:21 +00003171
3172int
3173CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3174 struct cifs_ntsd *pntsd, __u32 acllen)
3175{
3176 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3177 int rc = 0;
3178 int bytes_returned = 0;
3179 SET_SEC_DESC_REQ *pSMB = NULL;
3180 NTRANSACT_RSP *pSMBr = NULL;
3181
3182setCifsAclRetry:
3183 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3184 (void **) &pSMBr);
3185 if (rc)
3186 return (rc);
3187
3188 pSMB->MaxSetupCount = 0;
3189 pSMB->Reserved = 0;
3190
3191 param_count = 8;
3192 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3193 data_count = acllen;
3194 data_offset = param_offset + param_count;
3195 byte_count = 3 /* pad */ + param_count;
3196
3197 pSMB->DataCount = cpu_to_le32(data_count);
3198 pSMB->TotalDataCount = pSMB->DataCount;
3199 pSMB->MaxParameterCount = cpu_to_le32(4);
3200 pSMB->MaxDataCount = cpu_to_le32(16384);
3201 pSMB->ParameterCount = cpu_to_le32(param_count);
3202 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3203 pSMB->TotalParameterCount = pSMB->ParameterCount;
3204 pSMB->DataOffset = cpu_to_le32(data_offset);
3205 pSMB->SetupCount = 0;
3206 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3207 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3208
3209 pSMB->Fid = fid; /* file handle always le */
3210 pSMB->Reserved2 = 0;
3211 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3212
3213 if (pntsd && acllen) {
3214 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3215 (char *) pntsd,
3216 acllen);
3217 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3218
3219 } else
3220 pSMB->hdr.smb_buf_length += byte_count;
3221
3222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3224
3225 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3226 if (rc)
3227 cFYI(1, ("Set CIFS ACL returned %d", rc));
3228 cifs_buf_release(pSMB);
3229
3230 if (rc == -EAGAIN)
3231 goto setCifsAclRetry;
3232
3233 return (rc);
3234}
3235
Steve French297647c2007-10-12 04:11:59 +00003236#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003237
Steve French6b8edfe2005-08-23 20:26:03 -07003238/* Legacy Query Path Information call for lookup to old servers such
3239 as Win9x/WinME */
3240int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003241 const unsigned char *searchName,
3242 FILE_ALL_INFO *pFinfo,
3243 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003244{
Steve Frenchad7a2922008-02-07 23:25:02 +00003245 QUERY_INFORMATION_REQ *pSMB;
3246 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003247 int rc = 0;
3248 int bytes_returned;
3249 int name_len;
3250
Steve French50c2f752007-07-13 00:33:32 +00003251 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003252QInfRetry:
3253 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003254 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003255 if (rc)
3256 return rc;
3257
3258 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3259 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003260 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3261 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003262 name_len++; /* trailing null */
3263 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003264 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003265 name_len = strnlen(searchName, PATH_MAX);
3266 name_len++; /* trailing null */
3267 strncpy(pSMB->FileName, searchName, name_len);
3268 }
3269 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003270 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003271 pSMB->hdr.smb_buf_length += (__u16) name_len;
3272 pSMB->ByteCount = cpu_to_le16(name_len);
3273
3274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003275 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003276 if (rc) {
3277 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003278 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003279 struct timespec ts;
3280 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003281
3282 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003283 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003284 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003285 ts.tv_nsec = 0;
3286 ts.tv_sec = time;
3287 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003288 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003289 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3290 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003291 pFinfo->AllocationSize =
3292 cpu_to_le64(le32_to_cpu(pSMBr->size));
3293 pFinfo->EndOfFile = pFinfo->AllocationSize;
3294 pFinfo->Attributes =
3295 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003296 } else
3297 rc = -EIO; /* bad buffer passed in */
3298
3299 cifs_buf_release(pSMB);
3300
3301 if (rc == -EAGAIN)
3302 goto QInfRetry;
3303
3304 return rc;
3305}
3306
3307
3308
3309
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310int
3311CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3312 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003313 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003314 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003315 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316{
3317/* level 263 SMB_QUERY_FILE_ALL_INFO */
3318 TRANSACTION2_QPI_REQ *pSMB = NULL;
3319 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3320 int rc = 0;
3321 int bytes_returned;
3322 int name_len;
3323 __u16 params, byte_count;
3324
3325/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3326QPathInfoRetry:
3327 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3328 (void **) &pSMBr);
3329 if (rc)
3330 return rc;
3331
3332 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3333 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003334 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003335 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 name_len++; /* trailing null */
3337 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003338 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 name_len = strnlen(searchName, PATH_MAX);
3340 name_len++; /* trailing null */
3341 strncpy(pSMB->FileName, searchName, name_len);
3342 }
3343
Steve French50c2f752007-07-13 00:33:32 +00003344 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 pSMB->TotalDataCount = 0;
3346 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003347 /* BB find exact max SMB PDU from sess structure BB */
3348 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 pSMB->MaxSetupCount = 0;
3350 pSMB->Reserved = 0;
3351 pSMB->Flags = 0;
3352 pSMB->Timeout = 0;
3353 pSMB->Reserved2 = 0;
3354 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003355 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 pSMB->DataCount = 0;
3357 pSMB->DataOffset = 0;
3358 pSMB->SetupCount = 1;
3359 pSMB->Reserved3 = 0;
3360 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3361 byte_count = params + 1 /* pad */ ;
3362 pSMB->TotalParameterCount = cpu_to_le16(params);
3363 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003364 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003365 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3366 else
3367 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 pSMB->Reserved4 = 0;
3369 pSMB->hdr.smb_buf_length += byte_count;
3370 pSMB->ByteCount = cpu_to_le16(byte_count);
3371
3372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3374 if (rc) {
3375 cFYI(1, ("Send error in QPathInfo = %d", rc));
3376 } else { /* decode response */
3377 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3378
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003379 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3380 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003381 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003383 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003384 rc = -EIO; /* 24 or 26 expected but we do not read
3385 last field */
3386 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003387 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003389
3390 /* On legacy responses we do not read the last field,
3391 EAsize, fortunately since it varies by subdialect and
3392 also note it differs on Set vs. Get, ie two bytes or 4
3393 bytes depending but we don't care here */
3394 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003395 size = sizeof(FILE_INFO_STANDARD);
3396 else
3397 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 memcpy((char *) pFindData,
3399 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003400 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 } else
3402 rc = -ENOMEM;
3403 }
3404 cifs_buf_release(pSMB);
3405 if (rc == -EAGAIN)
3406 goto QPathInfoRetry;
3407
3408 return rc;
3409}
3410
3411int
3412CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3413 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003414 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003415 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416{
3417/* SMB_QUERY_FILE_UNIX_BASIC */
3418 TRANSACTION2_QPI_REQ *pSMB = NULL;
3419 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3420 int rc = 0;
3421 int bytes_returned = 0;
3422 int name_len;
3423 __u16 params, byte_count;
3424
3425 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3426UnixQPathInfoRetry:
3427 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3428 (void **) &pSMBr);
3429 if (rc)
3430 return rc;
3431
3432 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3433 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003434 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003435 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 name_len++; /* trailing null */
3437 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003438 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 name_len = strnlen(searchName, PATH_MAX);
3440 name_len++; /* trailing null */
3441 strncpy(pSMB->FileName, searchName, name_len);
3442 }
3443
Steve French50c2f752007-07-13 00:33:32 +00003444 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 pSMB->TotalDataCount = 0;
3446 pSMB->MaxParameterCount = cpu_to_le16(2);
3447 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003448 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003449 pSMB->MaxSetupCount = 0;
3450 pSMB->Reserved = 0;
3451 pSMB->Flags = 0;
3452 pSMB->Timeout = 0;
3453 pSMB->Reserved2 = 0;
3454 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003455 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003456 pSMB->DataCount = 0;
3457 pSMB->DataOffset = 0;
3458 pSMB->SetupCount = 1;
3459 pSMB->Reserved3 = 0;
3460 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3461 byte_count = params + 1 /* pad */ ;
3462 pSMB->TotalParameterCount = cpu_to_le16(params);
3463 pSMB->ParameterCount = pSMB->TotalParameterCount;
3464 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3465 pSMB->Reserved4 = 0;
3466 pSMB->hdr.smb_buf_length += byte_count;
3467 pSMB->ByteCount = cpu_to_le16(byte_count);
3468
3469 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3470 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3471 if (rc) {
3472 cFYI(1, ("Send error in QPathInfo = %d", rc));
3473 } else { /* decode response */
3474 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3475
3476 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003477 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3478 "Unix Extensions can be disabled on mount "
3479 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 rc = -EIO; /* bad smb */
3481 } else {
3482 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3483 memcpy((char *) pFindData,
3484 (char *) &pSMBr->hdr.Protocol +
3485 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003486 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487 }
3488 }
3489 cifs_buf_release(pSMB);
3490 if (rc == -EAGAIN)
3491 goto UnixQPathInfoRetry;
3492
3493 return rc;
3494}
3495
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496/* xid, tcon, searchName and codepage are input parms, rest are returned */
3497int
3498CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003499 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003501 __u16 *pnetfid,
3502 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503{
3504/* level 257 SMB_ */
3505 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3506 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003507 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 int rc = 0;
3509 int bytes_returned = 0;
3510 int name_len;
3511 __u16 params, byte_count;
3512
Steve French50c2f752007-07-13 00:33:32 +00003513 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
3515findFirstRetry:
3516 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3517 (void **) &pSMBr);
3518 if (rc)
3519 return rc;
3520
3521 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3522 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003523 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003524 PATH_MAX, nls_codepage, remap);
3525 /* We can not add the asterik earlier in case
3526 it got remapped to 0xF03A as if it were part of the
3527 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003529 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003530 pSMB->FileName[name_len+1] = 0;
3531 pSMB->FileName[name_len+2] = '*';
3532 pSMB->FileName[name_len+3] = 0;
3533 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3535 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003536 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 } else { /* BB add check for overrun of SMB buf BB */
3538 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003540 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 free buffer exit; BB */
3542 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003543 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003544 pSMB->FileName[name_len+1] = '*';
3545 pSMB->FileName[name_len+2] = 0;
3546 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 }
3548
3549 params = 12 + name_len /* includes null */ ;
3550 pSMB->TotalDataCount = 0; /* no EAs */
3551 pSMB->MaxParameterCount = cpu_to_le16(10);
3552 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3553 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3554 pSMB->MaxSetupCount = 0;
3555 pSMB->Reserved = 0;
3556 pSMB->Flags = 0;
3557 pSMB->Timeout = 0;
3558 pSMB->Reserved2 = 0;
3559 byte_count = params + 1 /* pad */ ;
3560 pSMB->TotalParameterCount = cpu_to_le16(params);
3561 pSMB->ParameterCount = pSMB->TotalParameterCount;
3562 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003563 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3564 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565 pSMB->DataCount = 0;
3566 pSMB->DataOffset = 0;
3567 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3568 pSMB->Reserved3 = 0;
3569 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3570 pSMB->SearchAttributes =
3571 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3572 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003573 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3574 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 CIFS_SEARCH_RETURN_RESUME);
3576 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3577
3578 /* BB what should we set StorageType to? Does it matter? BB */
3579 pSMB->SearchStorageType = 0;
3580 pSMB->hdr.smb_buf_length += byte_count;
3581 pSMB->ByteCount = cpu_to_le16(byte_count);
3582
3583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003585 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586
Steve French88274812006-03-09 22:21:45 +00003587 if (rc) {/* BB add logic to retry regular search if Unix search
3588 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 /* BB Add code to handle unsupported level rc */
3590 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003591
Steve French88274812006-03-09 22:21:45 +00003592 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
3594 /* BB eventually could optimize out free and realloc of buf */
3595 /* for this case */
3596 if (rc == -EAGAIN)
3597 goto findFirstRetry;
3598 } else { /* decode response */
3599 /* BB remember to free buffer if error BB */
3600 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003601 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003602 unsigned int lnoff;
3603
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003605 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 else
Steve French4b18f2a2008-04-29 00:06:05 +00003607 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
3609 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003610 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003611 psrch_inf->srch_entries_start =
3612 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3615 le16_to_cpu(pSMBr->t2.ParameterOffset));
3616
Steve French790fe572007-07-07 19:25:05 +00003617 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003618 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 else
Steve French4b18f2a2008-04-29 00:06:05 +00003620 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
Steve French50c2f752007-07-13 00:33:32 +00003622 psrch_inf->entries_in_buffer =
3623 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003624 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003626 lnoff = le16_to_cpu(parms->LastNameOffset);
3627 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3628 lnoff) {
3629 cERROR(1, ("ignoring corrupt resume name"));
3630 psrch_inf->last_entry = NULL;
3631 return rc;
3632 }
3633
Steve French0752f152008-10-07 20:03:33 +00003634 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003635 lnoff;
3636
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 *pnetfid = parms->SearchHandle;
3638 } else {
3639 cifs_buf_release(pSMB);
3640 }
3641 }
3642
3643 return rc;
3644}
3645
3646int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003647 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648{
3649 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3650 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003651 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 char *response_data;
3653 int rc = 0;
3654 int bytes_returned, name_len;
3655 __u16 params, byte_count;
3656
3657 cFYI(1, ("In FindNext"));
3658
Steve French4b18f2a2008-04-29 00:06:05 +00003659 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 return -ENOENT;
3661
3662 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3663 (void **) &pSMBr);
3664 if (rc)
3665 return rc;
3666
Steve French50c2f752007-07-13 00:33:32 +00003667 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 byte_count = 0;
3669 pSMB->TotalDataCount = 0; /* no EAs */
3670 pSMB->MaxParameterCount = cpu_to_le16(8);
3671 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003672 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3673 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 pSMB->MaxSetupCount = 0;
3675 pSMB->Reserved = 0;
3676 pSMB->Flags = 0;
3677 pSMB->Timeout = 0;
3678 pSMB->Reserved2 = 0;
3679 pSMB->ParameterOffset = cpu_to_le16(
3680 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3681 pSMB->DataCount = 0;
3682 pSMB->DataOffset = 0;
3683 pSMB->SetupCount = 1;
3684 pSMB->Reserved3 = 0;
3685 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3686 pSMB->SearchHandle = searchHandle; /* always kept as le */
3687 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003688 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3690 pSMB->ResumeKey = psrch_inf->resume_key;
3691 pSMB->SearchFlags =
3692 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3693
3694 name_len = psrch_inf->resume_name_len;
3695 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003696 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3698 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003699 /* 14 byte parm len above enough for 2 byte null terminator */
3700 pSMB->ResumeFileName[name_len] = 0;
3701 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 } else {
3703 rc = -EINVAL;
3704 goto FNext2_err_exit;
3705 }
3706 byte_count = params + 1 /* pad */ ;
3707 pSMB->TotalParameterCount = cpu_to_le16(params);
3708 pSMB->ParameterCount = pSMB->TotalParameterCount;
3709 pSMB->hdr.smb_buf_length += byte_count;
3710 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3713 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003714 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 if (rc) {
3716 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003717 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003718 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003719 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 } else
3721 cFYI(1, ("FindNext returned = %d", rc));
3722 } else { /* decode response */
3723 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003724
Steve French790fe572007-07-07 19:25:05 +00003725 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003726 unsigned int lnoff;
3727
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 /* BB fixme add lock for file (srch_info) struct here */
3729 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003730 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 else
Steve French4b18f2a2008-04-29 00:06:05 +00003732 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 response_data = (char *) &pSMBr->hdr.Protocol +
3734 le16_to_cpu(pSMBr->t2.ParameterOffset);
3735 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3736 response_data = (char *)&pSMBr->hdr.Protocol +
3737 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003738 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003739 cifs_small_buf_release(
3740 psrch_inf->ntwrk_buf_start);
3741 else
3742 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 psrch_inf->srch_entries_start = response_data;
3744 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003745 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003746 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003747 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 else
Steve French4b18f2a2008-04-29 00:06:05 +00003749 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003750 psrch_inf->entries_in_buffer =
3751 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 psrch_inf->index_of_last_entry +=
3753 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003754 lnoff = le16_to_cpu(parms->LastNameOffset);
3755 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3756 lnoff) {
3757 cERROR(1, ("ignoring corrupt resume name"));
3758 psrch_inf->last_entry = NULL;
3759 return rc;
3760 } else
3761 psrch_inf->last_entry =
3762 psrch_inf->srch_entries_start + lnoff;
3763
Steve French50c2f752007-07-13 00:33:32 +00003764/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3765 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766
3767 /* BB fixme add unlock here */
3768 }
3769
3770 }
3771
3772 /* BB On error, should we leave previous search buf (and count and
3773 last entry fields) intact or free the previous one? */
3774
3775 /* Note: On -EAGAIN error only caller can retry on handle based calls
3776 since file handle passed in no longer valid */
3777FNext2_err_exit:
3778 if (rc != 0)
3779 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 return rc;
3781}
3782
3783int
Steve French50c2f752007-07-13 00:33:32 +00003784CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3785 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786{
3787 int rc = 0;
3788 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
3790 cFYI(1, ("In CIFSSMBFindClose"));
3791 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3792
3793 /* no sense returning error if session restarted
3794 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003795 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 return 0;
3797 if (rc)
3798 return rc;
3799
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 pSMB->FileID = searchHandle;
3801 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003802 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003803 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003805
Steve Frencha4544342005-08-24 13:59:35 -07003806 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807
3808 /* Since session is dead, search handle closed on server already */
3809 if (rc == -EAGAIN)
3810 rc = 0;
3811
3812 return rc;
3813}
3814
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815int
3816CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003817 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003818 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820{
3821 int rc = 0;
3822 TRANSACTION2_QPI_REQ *pSMB = NULL;
3823 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3824 int name_len, bytes_returned;
3825 __u16 params, byte_count;
3826
Steve French50c2f752007-07-13 00:33:32 +00003827 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003828 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003829 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830
3831GetInodeNumberRetry:
3832 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003833 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 if (rc)
3835 return rc;
3836
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3838 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003839 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003840 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 name_len++; /* trailing null */
3842 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003843 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 name_len = strnlen(searchName, PATH_MAX);
3845 name_len++; /* trailing null */
3846 strncpy(pSMB->FileName, searchName, name_len);
3847 }
3848
3849 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3850 pSMB->TotalDataCount = 0;
3851 pSMB->MaxParameterCount = cpu_to_le16(2);
3852 /* BB find exact max data count below from sess structure BB */
3853 pSMB->MaxDataCount = cpu_to_le16(4000);
3854 pSMB->MaxSetupCount = 0;
3855 pSMB->Reserved = 0;
3856 pSMB->Flags = 0;
3857 pSMB->Timeout = 0;
3858 pSMB->Reserved2 = 0;
3859 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003860 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 pSMB->DataCount = 0;
3862 pSMB->DataOffset = 0;
3863 pSMB->SetupCount = 1;
3864 pSMB->Reserved3 = 0;
3865 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3866 byte_count = params + 1 /* pad */ ;
3867 pSMB->TotalParameterCount = cpu_to_le16(params);
3868 pSMB->ParameterCount = pSMB->TotalParameterCount;
3869 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3870 pSMB->Reserved4 = 0;
3871 pSMB->hdr.smb_buf_length += byte_count;
3872 pSMB->ByteCount = cpu_to_le16(byte_count);
3873
3874 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3875 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3876 if (rc) {
3877 cFYI(1, ("error %d in QueryInternalInfo", rc));
3878 } else {
3879 /* decode response */
3880 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3881 if (rc || (pSMBr->ByteCount < 2))
3882 /* BB also check enough total bytes returned */
3883 /* If rc should we check for EOPNOSUPP and
3884 disable the srvino flag? or in caller? */
3885 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003886 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3888 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003889 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003891 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3893 rc = -EIO;
3894 goto GetInodeNumOut;
3895 }
3896 pfinfo = (struct file_internal_info *)
3897 (data_offset + (char *) &pSMBr->hdr.Protocol);
3898 *inode_number = pfinfo->UniqueId;
3899 }
3900 }
3901GetInodeNumOut:
3902 cifs_buf_release(pSMB);
3903 if (rc == -EAGAIN)
3904 goto GetInodeNumberRetry;
3905 return rc;
3906}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
Igor Mammedov2c556082008-10-23 13:58:42 +04003908/* computes length of UCS string converted to host codepage
3909 * @src: UCS string
3910 * @maxlen: length of the input string in UCS characters
3911 * (not in bytes)
3912 *
3913 * return: size of input string in host codepage
3914 */
3915static int hostlen_fromUCS(const __le16 *src, const int maxlen,
3916 const struct nls_table *nls_codepage) {
3917 int i;
3918 int hostlen = 0;
3919 char to[4];
3920 int charlen;
3921 for (i = 0; (i < maxlen) && src[i]; ++i) {
3922 charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
3923 to, NLS_MAX_CHARSET_SIZE);
3924 hostlen += charlen > 0 ? charlen : 1;
3925 }
3926 return hostlen;
3927}
3928
Igor Mammedovfec45852008-05-16 13:06:30 +04003929/* parses DFS refferal V3 structure
3930 * caller is responsible for freeing target_nodes
3931 * returns:
3932 * on success - 0
3933 * on failure - errno
3934 */
3935static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003936parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003937 unsigned int *num_of_nodes,
3938 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003939 const struct nls_table *nls_codepage, int remap,
3940 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003941{
3942 int i, rc = 0;
3943 char *data_end;
3944 bool is_unicode;
3945 struct dfs_referral_level_3 *ref;
3946
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003947 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3948 is_unicode = true;
3949 else
3950 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003951 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3952
3953 if (*num_of_nodes < 1) {
3954 cERROR(1, ("num_referrals: must be at least > 0,"
3955 "but we get num_referrals = %d\n", *num_of_nodes));
3956 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003957 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003958 }
3959
3960 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003961 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003962 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003963 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003964 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003965 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003966 }
3967
3968 /* get the upper boundary of the resp buffer */
3969 data_end = (char *)(&(pSMBr->PathConsumed)) +
3970 le16_to_cpu(pSMBr->t2.DataCount);
3971
3972 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3973 *num_of_nodes,
3974 le16_to_cpu(pSMBr->DFSFlags)));
3975
3976 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3977 *num_of_nodes, GFP_KERNEL);
3978 if (*target_nodes == NULL) {
3979 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3980 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003981 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003982 }
3983
3984 /* collect neccessary data from referrals */
3985 for (i = 0; i < *num_of_nodes; i++) {
3986 char *temp;
3987 int max_len;
3988 struct dfs_info3_param *node = (*target_nodes)+i;
3989
3990 node->flags = le16_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003991 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003992 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3993 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003994 cifsConvertToUCS((__le16 *) tmp, searchName,
3995 PATH_MAX, nls_codepage, remap);
3996 node->path_consumed = hostlen_fromUCS(tmp,
3997 le16_to_cpu(pSMBr->PathConsumed)/2,
3998 nls_codepage);
3999 kfree(tmp);
4000 } else
4001 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4002
Igor Mammedovfec45852008-05-16 13:06:30 +04004003 node->server_type = le16_to_cpu(ref->ServerType);
4004 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4005
4006 /* copy DfsPath */
4007 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4008 max_len = data_end - temp;
4009 rc = cifs_strncpy_to_host(&(node->path_name), temp,
4010 max_len, is_unicode, nls_codepage);
4011 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004012 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004013
4014 /* copy link target UNC */
4015 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4016 max_len = data_end - temp;
4017 rc = cifs_strncpy_to_host(&(node->node_name), temp,
4018 max_len, is_unicode, nls_codepage);
4019 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004020 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004021
Al Viro1d92cfd2008-06-02 10:59:02 +01004022 ref += le16_to_cpu(ref->Size);
Igor Mammedovfec45852008-05-16 13:06:30 +04004023 }
4024
Steve Frencha1fe78f2008-05-16 18:48:38 +00004025parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004026 if (rc) {
4027 free_dfs_info_array(*target_nodes, *num_of_nodes);
4028 *target_nodes = NULL;
4029 *num_of_nodes = 0;
4030 }
4031 return rc;
4032}
4033
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034int
4035CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4036 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004037 struct dfs_info3_param **target_nodes,
4038 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004039 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040{
4041/* TRANS2_GET_DFS_REFERRAL */
4042 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4043 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 int rc = 0;
4045 int bytes_returned;
4046 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004048 *num_of_nodes = 0;
4049 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050
4051 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4052 if (ses == NULL)
4053 return -ENODEV;
4054getDFSRetry:
4055 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4056 (void **) &pSMBr);
4057 if (rc)
4058 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004059
4060 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004061 but should never be null here anyway */
4062 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 pSMB->hdr.Tid = ses->ipc_tid;
4064 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004065 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004067 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069
4070 if (ses->capabilities & CAP_UNICODE) {
4071 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4072 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004073 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004074 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 name_len++; /* trailing null */
4076 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004077 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 name_len = strnlen(searchName, PATH_MAX);
4079 name_len++; /* trailing null */
4080 strncpy(pSMB->RequestFileName, searchName, name_len);
4081 }
4082
Steve French790fe572007-07-07 19:25:05 +00004083 if (ses->server) {
4084 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004085 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4086 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4087 }
4088
Steve French50c2f752007-07-13 00:33:32 +00004089 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004090
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 params = 2 /* level */ + name_len /*includes null */ ;
4092 pSMB->TotalDataCount = 0;
4093 pSMB->DataCount = 0;
4094 pSMB->DataOffset = 0;
4095 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004096 /* BB find exact max SMB PDU from sess structure BB */
4097 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 pSMB->MaxSetupCount = 0;
4099 pSMB->Reserved = 0;
4100 pSMB->Flags = 0;
4101 pSMB->Timeout = 0;
4102 pSMB->Reserved2 = 0;
4103 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004104 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 pSMB->SetupCount = 1;
4106 pSMB->Reserved3 = 0;
4107 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4108 byte_count = params + 3 /* pad */ ;
4109 pSMB->ParameterCount = cpu_to_le16(params);
4110 pSMB->TotalParameterCount = pSMB->ParameterCount;
4111 pSMB->MaxReferralLevel = cpu_to_le16(3);
4112 pSMB->hdr.smb_buf_length += byte_count;
4113 pSMB->ByteCount = cpu_to_le16(byte_count);
4114
4115 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4116 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4117 if (rc) {
4118 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004119 goto GetDFSRefExit;
4120 }
4121 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004123 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004124 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004125 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004126 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004128
4129 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4130 pSMBr->ByteCount,
4131 le16_to_cpu(pSMBr->t2.DataOffset)));
4132
4133 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004134 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004135 target_nodes, nls_codepage, remap,
4136 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004137
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004139 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
4141 if (rc == -EAGAIN)
4142 goto getDFSRetry;
4143
4144 return rc;
4145}
4146
Steve French20962432005-09-21 22:05:57 -07004147/* Query File System Info such as free space to old servers such as Win 9x */
4148int
4149SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4150{
4151/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4152 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4153 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4154 FILE_SYSTEM_ALLOC_INFO *response_data;
4155 int rc = 0;
4156 int bytes_returned = 0;
4157 __u16 params, byte_count;
4158
4159 cFYI(1, ("OldQFSInfo"));
4160oldQFSInfoRetry:
4161 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4162 (void **) &pSMBr);
4163 if (rc)
4164 return rc;
Steve French20962432005-09-21 22:05:57 -07004165
4166 params = 2; /* level */
4167 pSMB->TotalDataCount = 0;
4168 pSMB->MaxParameterCount = cpu_to_le16(2);
4169 pSMB->MaxDataCount = cpu_to_le16(1000);
4170 pSMB->MaxSetupCount = 0;
4171 pSMB->Reserved = 0;
4172 pSMB->Flags = 0;
4173 pSMB->Timeout = 0;
4174 pSMB->Reserved2 = 0;
4175 byte_count = params + 1 /* pad */ ;
4176 pSMB->TotalParameterCount = cpu_to_le16(params);
4177 pSMB->ParameterCount = pSMB->TotalParameterCount;
4178 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4179 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4180 pSMB->DataCount = 0;
4181 pSMB->DataOffset = 0;
4182 pSMB->SetupCount = 1;
4183 pSMB->Reserved3 = 0;
4184 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4185 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4186 pSMB->hdr.smb_buf_length += byte_count;
4187 pSMB->ByteCount = cpu_to_le16(byte_count);
4188
4189 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4190 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4191 if (rc) {
4192 cFYI(1, ("Send error in QFSInfo = %d", rc));
4193 } else { /* decode response */
4194 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4195
4196 if (rc || (pSMBr->ByteCount < 18))
4197 rc = -EIO; /* bad smb */
4198 else {
4199 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004200 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004201 pSMBr->ByteCount, data_offset));
4202
Steve French50c2f752007-07-13 00:33:32 +00004203 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004204 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4205 FSData->f_bsize =
4206 le16_to_cpu(response_data->BytesPerSector) *
4207 le32_to_cpu(response_data->
4208 SectorsPerAllocationUnit);
4209 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004210 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004211 FSData->f_bfree = FSData->f_bavail =
4212 le32_to_cpu(response_data->FreeAllocationUnits);
4213 cFYI(1,
4214 ("Blocks: %lld Free: %lld Block size %ld",
4215 (unsigned long long)FSData->f_blocks,
4216 (unsigned long long)FSData->f_bfree,
4217 FSData->f_bsize));
4218 }
4219 }
4220 cifs_buf_release(pSMB);
4221
4222 if (rc == -EAGAIN)
4223 goto oldQFSInfoRetry;
4224
4225 return rc;
4226}
4227
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228int
Steve French737b7582005-04-28 22:41:06 -07004229CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230{
4231/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4232 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4233 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4234 FILE_SYSTEM_INFO *response_data;
4235 int rc = 0;
4236 int bytes_returned = 0;
4237 __u16 params, byte_count;
4238
4239 cFYI(1, ("In QFSInfo"));
4240QFSInfoRetry:
4241 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4242 (void **) &pSMBr);
4243 if (rc)
4244 return rc;
4245
4246 params = 2; /* level */
4247 pSMB->TotalDataCount = 0;
4248 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004249 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 pSMB->MaxSetupCount = 0;
4251 pSMB->Reserved = 0;
4252 pSMB->Flags = 0;
4253 pSMB->Timeout = 0;
4254 pSMB->Reserved2 = 0;
4255 byte_count = params + 1 /* pad */ ;
4256 pSMB->TotalParameterCount = cpu_to_le16(params);
4257 pSMB->ParameterCount = pSMB->TotalParameterCount;
4258 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004259 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 pSMB->DataCount = 0;
4261 pSMB->DataOffset = 0;
4262 pSMB->SetupCount = 1;
4263 pSMB->Reserved3 = 0;
4264 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4265 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4266 pSMB->hdr.smb_buf_length += byte_count;
4267 pSMB->ByteCount = cpu_to_le16(byte_count);
4268
4269 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4270 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4271 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004272 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004274 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275
Steve French20962432005-09-21 22:05:57 -07004276 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 rc = -EIO; /* bad smb */
4278 else {
4279 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
4281 response_data =
4282 (FILE_SYSTEM_INFO
4283 *) (((char *) &pSMBr->hdr.Protocol) +
4284 data_offset);
4285 FSData->f_bsize =
4286 le32_to_cpu(response_data->BytesPerSector) *
4287 le32_to_cpu(response_data->
4288 SectorsPerAllocationUnit);
4289 FSData->f_blocks =
4290 le64_to_cpu(response_data->TotalAllocationUnits);
4291 FSData->f_bfree = FSData->f_bavail =
4292 le64_to_cpu(response_data->FreeAllocationUnits);
4293 cFYI(1,
4294 ("Blocks: %lld Free: %lld Block size %ld",
4295 (unsigned long long)FSData->f_blocks,
4296 (unsigned long long)FSData->f_bfree,
4297 FSData->f_bsize));
4298 }
4299 }
4300 cifs_buf_release(pSMB);
4301
4302 if (rc == -EAGAIN)
4303 goto QFSInfoRetry;
4304
4305 return rc;
4306}
4307
4308int
Steve French737b7582005-04-28 22:41:06 -07004309CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310{
4311/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4312 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4313 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4314 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4315 int rc = 0;
4316 int bytes_returned = 0;
4317 __u16 params, byte_count;
4318
4319 cFYI(1, ("In QFSAttributeInfo"));
4320QFSAttributeRetry:
4321 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4322 (void **) &pSMBr);
4323 if (rc)
4324 return rc;
4325
4326 params = 2; /* level */
4327 pSMB->TotalDataCount = 0;
4328 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004329 /* BB find exact max SMB PDU from sess structure BB */
4330 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 pSMB->MaxSetupCount = 0;
4332 pSMB->Reserved = 0;
4333 pSMB->Flags = 0;
4334 pSMB->Timeout = 0;
4335 pSMB->Reserved2 = 0;
4336 byte_count = params + 1 /* pad */ ;
4337 pSMB->TotalParameterCount = cpu_to_le16(params);
4338 pSMB->ParameterCount = pSMB->TotalParameterCount;
4339 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004340 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 pSMB->DataCount = 0;
4342 pSMB->DataOffset = 0;
4343 pSMB->SetupCount = 1;
4344 pSMB->Reserved3 = 0;
4345 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4346 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4347 pSMB->hdr.smb_buf_length += byte_count;
4348 pSMB->ByteCount = cpu_to_le16(byte_count);
4349
4350 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4351 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4352 if (rc) {
4353 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4354 } else { /* decode response */
4355 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4356
Steve French50c2f752007-07-13 00:33:32 +00004357 if (rc || (pSMBr->ByteCount < 13)) {
4358 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 rc = -EIO; /* bad smb */
4360 } else {
4361 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4362 response_data =
4363 (FILE_SYSTEM_ATTRIBUTE_INFO
4364 *) (((char *) &pSMBr->hdr.Protocol) +
4365 data_offset);
4366 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004367 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 }
4369 }
4370 cifs_buf_release(pSMB);
4371
4372 if (rc == -EAGAIN)
4373 goto QFSAttributeRetry;
4374
4375 return rc;
4376}
4377
4378int
Steve French737b7582005-04-28 22:41:06 -07004379CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380{
4381/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4382 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4383 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4384 FILE_SYSTEM_DEVICE_INFO *response_data;
4385 int rc = 0;
4386 int bytes_returned = 0;
4387 __u16 params, byte_count;
4388
4389 cFYI(1, ("In QFSDeviceInfo"));
4390QFSDeviceRetry:
4391 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4392 (void **) &pSMBr);
4393 if (rc)
4394 return rc;
4395
4396 params = 2; /* level */
4397 pSMB->TotalDataCount = 0;
4398 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004399 /* BB find exact max SMB PDU from sess structure BB */
4400 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 pSMB->MaxSetupCount = 0;
4402 pSMB->Reserved = 0;
4403 pSMB->Flags = 0;
4404 pSMB->Timeout = 0;
4405 pSMB->Reserved2 = 0;
4406 byte_count = params + 1 /* pad */ ;
4407 pSMB->TotalParameterCount = cpu_to_le16(params);
4408 pSMB->ParameterCount = pSMB->TotalParameterCount;
4409 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004410 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411
4412 pSMB->DataCount = 0;
4413 pSMB->DataOffset = 0;
4414 pSMB->SetupCount = 1;
4415 pSMB->Reserved3 = 0;
4416 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4417 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4418 pSMB->hdr.smb_buf_length += byte_count;
4419 pSMB->ByteCount = cpu_to_le16(byte_count);
4420
4421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4423 if (rc) {
4424 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4425 } else { /* decode response */
4426 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4427
Steve French630f3f0c2007-10-25 21:17:17 +00004428 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 rc = -EIO; /* bad smb */
4430 else {
4431 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4432 response_data =
Steve French737b7582005-04-28 22:41:06 -07004433 (FILE_SYSTEM_DEVICE_INFO *)
4434 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 data_offset);
4436 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004437 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 }
4439 }
4440 cifs_buf_release(pSMB);
4441
4442 if (rc == -EAGAIN)
4443 goto QFSDeviceRetry;
4444
4445 return rc;
4446}
4447
4448int
Steve French737b7582005-04-28 22:41:06 -07004449CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450{
4451/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4452 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4453 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4454 FILE_SYSTEM_UNIX_INFO *response_data;
4455 int rc = 0;
4456 int bytes_returned = 0;
4457 __u16 params, byte_count;
4458
4459 cFYI(1, ("In QFSUnixInfo"));
4460QFSUnixRetry:
4461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4462 (void **) &pSMBr);
4463 if (rc)
4464 return rc;
4465
4466 params = 2; /* level */
4467 pSMB->TotalDataCount = 0;
4468 pSMB->DataCount = 0;
4469 pSMB->DataOffset = 0;
4470 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004471 /* BB find exact max SMB PDU from sess structure BB */
4472 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 pSMB->MaxSetupCount = 0;
4474 pSMB->Reserved = 0;
4475 pSMB->Flags = 0;
4476 pSMB->Timeout = 0;
4477 pSMB->Reserved2 = 0;
4478 byte_count = params + 1 /* pad */ ;
4479 pSMB->ParameterCount = cpu_to_le16(params);
4480 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004481 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4482 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 pSMB->SetupCount = 1;
4484 pSMB->Reserved3 = 0;
4485 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4486 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4487 pSMB->hdr.smb_buf_length += byte_count;
4488 pSMB->ByteCount = cpu_to_le16(byte_count);
4489
4490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4492 if (rc) {
4493 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4494 } else { /* decode response */
4495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4496
4497 if (rc || (pSMBr->ByteCount < 13)) {
4498 rc = -EIO; /* bad smb */
4499 } else {
4500 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4501 response_data =
4502 (FILE_SYSTEM_UNIX_INFO
4503 *) (((char *) &pSMBr->hdr.Protocol) +
4504 data_offset);
4505 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004506 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 }
4508 }
4509 cifs_buf_release(pSMB);
4510
4511 if (rc == -EAGAIN)
4512 goto QFSUnixRetry;
4513
4514
4515 return rc;
4516}
4517
Jeremy Allisonac670552005-06-22 17:26:35 -07004518int
Steve French45abc6e2005-06-23 13:42:03 -05004519CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004520{
4521/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4522 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4523 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4524 int rc = 0;
4525 int bytes_returned = 0;
4526 __u16 params, param_offset, offset, byte_count;
4527
4528 cFYI(1, ("In SETFSUnixInfo"));
4529SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004530 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004531 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4532 (void **) &pSMBr);
4533 if (rc)
4534 return rc;
4535
4536 params = 4; /* 2 bytes zero followed by info level. */
4537 pSMB->MaxSetupCount = 0;
4538 pSMB->Reserved = 0;
4539 pSMB->Flags = 0;
4540 pSMB->Timeout = 0;
4541 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004542 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4543 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004544 offset = param_offset + params;
4545
4546 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004547 /* BB find exact max SMB PDU from sess structure BB */
4548 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004549 pSMB->SetupCount = 1;
4550 pSMB->Reserved3 = 0;
4551 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4552 byte_count = 1 /* pad */ + params + 12;
4553
4554 pSMB->DataCount = cpu_to_le16(12);
4555 pSMB->ParameterCount = cpu_to_le16(params);
4556 pSMB->TotalDataCount = pSMB->DataCount;
4557 pSMB->TotalParameterCount = pSMB->ParameterCount;
4558 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4559 pSMB->DataOffset = cpu_to_le16(offset);
4560
4561 /* Params. */
4562 pSMB->FileNum = 0;
4563 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4564
4565 /* Data. */
4566 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4567 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4568 pSMB->ClientUnixCap = cpu_to_le64(cap);
4569
4570 pSMB->hdr.smb_buf_length += byte_count;
4571 pSMB->ByteCount = cpu_to_le16(byte_count);
4572
4573 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4574 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4575 if (rc) {
4576 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4577 } else { /* decode response */
4578 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004579 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004580 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004581 }
4582 cifs_buf_release(pSMB);
4583
4584 if (rc == -EAGAIN)
4585 goto SETFSUnixRetry;
4586
4587 return rc;
4588}
4589
4590
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591
4592int
4593CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004594 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595{
4596/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4597 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4598 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4599 FILE_SYSTEM_POSIX_INFO *response_data;
4600 int rc = 0;
4601 int bytes_returned = 0;
4602 __u16 params, byte_count;
4603
4604 cFYI(1, ("In QFSPosixInfo"));
4605QFSPosixRetry:
4606 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4607 (void **) &pSMBr);
4608 if (rc)
4609 return rc;
4610
4611 params = 2; /* level */
4612 pSMB->TotalDataCount = 0;
4613 pSMB->DataCount = 0;
4614 pSMB->DataOffset = 0;
4615 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004616 /* BB find exact max SMB PDU from sess structure BB */
4617 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 pSMB->MaxSetupCount = 0;
4619 pSMB->Reserved = 0;
4620 pSMB->Flags = 0;
4621 pSMB->Timeout = 0;
4622 pSMB->Reserved2 = 0;
4623 byte_count = params + 1 /* pad */ ;
4624 pSMB->ParameterCount = cpu_to_le16(params);
4625 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004626 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4627 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 pSMB->SetupCount = 1;
4629 pSMB->Reserved3 = 0;
4630 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4631 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4632 pSMB->hdr.smb_buf_length += byte_count;
4633 pSMB->ByteCount = cpu_to_le16(byte_count);
4634
4635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4637 if (rc) {
4638 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4639 } else { /* decode response */
4640 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4641
4642 if (rc || (pSMBr->ByteCount < 13)) {
4643 rc = -EIO; /* bad smb */
4644 } else {
4645 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4646 response_data =
4647 (FILE_SYSTEM_POSIX_INFO
4648 *) (((char *) &pSMBr->hdr.Protocol) +
4649 data_offset);
4650 FSData->f_bsize =
4651 le32_to_cpu(response_data->BlockSize);
4652 FSData->f_blocks =
4653 le64_to_cpu(response_data->TotalBlocks);
4654 FSData->f_bfree =
4655 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004656 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 FSData->f_bavail = FSData->f_bfree;
4658 } else {
4659 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004660 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 }
Steve French790fe572007-07-07 19:25:05 +00004662 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004664 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004665 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004667 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 }
4669 }
4670 cifs_buf_release(pSMB);
4671
4672 if (rc == -EAGAIN)
4673 goto QFSPosixRetry;
4674
4675 return rc;
4676}
4677
4678
Steve French50c2f752007-07-13 00:33:32 +00004679/* We can not use write of zero bytes trick to
4680 set file size due to need for large file support. Also note that
4681 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 routine which is only needed to work around a sharing violation bug
4683 in Samba which this routine can run into */
4684
4685int
4686CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004687 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004688 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689{
4690 struct smb_com_transaction2_spi_req *pSMB = NULL;
4691 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4692 struct file_end_of_file_info *parm_data;
4693 int name_len;
4694 int rc = 0;
4695 int bytes_returned = 0;
4696 __u16 params, byte_count, data_count, param_offset, offset;
4697
4698 cFYI(1, ("In SetEOF"));
4699SetEOFRetry:
4700 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4701 (void **) &pSMBr);
4702 if (rc)
4703 return rc;
4704
4705 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4706 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004707 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004708 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 name_len++; /* trailing null */
4710 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004711 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 name_len = strnlen(fileName, PATH_MAX);
4713 name_len++; /* trailing null */
4714 strncpy(pSMB->FileName, fileName, name_len);
4715 }
4716 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004717 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004719 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 pSMB->MaxSetupCount = 0;
4721 pSMB->Reserved = 0;
4722 pSMB->Flags = 0;
4723 pSMB->Timeout = 0;
4724 pSMB->Reserved2 = 0;
4725 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004726 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004728 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004729 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4730 pSMB->InformationLevel =
4731 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4732 else
4733 pSMB->InformationLevel =
4734 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4735 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4737 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004738 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 else
4740 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004741 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 }
4743
4744 parm_data =
4745 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4746 offset);
4747 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4748 pSMB->DataOffset = cpu_to_le16(offset);
4749 pSMB->SetupCount = 1;
4750 pSMB->Reserved3 = 0;
4751 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4752 byte_count = 3 /* pad */ + params + data_count;
4753 pSMB->DataCount = cpu_to_le16(data_count);
4754 pSMB->TotalDataCount = pSMB->DataCount;
4755 pSMB->ParameterCount = cpu_to_le16(params);
4756 pSMB->TotalParameterCount = pSMB->ParameterCount;
4757 pSMB->Reserved4 = 0;
4758 pSMB->hdr.smb_buf_length += byte_count;
4759 parm_data->FileSize = cpu_to_le64(size);
4760 pSMB->ByteCount = cpu_to_le16(byte_count);
4761 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4762 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004763 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
4766 cifs_buf_release(pSMB);
4767
4768 if (rc == -EAGAIN)
4769 goto SetEOFRetry;
4770
4771 return rc;
4772}
4773
4774int
Steve French50c2f752007-07-13 00:33:32 +00004775CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004776 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777{
4778 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 char *data_offset;
4780 struct file_end_of_file_info *parm_data;
4781 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 __u16 params, param_offset, offset, byte_count, count;
4783
4784 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4785 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004786 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4787
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 if (rc)
4789 return rc;
4790
4791 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4792 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004793
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 params = 6;
4795 pSMB->MaxSetupCount = 0;
4796 pSMB->Reserved = 0;
4797 pSMB->Flags = 0;
4798 pSMB->Timeout = 0;
4799 pSMB->Reserved2 = 0;
4800 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4801 offset = param_offset + params;
4802
Steve French50c2f752007-07-13 00:33:32 +00004803 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804
4805 count = sizeof(struct file_end_of_file_info);
4806 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004807 /* BB find exact max SMB PDU from sess structure BB */
4808 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 pSMB->SetupCount = 1;
4810 pSMB->Reserved3 = 0;
4811 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4812 byte_count = 3 /* pad */ + params + count;
4813 pSMB->DataCount = cpu_to_le16(count);
4814 pSMB->ParameterCount = cpu_to_le16(params);
4815 pSMB->TotalDataCount = pSMB->DataCount;
4816 pSMB->TotalParameterCount = pSMB->ParameterCount;
4817 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4818 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004819 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4820 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->DataOffset = cpu_to_le16(offset);
4822 parm_data->FileSize = cpu_to_le64(size);
4823 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004824 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4826 pSMB->InformationLevel =
4827 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4828 else
4829 pSMB->InformationLevel =
4830 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004831 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4833 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004834 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 else
4836 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004837 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 }
4839 pSMB->Reserved4 = 0;
4840 pSMB->hdr.smb_buf_length += byte_count;
4841 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004842 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 if (rc) {
4844 cFYI(1,
4845 ("Send error in SetFileInfo (SetFileSize) = %d",
4846 rc));
4847 }
4848
Steve French50c2f752007-07-13 00:33:32 +00004849 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 since file handle passed in no longer valid */
4851
4852 return rc;
4853}
4854
Steve French50c2f752007-07-13 00:33:32 +00004855/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 an open handle, rather than by pathname - this is awkward due to
4857 potential access conflicts on the open, but it is unavoidable for these
4858 old servers since the only other choice is to go from 100 nanosecond DCE
4859 time and resort to the original setpathinfo level which takes the ancient
4860 DOS time format with 2 second granularity */
4861int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004862CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4863 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864{
4865 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 char *data_offset;
4867 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 __u16 params, param_offset, offset, byte_count, count;
4869
4870 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004871 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4872
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 if (rc)
4874 return rc;
4875
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004876 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4877 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004878
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 params = 6;
4880 pSMB->MaxSetupCount = 0;
4881 pSMB->Reserved = 0;
4882 pSMB->Flags = 0;
4883 pSMB->Timeout = 0;
4884 pSMB->Reserved2 = 0;
4885 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4886 offset = param_offset + params;
4887
Steve French50c2f752007-07-13 00:33:32 +00004888 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889
Steve French26f57362007-08-30 22:09:15 +00004890 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004892 /* BB find max SMB PDU from sess */
4893 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 pSMB->SetupCount = 1;
4895 pSMB->Reserved3 = 0;
4896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4897 byte_count = 3 /* pad */ + params + count;
4898 pSMB->DataCount = cpu_to_le16(count);
4899 pSMB->ParameterCount = cpu_to_le16(params);
4900 pSMB->TotalDataCount = pSMB->DataCount;
4901 pSMB->TotalParameterCount = pSMB->ParameterCount;
4902 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4903 pSMB->DataOffset = cpu_to_le16(offset);
4904 pSMB->Fid = fid;
4905 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4906 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4907 else
4908 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4909 pSMB->Reserved4 = 0;
4910 pSMB->hdr.smb_buf_length += byte_count;
4911 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004912 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004913 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004914 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004915 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916
Steve French50c2f752007-07-13 00:33:32 +00004917 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 since file handle passed in no longer valid */
4919
4920 return rc;
4921}
4922
Jeff Layton6d22f092008-09-23 11:48:35 -04004923int
4924CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4925 bool delete_file, __u16 fid, __u32 pid_of_opener)
4926{
4927 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4928 char *data_offset;
4929 int rc = 0;
4930 __u16 params, param_offset, offset, byte_count, count;
4931
4932 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4933 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4934
4935 if (rc)
4936 return rc;
4937
4938 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4939 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4940
4941 params = 6;
4942 pSMB->MaxSetupCount = 0;
4943 pSMB->Reserved = 0;
4944 pSMB->Flags = 0;
4945 pSMB->Timeout = 0;
4946 pSMB->Reserved2 = 0;
4947 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4948 offset = param_offset + params;
4949
4950 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4951
4952 count = 1;
4953 pSMB->MaxParameterCount = cpu_to_le16(2);
4954 /* BB find max SMB PDU from sess */
4955 pSMB->MaxDataCount = cpu_to_le16(1000);
4956 pSMB->SetupCount = 1;
4957 pSMB->Reserved3 = 0;
4958 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4959 byte_count = 3 /* pad */ + params + count;
4960 pSMB->DataCount = cpu_to_le16(count);
4961 pSMB->ParameterCount = cpu_to_le16(params);
4962 pSMB->TotalDataCount = pSMB->DataCount;
4963 pSMB->TotalParameterCount = pSMB->ParameterCount;
4964 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4965 pSMB->DataOffset = cpu_to_le16(offset);
4966 pSMB->Fid = fid;
4967 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4968 pSMB->Reserved4 = 0;
4969 pSMB->hdr.smb_buf_length += byte_count;
4970 pSMB->ByteCount = cpu_to_le16(byte_count);
4971 *data_offset = delete_file ? 1 : 0;
4972 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4973 if (rc)
4974 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4975
4976 return rc;
4977}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978
4979int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004980CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4981 const char *fileName, const FILE_BASIC_INFO *data,
4982 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983{
4984 TRANSACTION2_SPI_REQ *pSMB = NULL;
4985 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4986 int name_len;
4987 int rc = 0;
4988 int bytes_returned = 0;
4989 char *data_offset;
4990 __u16 params, param_offset, offset, byte_count, count;
4991
4992 cFYI(1, ("In SetTimes"));
4993
4994SetTimesRetry:
4995 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4996 (void **) &pSMBr);
4997 if (rc)
4998 return rc;
4999
5000 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5001 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005002 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005003 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 name_len++; /* trailing null */
5005 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005006 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 name_len = strnlen(fileName, PATH_MAX);
5008 name_len++; /* trailing null */
5009 strncpy(pSMB->FileName, fileName, name_len);
5010 }
5011
5012 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005013 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005015 /* BB find max SMB PDU from sess structure BB */
5016 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 pSMB->MaxSetupCount = 0;
5018 pSMB->Reserved = 0;
5019 pSMB->Flags = 0;
5020 pSMB->Timeout = 0;
5021 pSMB->Reserved2 = 0;
5022 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005023 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 offset = param_offset + params;
5025 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5026 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5027 pSMB->DataOffset = cpu_to_le16(offset);
5028 pSMB->SetupCount = 1;
5029 pSMB->Reserved3 = 0;
5030 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5031 byte_count = 3 /* pad */ + params + count;
5032
5033 pSMB->DataCount = cpu_to_le16(count);
5034 pSMB->ParameterCount = cpu_to_le16(params);
5035 pSMB->TotalDataCount = pSMB->DataCount;
5036 pSMB->TotalParameterCount = pSMB->ParameterCount;
5037 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5038 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5039 else
5040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5041 pSMB->Reserved4 = 0;
5042 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005043 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 pSMB->ByteCount = cpu_to_le16(byte_count);
5045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005047 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049
5050 cifs_buf_release(pSMB);
5051
5052 if (rc == -EAGAIN)
5053 goto SetTimesRetry;
5054
5055 return rc;
5056}
5057
5058/* Can not be used to set time stamps yet (due to old DOS time format) */
5059/* Can be used to set attributes */
5060#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5061 handling it anyway and NT4 was what we thought it would be needed for
5062 Do not delete it until we prove whether needed for Win9x though */
5063int
5064CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5065 __u16 dos_attrs, const struct nls_table *nls_codepage)
5066{
5067 SETATTR_REQ *pSMB = NULL;
5068 SETATTR_RSP *pSMBr = NULL;
5069 int rc = 0;
5070 int bytes_returned;
5071 int name_len;
5072
5073 cFYI(1, ("In SetAttrLegacy"));
5074
5075SetAttrLgcyRetry:
5076 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5077 (void **) &pSMBr);
5078 if (rc)
5079 return rc;
5080
5081 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5082 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005083 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 PATH_MAX, nls_codepage);
5085 name_len++; /* trailing null */
5086 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005087 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 name_len = strnlen(fileName, PATH_MAX);
5089 name_len++; /* trailing null */
5090 strncpy(pSMB->fileName, fileName, name_len);
5091 }
5092 pSMB->attr = cpu_to_le16(dos_attrs);
5093 pSMB->BufferFormat = 0x04;
5094 pSMB->hdr.smb_buf_length += name_len + 1;
5095 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5096 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5097 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005098 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100
5101 cifs_buf_release(pSMB);
5102
5103 if (rc == -EAGAIN)
5104 goto SetAttrLgcyRetry;
5105
5106 return rc;
5107}
5108#endif /* temporarily unneeded SetAttr legacy function */
5109
5110int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005111CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005112 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005113 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114{
5115 TRANSACTION2_SPI_REQ *pSMB = NULL;
5116 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5117 int name_len;
5118 int rc = 0;
5119 int bytes_returned = 0;
5120 FILE_UNIX_BASIC_INFO *data_offset;
5121 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005122 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123
5124 cFYI(1, ("In SetUID/GID/Mode"));
5125setPermsRetry:
5126 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5127 (void **) &pSMBr);
5128 if (rc)
5129 return rc;
5130
5131 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5132 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005133 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005134 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 name_len++; /* trailing null */
5136 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005137 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 name_len = strnlen(fileName, PATH_MAX);
5139 name_len++; /* trailing null */
5140 strncpy(pSMB->FileName, fileName, name_len);
5141 }
5142
5143 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005144 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005146 /* BB find max SMB PDU from sess structure BB */
5147 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 pSMB->MaxSetupCount = 0;
5149 pSMB->Reserved = 0;
5150 pSMB->Flags = 0;
5151 pSMB->Timeout = 0;
5152 pSMB->Reserved2 = 0;
5153 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005154 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 offset = param_offset + params;
5156 data_offset =
5157 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5158 offset);
5159 memset(data_offset, 0, count);
5160 pSMB->DataOffset = cpu_to_le16(offset);
5161 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5162 pSMB->SetupCount = 1;
5163 pSMB->Reserved3 = 0;
5164 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5165 byte_count = 3 /* pad */ + params + count;
5166 pSMB->ParameterCount = cpu_to_le16(params);
5167 pSMB->DataCount = cpu_to_le16(count);
5168 pSMB->TotalParameterCount = pSMB->ParameterCount;
5169 pSMB->TotalDataCount = pSMB->DataCount;
5170 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5171 pSMB->Reserved4 = 0;
5172 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005173 /* Samba server ignores set of file size to zero due to bugs in some
5174 older clients, but we should be precise - we use SetFileSize to
5175 set file size and do not want to truncate file size to zero
5176 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005177 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005178 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5179 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5180 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5181 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5182 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5183 data_offset->Uid = cpu_to_le64(args->uid);
5184 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005186 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5187 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005189
Steve French790fe572007-07-07 19:25:05 +00005190 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005192 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005194 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005196 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005198 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005200 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005202 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5204
5205
5206 pSMB->ByteCount = cpu_to_le16(byte_count);
5207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005209 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211
Steve French0d817bc2008-05-22 02:02:03 +00005212 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 if (rc == -EAGAIN)
5214 goto setPermsRetry;
5215 return rc;
5216}
5217
Steve French50c2f752007-07-13 00:33:32 +00005218int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005219 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005220 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005221 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222{
5223 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005224 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5225 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005226 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 int bytes_returned;
5228
Steve French50c2f752007-07-13 00:33:32 +00005229 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005231 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 if (rc)
5233 return rc;
5234
5235 pSMB->TotalParameterCount = 0 ;
5236 pSMB->TotalDataCount = 0;
5237 pSMB->MaxParameterCount = cpu_to_le32(2);
5238 /* BB find exact data count max from sess structure BB */
5239 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005240/* BB VERIFY verify which is correct for above BB */
5241 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5242 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5243
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 pSMB->MaxSetupCount = 4;
5245 pSMB->Reserved = 0;
5246 pSMB->ParameterOffset = 0;
5247 pSMB->DataCount = 0;
5248 pSMB->DataOffset = 0;
5249 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5250 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5251 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005252 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5254 pSMB->Reserved2 = 0;
5255 pSMB->CompletionFilter = cpu_to_le32(filter);
5256 pSMB->Fid = netfid; /* file handle always le */
5257 pSMB->ByteCount = 0;
5258
5259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005260 (struct smb_hdr *)pSMBr, &bytes_returned,
5261 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 if (rc) {
5263 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005264 } else {
5265 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005266 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005267 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005268 sizeof(struct dir_notify_req),
5269 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005270 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005271 dnotify_req->Pid = pSMB->hdr.Pid;
5272 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5273 dnotify_req->Mid = pSMB->hdr.Mid;
5274 dnotify_req->Tid = pSMB->hdr.Tid;
5275 dnotify_req->Uid = pSMB->hdr.Uid;
5276 dnotify_req->netfid = netfid;
5277 dnotify_req->pfile = pfile;
5278 dnotify_req->filter = filter;
5279 dnotify_req->multishot = multishot;
5280 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005281 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005282 &GlobalDnotifyReqList);
5283 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005284 } else
Steve French47c786e2005-10-11 20:03:18 -07005285 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 }
5287 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005288 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289}
5290#ifdef CONFIG_CIFS_XATTR
5291ssize_t
5292CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5293 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005294 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005295 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296{
5297 /* BB assumes one setup word */
5298 TRANSACTION2_QPI_REQ *pSMB = NULL;
5299 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5300 int rc = 0;
5301 int bytes_returned;
5302 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005303 struct fea *temp_fea;
5304 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 __u16 params, byte_count;
5306
5307 cFYI(1, ("In Query All EAs path %s", searchName));
5308QAllEAsRetry:
5309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5310 (void **) &pSMBr);
5311 if (rc)
5312 return rc;
5313
5314 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5315 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005316 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005317 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 name_len++; /* trailing null */
5319 name_len *= 2;
5320 } else { /* BB improve the check for buffer overruns BB */
5321 name_len = strnlen(searchName, PATH_MAX);
5322 name_len++; /* trailing null */
5323 strncpy(pSMB->FileName, searchName, name_len);
5324 }
5325
Steve French50c2f752007-07-13 00:33:32 +00005326 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 pSMB->TotalDataCount = 0;
5328 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005329 /* BB find exact max SMB PDU from sess structure BB */
5330 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 pSMB->MaxSetupCount = 0;
5332 pSMB->Reserved = 0;
5333 pSMB->Flags = 0;
5334 pSMB->Timeout = 0;
5335 pSMB->Reserved2 = 0;
5336 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005337 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 pSMB->DataCount = 0;
5339 pSMB->DataOffset = 0;
5340 pSMB->SetupCount = 1;
5341 pSMB->Reserved3 = 0;
5342 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5343 byte_count = params + 1 /* pad */ ;
5344 pSMB->TotalParameterCount = cpu_to_le16(params);
5345 pSMB->ParameterCount = pSMB->TotalParameterCount;
5346 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5347 pSMB->Reserved4 = 0;
5348 pSMB->hdr.smb_buf_length += byte_count;
5349 pSMB->ByteCount = cpu_to_le16(byte_count);
5350
5351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5352 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5353 if (rc) {
5354 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5355 } else { /* decode response */
5356 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5357
5358 /* BB also check enough total bytes returned */
5359 /* BB we need to improve the validity checking
5360 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005361 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 rc = -EIO; /* bad smb */
5363 /* else if (pFindData){
5364 memcpy((char *) pFindData,
5365 (char *) &pSMBr->hdr.Protocol +
5366 data_offset, kl);
5367 }*/ else {
5368 /* check that length of list is not more than bcc */
5369 /* check that each entry does not go beyond length
5370 of list */
5371 /* check that each element of each entry does not
5372 go beyond end of list */
5373 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005374 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 rc = 0;
5376 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005377 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 ea_response_data = (struct fealist *)
5379 (((char *) &pSMBr->hdr.Protocol) +
5380 data_offset);
5381 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005382 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005383 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005385 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 } else {
5387 /* account for ea list len */
5388 name_len -= 4;
5389 temp_fea = ea_response_data->list;
5390 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005391 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 __u16 value_len;
5393 name_len -= 4;
5394 temp_ptr += 4;
5395 rc += temp_fea->name_len;
5396 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005397 rc = rc + 5 + 1;
5398 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005399 memcpy(EAData, "user.", 5);
5400 EAData += 5;
5401 memcpy(EAData, temp_ptr,
5402 temp_fea->name_len);
5403 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 /* null terminate name */
5405 *EAData = 0;
5406 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005407 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 /* skip copy - calc size only */
5409 } else {
5410 /* stop before overrun buffer */
5411 rc = -ERANGE;
5412 break;
5413 }
5414 name_len -= temp_fea->name_len;
5415 temp_ptr += temp_fea->name_len;
5416 /* account for trailing null */
5417 name_len--;
5418 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005419 value_len =
5420 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 name_len -= value_len;
5422 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005423 /* BB check that temp_ptr is still
5424 within the SMB BB*/
5425
5426 /* no trailing null to account for
5427 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 /* go on to next EA */
5429 temp_fea = (struct fea *)temp_ptr;
5430 }
5431 }
5432 }
5433 }
Steve French0d817bc2008-05-22 02:02:03 +00005434 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 if (rc == -EAGAIN)
5436 goto QAllEAsRetry;
5437
5438 return (ssize_t)rc;
5439}
5440
Steve French50c2f752007-07-13 00:33:32 +00005441ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5442 const unsigned char *searchName, const unsigned char *ea_name,
5443 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005444 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445{
5446 TRANSACTION2_QPI_REQ *pSMB = NULL;
5447 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5448 int rc = 0;
5449 int bytes_returned;
5450 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005451 struct fea *temp_fea;
5452 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 __u16 params, byte_count;
5454
5455 cFYI(1, ("In Query EA path %s", searchName));
5456QEARetry:
5457 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5458 (void **) &pSMBr);
5459 if (rc)
5460 return rc;
5461
5462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5463 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005464 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005465 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 name_len++; /* trailing null */
5467 name_len *= 2;
5468 } else { /* BB improve the check for buffer overruns BB */
5469 name_len = strnlen(searchName, PATH_MAX);
5470 name_len++; /* trailing null */
5471 strncpy(pSMB->FileName, searchName, name_len);
5472 }
5473
Steve French50c2f752007-07-13 00:33:32 +00005474 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 pSMB->TotalDataCount = 0;
5476 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005477 /* BB find exact max SMB PDU from sess structure BB */
5478 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 pSMB->MaxSetupCount = 0;
5480 pSMB->Reserved = 0;
5481 pSMB->Flags = 0;
5482 pSMB->Timeout = 0;
5483 pSMB->Reserved2 = 0;
5484 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005485 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 pSMB->DataCount = 0;
5487 pSMB->DataOffset = 0;
5488 pSMB->SetupCount = 1;
5489 pSMB->Reserved3 = 0;
5490 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5491 byte_count = params + 1 /* pad */ ;
5492 pSMB->TotalParameterCount = cpu_to_le16(params);
5493 pSMB->ParameterCount = pSMB->TotalParameterCount;
5494 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5495 pSMB->Reserved4 = 0;
5496 pSMB->hdr.smb_buf_length += byte_count;
5497 pSMB->ByteCount = cpu_to_le16(byte_count);
5498
5499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5501 if (rc) {
5502 cFYI(1, ("Send error in Query EA = %d", rc));
5503 } else { /* decode response */
5504 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5505
5506 /* BB also check enough total bytes returned */
5507 /* BB we need to improve the validity checking
5508 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005509 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 rc = -EIO; /* bad smb */
5511 /* else if (pFindData){
5512 memcpy((char *) pFindData,
5513 (char *) &pSMBr->hdr.Protocol +
5514 data_offset, kl);
5515 }*/ else {
5516 /* check that length of list is not more than bcc */
5517 /* check that each entry does not go beyond length
5518 of list */
5519 /* check that each element of each entry does not
5520 go beyond end of list */
5521 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005522 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 rc = -ENODATA;
5524 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005525 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 ea_response_data = (struct fealist *)
5527 (((char *) &pSMBr->hdr.Protocol) +
5528 data_offset);
5529 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005530 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005531 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005533 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 } else {
5535 /* account for ea list len */
5536 name_len -= 4;
5537 temp_fea = ea_response_data->list;
5538 temp_ptr = (char *)temp_fea;
5539 /* loop through checking if we have a matching
5540 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005541 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005542 __u16 value_len;
5543 name_len -= 4;
5544 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005545 value_len =
5546 le16_to_cpu(temp_fea->value_len);
5547 /* BB validate that value_len falls within SMB,
5548 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005549 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005550 temp_fea->name_len) == 0) {
5551 /* found a match */
5552 rc = value_len;
5553 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005554 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 memcpy(ea_value,
5556 temp_fea->name+temp_fea->name_len+1,
5557 rc);
Steve French50c2f752007-07-13 00:33:32 +00005558 /* ea values, unlike ea
5559 names, are not null
5560 terminated */
Steve French790fe572007-07-07 19:25:05 +00005561 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 /* skip copy - calc size only */
5563 } else {
Steve French50c2f752007-07-13 00:33:32 +00005564 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 rc = -ERANGE;
5566 }
5567 break;
5568 }
5569 name_len -= temp_fea->name_len;
5570 temp_ptr += temp_fea->name_len;
5571 /* account for trailing null */
5572 name_len--;
5573 temp_ptr++;
5574 name_len -= value_len;
5575 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005576 /* No trailing null to account for in
5577 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 temp_fea = (struct fea *)temp_ptr;
5579 }
Steve French50c2f752007-07-13 00:33:32 +00005580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 }
5582 }
Steve French0d817bc2008-05-22 02:02:03 +00005583 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 if (rc == -EAGAIN)
5585 goto QEARetry;
5586
5587 return (ssize_t)rc;
5588}
5589
5590int
5591CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005592 const char *ea_name, const void *ea_value,
5593 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5594 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595{
5596 struct smb_com_transaction2_spi_req *pSMB = NULL;
5597 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5598 struct fealist *parm_data;
5599 int name_len;
5600 int rc = 0;
5601 int bytes_returned = 0;
5602 __u16 params, param_offset, byte_count, offset, count;
5603
5604 cFYI(1, ("In SetEA"));
5605SetEARetry:
5606 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5607 (void **) &pSMBr);
5608 if (rc)
5609 return rc;
5610
5611 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5612 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005613 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005614 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 name_len++; /* trailing null */
5616 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005617 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 name_len = strnlen(fileName, PATH_MAX);
5619 name_len++; /* trailing null */
5620 strncpy(pSMB->FileName, fileName, name_len);
5621 }
5622
5623 params = 6 + name_len;
5624
5625 /* done calculating parms using name_len of file name,
5626 now use name_len to calculate length of ea name
5627 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005628 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 name_len = 0;
5630 else
Steve French50c2f752007-07-13 00:33:32 +00005631 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005633 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005635 /* BB find max SMB PDU from sess */
5636 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 pSMB->MaxSetupCount = 0;
5638 pSMB->Reserved = 0;
5639 pSMB->Flags = 0;
5640 pSMB->Timeout = 0;
5641 pSMB->Reserved2 = 0;
5642 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005643 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 offset = param_offset + params;
5645 pSMB->InformationLevel =
5646 cpu_to_le16(SMB_SET_FILE_EA);
5647
5648 parm_data =
5649 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5650 offset);
5651 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5652 pSMB->DataOffset = cpu_to_le16(offset);
5653 pSMB->SetupCount = 1;
5654 pSMB->Reserved3 = 0;
5655 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5656 byte_count = 3 /* pad */ + params + count;
5657 pSMB->DataCount = cpu_to_le16(count);
5658 parm_data->list_len = cpu_to_le32(count);
5659 parm_data->list[0].EA_flags = 0;
5660 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005661 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005663 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005664 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 parm_data->list[0].name[name_len] = 0;
5666 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5667 /* caller ensures that ea_value_len is less than 64K but
5668 we need to ensure that it fits within the smb */
5669
Steve French50c2f752007-07-13 00:33:32 +00005670 /*BB add length check to see if it would fit in
5671 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005672 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5673 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005674 memcpy(parm_data->list[0].name+name_len+1,
5675 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
5677 pSMB->TotalDataCount = pSMB->DataCount;
5678 pSMB->ParameterCount = cpu_to_le16(params);
5679 pSMB->TotalParameterCount = pSMB->ParameterCount;
5680 pSMB->Reserved4 = 0;
5681 pSMB->hdr.smb_buf_length += byte_count;
5682 pSMB->ByteCount = cpu_to_le16(byte_count);
5683 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005685 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687
5688 cifs_buf_release(pSMB);
5689
5690 if (rc == -EAGAIN)
5691 goto SetEARetry;
5692
5693 return rc;
5694}
5695
5696#endif