blob: cadacae46b82e715e7604c7beeb7110c41c782bb [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
Suresh Jayaraman968460e2009-04-20 18:54:21 +053091cifs_strlcpy_to_host(char **dst, const char *src, const int maxlen,
Igor Mammedovfec45852008-05-16 13:06:30 +040092 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);
Suresh Jayaraman968460e2009-04-20 18:54:21 +053098 *dst = kmalloc((4 * plen) + 2, GFP_KERNEL);
Igor Mammedovfec45852008-05-16 13:06:30 +040099 if (!*dst)
Suresh Jayaraman968460e2009-04-20 18:54:21 +0530100 goto cifs_strlcpy_to_host_ErrExit;
Igor Mammedovfec45852008-05-16 13:06:30 +0400101 cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
Suresh Jayaraman968460e2009-04-20 18:54:21 +0530102 (*dst)[plen] = 0;
103 (*dst)[plen+1] = 0; /* needed for Unicode */
Igor Mammedovfec45852008-05-16 13:06:30 +0400104 } else {
105 plen = strnlen(src, maxlen);
106 *dst = kmalloc(plen + 2, GFP_KERNEL);
107 if (!*dst)
Suresh Jayaraman968460e2009-04-20 18:54:21 +0530108 goto cifs_strlcpy_to_host_ErrExit;
109 strlcpy(*dst, src, plen);
Igor Mammedovfec45852008-05-16 13:06:30 +0400110 }
Igor Mammedovfec45852008-05-16 13:06:30 +0400111 return 0;
112
Suresh Jayaraman968460e2009-04-20 18:54:21 +0530113cifs_strlcpy_to_host_ErrExit:
Igor Mammedovfec45852008-05-16 13:06:30 +0400114 cERROR(1, ("Failed to allocate buffer for string\n"));
115 return -ENOMEM;
116}
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/* Mark as invalid, all open files on tree connections since they
120 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +0000121static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000124 struct list_head *tmp;
125 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127/* list all files open on tree connection and mark them invalid */
128 write_lock(&GlobalSMBSeslock);
129 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000130 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000131 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700134 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
135 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Steve Frenchad7a2922008-02-07 23:25:02 +0000138/* Allocate and return pointer to an SMB request buffer, and set basic
139 SMB information in the SMB header. If the return code is zero, this
140 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int
142small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000143 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 int rc = 0;
146
147 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
148 check for tcp and smb session status done differently
149 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000150 if (tcon) {
151 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800152 /* only tree disconnect, open, and write,
153 (and ulogoff which does not have tcon)
154 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000155 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000156 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800157 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000158 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800159 smb_command));
160 return -ENODEV;
161 }
162 }
Steve French790fe572007-07-07 19:25:05 +0000163 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000164 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000166 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700167 reconnect, should be greater than cifs socket
168 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000169 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000170 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000172 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000173 CifsGood), 10 * HZ);
174 if (tcon->ses->server->tcpStatus ==
175 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000177 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000179 cFYI(1, ("gave up waiting on "
180 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700182 } /* else "hard" mount - keep retrying
183 until process is killed or server
184 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 } else /* TCP session is reestablished now */
186 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 }
Steve French50c2f752007-07-13 00:33:32 +0000188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 nls_codepage = load_nls_default();
190 /* need to prevent multiple threads trying to
191 simultaneously reconnect the same SMB session */
192 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000193 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000194 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700195 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000196 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000198 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000199 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700201 /* BB FIXME add code to check if wsize needs
202 update due to negotiated smb buffer size
203 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000204 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000206 /* tell server Unix caps we support */
207 if (tcon->ses->capabilities & CAP_UNIX)
208 reset_cifs_unix_caps(
209 0 /* no xid */,
210 tcon,
211 NULL /* we do not know sb */,
212 NULL /* no vol info */);
213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000216 /* Removed call to reopen open files here.
217 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700218 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Steve French50c2f752007-07-13 00:33:32 +0000220 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700221 know whether we can continue or not without
222 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000223 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 case SMB_COM_READ_ANDX:
225 case SMB_COM_WRITE_ANDX:
226 case SMB_COM_CLOSE:
227 case SMB_COM_FIND_CLOSE2:
228 case SMB_COM_LOCKING_ANDX: {
229 unload_nls(nls_codepage);
230 return -EAGAIN;
231 }
232 }
233 } else {
234 up(&tcon->ses->sesSem);
235 }
236 unload_nls(nls_codepage);
237
238 } else {
239 return -EIO;
240 }
241 }
Steve French790fe572007-07-07 19:25:05 +0000242 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 return rc;
244
245 *request_buf = cifs_small_buf_get();
246 if (*request_buf == NULL) {
247 /* BB should we add a retry in here if not a writepage? */
248 return -ENOMEM;
249 }
250
Steve French63135e02007-07-17 17:34:02 +0000251 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000252 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Steve French790fe572007-07-07 19:25:05 +0000254 if (tcon != NULL)
255 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000258}
259
Steve French12b3b8f2006-02-09 21:12:47 +0000260int
Steve French50c2f752007-07-13 00:33:32 +0000261small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000262 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000263{
264 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000265 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000266
Steve French5815449d2006-02-14 01:36:20 +0000267 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000268 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 return rc;
270
Steve French04fdabe2006-02-10 05:52:50 +0000271 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000272 buffer->Mid = GetNextMid(ses->server);
273 if (ses->capabilities & CAP_UNICODE)
274 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000275 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000276 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
277
278 /* uid, tid can stay at zero as set in header assemble */
279
Steve French50c2f752007-07-13 00:33:32 +0000280 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000281 this function is used after 1st of session setup requests */
282
283 return rc;
284}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286/* If the return code is zero, this function must fill in request_buf pointer */
287static int
288smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
289 void **request_buf /* returned */ ,
290 void **response_buf /* returned */ )
291{
292 int rc = 0;
293
294 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
295 check for tcp and smb session status done differently
296 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000297 if (tcon) {
Steve Frenchbfb59822008-11-18 16:33:48 +0000298 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800299 /* only tree disconnect, open, and write,
300 (and ulogoff which does not have tcon)
301 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000302 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800303 (smb_command != SMB_COM_OPEN_ANDX) &&
304 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000305 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800306 smb_command));
307 return -ENODEV;
308 }
309 }
310
Steve French790fe572007-07-07 19:25:05 +0000311 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000312 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700314 /* Give Demultiplex thread up to 10 seconds to
315 reconnect, should be greater than cifs socket
316 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000317 while (tcon->ses->server->tcpStatus ==
318 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000320 (tcon->ses->server->tcpStatus ==
321 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000322 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700323 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000325 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000327 cFYI(1, ("gave up waiting on "
328 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700330 } /* else "hard" mount - keep retrying
331 until process is killed or server
332 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 } else /* TCP session is reestablished now */
334 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 nls_codepage = load_nls_default();
337 /* need to prevent multiple threads trying to
338 simultaneously reconnect the same SMB session */
339 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000340 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000341 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700342 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000343 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700345 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
346 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700348 /* BB FIXME add code to check if wsize needs
349 update due to negotiated smb buffer size
350 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000351 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000353 /* tell server Unix caps we support */
354 if (tcon->ses->capabilities & CAP_UNIX)
355 reset_cifs_unix_caps(
356 0 /* no xid */,
357 tcon,
358 NULL /* do not know sb */,
359 NULL /* no vol info */);
360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000363 /* Removed call to reopen open files here.
364 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700365 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Steve French50c2f752007-07-13 00:33:32 +0000367 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700368 know whether we can continue or not without
369 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000370 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 case SMB_COM_READ_ANDX:
372 case SMB_COM_WRITE_ANDX:
373 case SMB_COM_CLOSE:
374 case SMB_COM_FIND_CLOSE2:
375 case SMB_COM_LOCKING_ANDX: {
376 unload_nls(nls_codepage);
377 return -EAGAIN;
378 }
379 }
380 } else {
381 up(&tcon->ses->sesSem);
382 }
383 unload_nls(nls_codepage);
384
385 } else {
386 return -EIO;
387 }
388 }
Steve French790fe572007-07-07 19:25:05 +0000389 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return rc;
391
392 *request_buf = cifs_buf_get();
393 if (*request_buf == NULL) {
394 /* BB should we add a retry in here if not a writepage? */
395 return -ENOMEM;
396 }
397 /* Although the original thought was we needed the response buf for */
398 /* potential retries of smb operations it turns out we can determine */
399 /* from the mid flags when the request buffer can be resent without */
400 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000401 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000402 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000405 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Steve French790fe572007-07-07 19:25:05 +0000407 if (tcon != NULL)
408 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return rc;
411}
412
Steve French50c2f752007-07-13 00:33:32 +0000413static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
415 int rc = -EINVAL;
416 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000417 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /* check for plausible wct, bcc and t2 data and parm sizes */
420 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000421 if (pSMB->hdr.WordCount >= 10) {
422 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
424 /* check that bcc is at least as big as parms + data */
425 /* check that bcc is less than negotiated smb buffer */
426 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000427 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000428 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000429 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000431 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700432 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000434 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000435 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
437 return 0;
438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440 }
441 }
Steve French50c2f752007-07-13 00:33:32 +0000442 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 sizeof(struct smb_t2_rsp) + 16);
444 return rc;
445}
446int
447CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
448{
449 NEGOTIATE_REQ *pSMB;
450 NEGOTIATE_RSP *pSMBr;
451 int rc = 0;
452 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000453 int i;
Steve French50c2f752007-07-13 00:33:32 +0000454 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000456 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100457 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Steve French790fe572007-07-07 19:25:05 +0000459 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 server = ses->server;
461 else {
462 rc = -EIO;
463 return rc;
464 }
465 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
466 (void **) &pSMB, (void **) &pSMBr);
467 if (rc)
468 return rc;
Steve French750d1152006-06-27 06:28:30 +0000469
470 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000471 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000472 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000473 else /* if override flags set only sign/seal OR them with global auth */
474 secFlags = extended_security | ses->overrideSecFlg;
475
Steve French762e5ab2007-06-28 18:41:42 +0000476 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000477
Steve French1982c342005-08-17 12:38:22 -0700478 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000479 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000480
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000481 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000482 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000483 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
484 cFYI(1, ("Kerberos only mechanism, enable extended security"));
485 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
486 }
Steve French50c2f752007-07-13 00:33:32 +0000487
Steve French39798772006-05-31 22:40:51 +0000488 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000489 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000490 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
491 count += strlen(protocols[i].name) + 1;
492 /* null at end of source and target buffers anyway */
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 pSMB->hdr.smb_buf_length += count;
495 pSMB->ByteCount = cpu_to_le16(count);
496
497 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000499 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000500 goto neg_err_exit;
501
Al Viro733f99a2006-10-14 16:48:26 +0100502 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000503 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000504 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000505 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000506 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000507 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000508 could not negotiate a common dialect */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000511#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000512 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100513 && ((dialect == LANMAN_PROT)
514 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000515 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000516 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000517
Steve French790fe572007-07-07 19:25:05 +0000518 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000519 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000520 server->secType = LANMAN;
521 else {
522 cERROR(1, ("mount failed weak security disabled"
523 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000524 rc = -EOPNOTSUPP;
525 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000526 }
Steve French254e55e2006-06-04 05:53:15 +0000527 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
528 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
529 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000530 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve 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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-10-02 05:53:29 +0000567 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000568 } else {
Steve Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frencheda3c022005-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 Frencheda3c022005-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 Frencheda3c022005-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
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001629 *nbytes = 0;
1630
Steve French790fe572007-07-07 19:25:05 +00001631 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001632
Steve French4c3130e2008-12-09 00:28:16 +00001633 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001634 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001635 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001636 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001637 if ((offset >> 32) > 0) {
1638 /* can not handle big offset for old srv */
1639 return -EIO;
1640 }
1641 }
Steve French8cc64c62005-10-03 13:49:43 -07001642 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 if (rc)
1644 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 /* tcon and ses pointer are checked in smb_init */
1646 if (tcon->ses->server == NULL)
1647 return -ECONNABORTED;
1648
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001649 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 pSMB->Fid = netfid;
1651 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001652 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001653 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 pSMB->Reserved = 0xFFFFFFFF;
1655 pSMB->WriteMode = 0;
1656 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001657
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001659 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660
Steve French3e844692005-10-03 13:37:24 -07001661 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1662 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001663 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001664 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001665 pSMB->hdr.smb_buf_length += count+1;
1666 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001667 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1668 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001669 pSMB->ByteCount = cpu_to_le16(count + 1);
1670 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001671 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001672 (struct smb_com_writex_req *)pSMB;
1673 pSMBW->ByteCount = cpu_to_le16(count + 5);
1674 }
Steve French3e844692005-10-03 13:37:24 -07001675 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001676 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001677 iov[0].iov_len = smb_hdr_len + 4;
1678 else /* wct == 12 pad bigger by four bytes */
1679 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001680
Steve French3e844692005-10-03 13:37:24 -07001681
Steve Frenchec637e32005-12-12 20:53:18 -08001682 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001683 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001684 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001686 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001687 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001688 /* presumably this can not happen, but best to be safe */
1689 rc = -EIO;
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 Frenchb815f1e2006-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
Steve Frenchb298f222009-02-21 21:17:43 +00001937CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1938{
1939 int rc = 0;
1940 FLUSH_REQ *pSMB = NULL;
1941 cFYI(1, ("In CIFSSMBFlush"));
1942
1943 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1944 if (rc)
1945 return rc;
1946
1947 pSMB->FileID = (__u16) smb_file_id;
1948 pSMB->ByteCount = 0;
1949 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1950 cifs_stats_inc(&tcon->num_flushes);
1951 if (rc)
1952 cERROR(1, ("Send error in Flush = %d", rc));
1953
1954 return rc;
1955}
1956
1957int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1959 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001960 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961{
1962 int rc = 0;
1963 RENAME_REQ *pSMB = NULL;
1964 RENAME_RSP *pSMBr = NULL;
1965 int bytes_returned;
1966 int name_len, name_len2;
1967 __u16 count;
1968
1969 cFYI(1, ("In CIFSSMBRename"));
1970renameRetry:
1971 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1972 (void **) &pSMBr);
1973 if (rc)
1974 return rc;
1975
1976 pSMB->BufferFormat = 0x04;
1977 pSMB->SearchAttributes =
1978 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1979 ATTR_DIRECTORY);
1980
1981 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1982 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001983 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001984 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 name_len++; /* trailing null */
1986 name_len *= 2;
1987 pSMB->OldFileName[name_len] = 0x04; /* pad */
1988 /* protocol requires ASCII signature byte on Unicode string */
1989 pSMB->OldFileName[name_len + 1] = 0x00;
1990 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001991 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001992 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1994 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001995 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 name_len = strnlen(fromName, PATH_MAX);
1997 name_len++; /* trailing null */
1998 strncpy(pSMB->OldFileName, fromName, name_len);
1999 name_len2 = strnlen(toName, PATH_MAX);
2000 name_len2++; /* trailing null */
2001 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2002 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2003 name_len2++; /* trailing null */
2004 name_len2++; /* signature byte */
2005 }
2006
2007 count = 1 /* 1st signature byte */ + name_len + name_len2;
2008 pSMB->hdr.smb_buf_length += count;
2009 pSMB->ByteCount = cpu_to_le16(count);
2010
2011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002013 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002014 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017 cifs_buf_release(pSMB);
2018
2019 if (rc == -EAGAIN)
2020 goto renameRetry;
2021
2022 return rc;
2023}
2024
Steve French50c2f752007-07-13 00:33:32 +00002025int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002026 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002027 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028{
2029 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2030 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002031 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 char *data_offset;
2033 char dummy_string[30];
2034 int rc = 0;
2035 int bytes_returned = 0;
2036 int len_of_str;
2037 __u16 params, param_offset, offset, count, byte_count;
2038
2039 cFYI(1, ("Rename to File by handle"));
2040 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2041 (void **) &pSMBr);
2042 if (rc)
2043 return rc;
2044
2045 params = 6;
2046 pSMB->MaxSetupCount = 0;
2047 pSMB->Reserved = 0;
2048 pSMB->Flags = 0;
2049 pSMB->Timeout = 0;
2050 pSMB->Reserved2 = 0;
2051 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2052 offset = param_offset + params;
2053
2054 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2055 rename_info = (struct set_file_rename *) data_offset;
2056 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002057 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 pSMB->SetupCount = 1;
2059 pSMB->Reserved3 = 0;
2060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2061 byte_count = 3 /* pad */ + params;
2062 pSMB->ParameterCount = cpu_to_le16(params);
2063 pSMB->TotalParameterCount = pSMB->ParameterCount;
2064 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2065 pSMB->DataOffset = cpu_to_le16(offset);
2066 /* construct random name ".cifs_tmp<inodenum><mid>" */
2067 rename_info->overwrite = cpu_to_le32(1);
2068 rename_info->root_fid = 0;
2069 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002070 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002071 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2072 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002073 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002075 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002076 target_name, PATH_MAX, nls_codepage,
2077 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078 }
2079 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002080 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 byte_count += count;
2082 pSMB->DataCount = cpu_to_le16(count);
2083 pSMB->TotalDataCount = pSMB->DataCount;
2084 pSMB->Fid = netfid;
2085 pSMB->InformationLevel =
2086 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2087 pSMB->Reserved4 = 0;
2088 pSMB->hdr.smb_buf_length += byte_count;
2089 pSMB->ByteCount = cpu_to_le16(byte_count);
2090 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002092 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002093 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002094 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002095
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 cifs_buf_release(pSMB);
2097
2098 /* Note: On -EAGAIN error only caller can retry on handle based calls
2099 since file handle passed in no longer valid */
2100
2101 return rc;
2102}
2103
2104int
Steve French50c2f752007-07-13 00:33:32 +00002105CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2106 const __u16 target_tid, const char *toName, const int flags,
2107 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
2109 int rc = 0;
2110 COPY_REQ *pSMB = NULL;
2111 COPY_RSP *pSMBr = NULL;
2112 int bytes_returned;
2113 int name_len, name_len2;
2114 __u16 count;
2115
2116 cFYI(1, ("In CIFSSMBCopy"));
2117copyRetry:
2118 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2119 (void **) &pSMBr);
2120 if (rc)
2121 return rc;
2122
2123 pSMB->BufferFormat = 0x04;
2124 pSMB->Tid2 = target_tid;
2125
2126 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2127
2128 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002129 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002130 fromName, PATH_MAX, nls_codepage,
2131 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 name_len++; /* trailing null */
2133 name_len *= 2;
2134 pSMB->OldFileName[name_len] = 0x04; /* pad */
2135 /* protocol requires ASCII signature byte on Unicode string */
2136 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002137 name_len2 =
2138 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002139 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2141 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002142 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143 name_len = strnlen(fromName, PATH_MAX);
2144 name_len++; /* trailing null */
2145 strncpy(pSMB->OldFileName, fromName, name_len);
2146 name_len2 = strnlen(toName, PATH_MAX);
2147 name_len2++; /* trailing null */
2148 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2149 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2150 name_len2++; /* trailing null */
2151 name_len2++; /* signature byte */
2152 }
2153
2154 count = 1 /* 1st signature byte */ + name_len + name_len2;
2155 pSMB->hdr.smb_buf_length += count;
2156 pSMB->ByteCount = cpu_to_le16(count);
2157
2158 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2159 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2160 if (rc) {
2161 cFYI(1, ("Send error in copy = %d with %d files copied",
2162 rc, le16_to_cpu(pSMBr->CopyCount)));
2163 }
Steve French0d817bc2008-05-22 02:02:03 +00002164 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
2166 if (rc == -EAGAIN)
2167 goto copyRetry;
2168
2169 return rc;
2170}
2171
2172int
2173CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2174 const char *fromName, const char *toName,
2175 const struct nls_table *nls_codepage)
2176{
2177 TRANSACTION2_SPI_REQ *pSMB = NULL;
2178 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2179 char *data_offset;
2180 int name_len;
2181 int name_len_target;
2182 int rc = 0;
2183 int bytes_returned = 0;
2184 __u16 params, param_offset, offset, byte_count;
2185
2186 cFYI(1, ("In Symlink Unix style"));
2187createSymLinkRetry:
2188 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2189 (void **) &pSMBr);
2190 if (rc)
2191 return rc;
2192
2193 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2194 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002195 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 /* find define for this maxpathcomponent */
2197 , nls_codepage);
2198 name_len++; /* trailing null */
2199 name_len *= 2;
2200
Steve French50c2f752007-07-13 00:33:32 +00002201 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 name_len = strnlen(fromName, PATH_MAX);
2203 name_len++; /* trailing null */
2204 strncpy(pSMB->FileName, fromName, name_len);
2205 }
2206 params = 6 + name_len;
2207 pSMB->MaxSetupCount = 0;
2208 pSMB->Reserved = 0;
2209 pSMB->Flags = 0;
2210 pSMB->Timeout = 0;
2211 pSMB->Reserved2 = 0;
2212 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002213 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 offset = param_offset + params;
2215
2216 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2218 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002219 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 /* find define for this maxpathcomponent */
2221 , nls_codepage);
2222 name_len_target++; /* trailing null */
2223 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002224 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 name_len_target = strnlen(toName, PATH_MAX);
2226 name_len_target++; /* trailing null */
2227 strncpy(data_offset, toName, name_len_target);
2228 }
2229
2230 pSMB->MaxParameterCount = cpu_to_le16(2);
2231 /* BB find exact max on data count below from sess */
2232 pSMB->MaxDataCount = cpu_to_le16(1000);
2233 pSMB->SetupCount = 1;
2234 pSMB->Reserved3 = 0;
2235 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2236 byte_count = 3 /* pad */ + params + name_len_target;
2237 pSMB->DataCount = cpu_to_le16(name_len_target);
2238 pSMB->ParameterCount = cpu_to_le16(params);
2239 pSMB->TotalDataCount = pSMB->DataCount;
2240 pSMB->TotalParameterCount = pSMB->ParameterCount;
2241 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2242 pSMB->DataOffset = cpu_to_le16(offset);
2243 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2244 pSMB->Reserved4 = 0;
2245 pSMB->hdr.smb_buf_length += byte_count;
2246 pSMB->ByteCount = cpu_to_le16(byte_count);
2247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2248 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002249 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002250 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002251 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Steve French0d817bc2008-05-22 02:02:03 +00002253 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 if (rc == -EAGAIN)
2256 goto createSymLinkRetry;
2257
2258 return rc;
2259}
2260
2261int
2262CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2263 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002264 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265{
2266 TRANSACTION2_SPI_REQ *pSMB = NULL;
2267 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2268 char *data_offset;
2269 int name_len;
2270 int name_len_target;
2271 int rc = 0;
2272 int bytes_returned = 0;
2273 __u16 params, param_offset, offset, byte_count;
2274
2275 cFYI(1, ("In Create Hard link Unix style"));
2276createHardLinkRetry:
2277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2278 (void **) &pSMBr);
2279 if (rc)
2280 return rc;
2281
2282 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002283 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002284 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 name_len++; /* trailing null */
2286 name_len *= 2;
2287
Steve French50c2f752007-07-13 00:33:32 +00002288 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 name_len = strnlen(toName, PATH_MAX);
2290 name_len++; /* trailing null */
2291 strncpy(pSMB->FileName, toName, name_len);
2292 }
2293 params = 6 + name_len;
2294 pSMB->MaxSetupCount = 0;
2295 pSMB->Reserved = 0;
2296 pSMB->Flags = 0;
2297 pSMB->Timeout = 0;
2298 pSMB->Reserved2 = 0;
2299 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002300 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 offset = param_offset + params;
2302
2303 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2305 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002306 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002307 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 name_len_target++; /* trailing null */
2309 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002310 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 name_len_target = strnlen(fromName, PATH_MAX);
2312 name_len_target++; /* trailing null */
2313 strncpy(data_offset, fromName, name_len_target);
2314 }
2315
2316 pSMB->MaxParameterCount = cpu_to_le16(2);
2317 /* BB find exact max on data count below from sess*/
2318 pSMB->MaxDataCount = cpu_to_le16(1000);
2319 pSMB->SetupCount = 1;
2320 pSMB->Reserved3 = 0;
2321 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2322 byte_count = 3 /* pad */ + params + name_len_target;
2323 pSMB->ParameterCount = cpu_to_le16(params);
2324 pSMB->TotalParameterCount = pSMB->ParameterCount;
2325 pSMB->DataCount = cpu_to_le16(name_len_target);
2326 pSMB->TotalDataCount = pSMB->DataCount;
2327 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2328 pSMB->DataOffset = cpu_to_le16(offset);
2329 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2330 pSMB->Reserved4 = 0;
2331 pSMB->hdr.smb_buf_length += byte_count;
2332 pSMB->ByteCount = cpu_to_le16(byte_count);
2333 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2334 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002335 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002336 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
2339 cifs_buf_release(pSMB);
2340 if (rc == -EAGAIN)
2341 goto createHardLinkRetry;
2342
2343 return rc;
2344}
2345
2346int
2347CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2348 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002349 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350{
2351 int rc = 0;
2352 NT_RENAME_REQ *pSMB = NULL;
2353 RENAME_RSP *pSMBr = NULL;
2354 int bytes_returned;
2355 int name_len, name_len2;
2356 __u16 count;
2357
2358 cFYI(1, ("In CIFSCreateHardLink"));
2359winCreateHardLinkRetry:
2360
2361 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2362 (void **) &pSMBr);
2363 if (rc)
2364 return rc;
2365
2366 pSMB->SearchAttributes =
2367 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2368 ATTR_DIRECTORY);
2369 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2370 pSMB->ClusterCount = 0;
2371
2372 pSMB->BufferFormat = 0x04;
2373
2374 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2375 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002376 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002377 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 name_len++; /* trailing null */
2379 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002380
2381 /* protocol specifies ASCII buffer format (0x04) for unicode */
2382 pSMB->OldFileName[name_len] = 0x04;
2383 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002385 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002386 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2388 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002389 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 name_len = strnlen(fromName, PATH_MAX);
2391 name_len++; /* trailing null */
2392 strncpy(pSMB->OldFileName, fromName, name_len);
2393 name_len2 = strnlen(toName, PATH_MAX);
2394 name_len2++; /* trailing null */
2395 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2396 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2397 name_len2++; /* trailing null */
2398 name_len2++; /* signature byte */
2399 }
2400
2401 count = 1 /* string type byte */ + name_len + name_len2;
2402 pSMB->hdr.smb_buf_length += count;
2403 pSMB->ByteCount = cpu_to_le16(count);
2404
2405 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2406 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002407 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002408 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002410
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 cifs_buf_release(pSMB);
2412 if (rc == -EAGAIN)
2413 goto winCreateHardLinkRetry;
2414
2415 return rc;
2416}
2417
2418int
2419CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2420 const unsigned char *searchName,
2421 char *symlinkinfo, const int buflen,
2422 const struct nls_table *nls_codepage)
2423{
2424/* SMB_QUERY_FILE_UNIX_LINK */
2425 TRANSACTION2_QPI_REQ *pSMB = NULL;
2426 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2427 int rc = 0;
2428 int bytes_returned;
2429 int name_len;
2430 __u16 params, byte_count;
2431
2432 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2433
2434querySymLinkRetry:
2435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2436 (void **) &pSMBr);
2437 if (rc)
2438 return rc;
2439
2440 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2441 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002442 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2443 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 name_len++; /* trailing null */
2445 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002446 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 name_len = strnlen(searchName, PATH_MAX);
2448 name_len++; /* trailing null */
2449 strncpy(pSMB->FileName, searchName, name_len);
2450 }
2451
2452 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2453 pSMB->TotalDataCount = 0;
2454 pSMB->MaxParameterCount = cpu_to_le16(2);
2455 /* BB find exact max data count below from sess structure BB */
2456 pSMB->MaxDataCount = cpu_to_le16(4000);
2457 pSMB->MaxSetupCount = 0;
2458 pSMB->Reserved = 0;
2459 pSMB->Flags = 0;
2460 pSMB->Timeout = 0;
2461 pSMB->Reserved2 = 0;
2462 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002463 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 pSMB->DataCount = 0;
2465 pSMB->DataOffset = 0;
2466 pSMB->SetupCount = 1;
2467 pSMB->Reserved3 = 0;
2468 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2469 byte_count = params + 1 /* pad */ ;
2470 pSMB->TotalParameterCount = cpu_to_le16(params);
2471 pSMB->ParameterCount = pSMB->TotalParameterCount;
2472 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2473 pSMB->Reserved4 = 0;
2474 pSMB->hdr.smb_buf_length += byte_count;
2475 pSMB->ByteCount = cpu_to_le16(byte_count);
2476
2477 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2479 if (rc) {
2480 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2481 } else {
2482 /* decode response */
2483
2484 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2485 if (rc || (pSMBr->ByteCount < 2))
2486 /* BB also check enough total bytes returned */
2487 rc = -EIO; /* bad smb */
2488 else {
2489 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2490 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2491
2492 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2493 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002494 &pSMBr->hdr.Protocol + data_offset),
2495 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002496 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002498 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2499 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 name_len, nls_codepage);
2501 } else {
2502 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002503 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 data_offset,
2505 min_t(const int, buflen, count));
2506 }
2507 symlinkinfo[buflen] = 0;
2508 /* just in case so calling code does not go off the end of buffer */
2509 }
2510 }
2511 cifs_buf_release(pSMB);
2512 if (rc == -EAGAIN)
2513 goto querySymLinkRetry;
2514 return rc;
2515}
2516
Parag Warudkarc9489772007-10-23 18:09:48 +00002517#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002518/* Initialize NT TRANSACT SMB into small smb request buffer.
2519 This assumes that all NT TRANSACTS that we init here have
2520 total parm and data under about 400 bytes (to fit in small cifs
2521 buffer size), which is the case so far, it easily fits. NB:
2522 Setup words themselves and ByteCount
2523 MaxSetupCount (size of returned setup area) and
2524 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002525static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002526smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002527 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002528 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002529{
2530 int rc;
2531 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002532 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002533
2534 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2535 (void **)&pSMB);
2536 if (rc)
2537 return rc;
2538 *ret_buf = (void *)pSMB;
2539 pSMB->Reserved = 0;
2540 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2541 pSMB->TotalDataCount = 0;
2542 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2543 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2544 pSMB->ParameterCount = pSMB->TotalParameterCount;
2545 pSMB->DataCount = pSMB->TotalDataCount;
2546 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2547 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2548 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2549 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2550 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2551 pSMB->SubCommand = cpu_to_le16(sub_command);
2552 return 0;
2553}
2554
2555static int
Steve French50c2f752007-07-13 00:33:32 +00002556validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002557 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002558{
Steve French50c2f752007-07-13 00:33:32 +00002559 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002560 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002561 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002562
Steve French630f3f02007-10-25 21:17:17 +00002563 *pdatalen = 0;
2564 *pparmlen = 0;
2565
Steve French790fe572007-07-07 19:25:05 +00002566 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002567 return -EINVAL;
2568
2569 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2570
2571 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002572 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002573 (char *)&pSMBr->ByteCount;
2574
Steve French0a4b92c2006-01-12 15:44:21 -08002575 data_offset = le32_to_cpu(pSMBr->DataOffset);
2576 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002577 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002578 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2579
2580 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2581 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2582
2583 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002584 if (*ppparm > end_of_smb) {
2585 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002586 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002587 } else if (parm_count + *ppparm > end_of_smb) {
2588 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002589 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002590 } else if (*ppdata > end_of_smb) {
2591 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002592 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002593 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002594 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002595 *ppdata, data_count, (data_count + *ppdata),
2596 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002597 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002598 } else if (parm_count + data_count > pSMBr->ByteCount) {
2599 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002600 return -EINVAL;
2601 }
Steve French630f3f02007-10-25 21:17:17 +00002602 *pdatalen = data_count;
2603 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002604 return 0;
2605}
Parag Warudkarc9489772007-10-23 18:09:48 +00002606#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002607
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608int
2609CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2610 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002611 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 const struct nls_table *nls_codepage)
2613{
2614 int rc = 0;
2615 int bytes_returned;
2616 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002617 struct smb_com_transaction_ioctl_req *pSMB;
2618 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
2620 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2621 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2622 (void **) &pSMBr);
2623 if (rc)
2624 return rc;
2625
2626 pSMB->TotalParameterCount = 0 ;
2627 pSMB->TotalDataCount = 0;
2628 pSMB->MaxParameterCount = cpu_to_le32(2);
2629 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002630 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2631 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 pSMB->MaxSetupCount = 4;
2633 pSMB->Reserved = 0;
2634 pSMB->ParameterOffset = 0;
2635 pSMB->DataCount = 0;
2636 pSMB->DataOffset = 0;
2637 pSMB->SetupCount = 4;
2638 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2639 pSMB->ParameterCount = pSMB->TotalParameterCount;
2640 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2641 pSMB->IsFsctl = 1; /* FSCTL */
2642 pSMB->IsRootFlag = 0;
2643 pSMB->Fid = fid; /* file handle always le */
2644 pSMB->ByteCount = 0;
2645
2646 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2647 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2648 if (rc) {
2649 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2650 } else { /* decode response */
2651 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2652 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2653 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2654 /* BB also check enough total bytes returned */
2655 rc = -EIO; /* bad smb */
2656 else {
Steve French790fe572007-07-07 19:25:05 +00002657 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002658 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002659 pSMBr->ByteCount +
2660 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Steve French50c2f752007-07-13 00:33:32 +00002662 struct reparse_data *reparse_buf =
2663 (struct reparse_data *)
2664 ((char *)&pSMBr->hdr.Protocol
2665 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002666 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 rc = -EIO;
2668 goto qreparse_out;
2669 }
Steve French790fe572007-07-07 19:25:05 +00002670 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 reparse_buf->TargetNameOffset +
2672 reparse_buf->TargetNameLen) >
2673 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002674 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 rc = -EIO;
2676 goto qreparse_out;
2677 }
Steve French50c2f752007-07-13 00:33:32 +00002678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2680 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002681 (reparse_buf->LinkNamesBuf +
2682 reparse_buf->TargetNameOffset),
2683 min(buflen/2,
2684 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002686 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 reparse_buf->TargetNameOffset),
2688 name_len, nls_codepage);
2689 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002690 strncpy(symlinkinfo,
2691 reparse_buf->LinkNamesBuf +
2692 reparse_buf->TargetNameOffset,
2693 min_t(const int, buflen,
2694 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 }
2696 } else {
2697 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002698 cFYI(1, ("Invalid return data count on "
2699 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 }
2701 symlinkinfo[buflen] = 0; /* just in case so the caller
2702 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002703 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 }
2705 }
2706qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002707 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709 /* Note: On -EAGAIN error only caller can retry on handle based calls
2710 since file handle passed in no longer valid */
2711
2712 return rc;
2713}
2714
2715#ifdef CONFIG_CIFS_POSIX
2716
2717/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002718static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2719 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720{
2721 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002722 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2723 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2724 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2726
2727 return;
2728}
2729
2730/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002731static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2732 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733{
2734 int size = 0;
2735 int i;
2736 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002737 struct cifs_posix_ace *pACE;
2738 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2739 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
2741 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2742 return -EOPNOTSUPP;
2743
Steve French790fe572007-07-07 19:25:05 +00002744 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 count = le16_to_cpu(cifs_acl->access_entry_count);
2746 pACE = &cifs_acl->ace_array[0];
2747 size = sizeof(struct cifs_posix_acl);
2748 size += sizeof(struct cifs_posix_ace) * count;
2749 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002750 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002751 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2752 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 return -EINVAL;
2754 }
Steve French790fe572007-07-07 19:25:05 +00002755 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 count = le16_to_cpu(cifs_acl->access_entry_count);
2757 size = sizeof(struct cifs_posix_acl);
2758 size += sizeof(struct cifs_posix_ace) * count;
2759/* skip past access ACEs to get to default ACEs */
2760 pACE = &cifs_acl->ace_array[count];
2761 count = le16_to_cpu(cifs_acl->default_entry_count);
2762 size += sizeof(struct cifs_posix_ace) * count;
2763 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002764 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 return -EINVAL;
2766 } else {
2767 /* illegal type */
2768 return -EINVAL;
2769 }
2770
2771 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002772 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002773 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002774 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 return -ERANGE;
2776 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002777 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002778 for (i = 0; i < count ; i++) {
2779 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2780 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 }
2782 }
2783 return size;
2784}
2785
Steve French50c2f752007-07-13 00:33:32 +00002786static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2787 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788{
2789 __u16 rc = 0; /* 0 = ACL converted ok */
2790
Steve Frenchff7feac2005-11-15 16:45:16 -08002791 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2792 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002794 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 /* Probably no need to le convert -1 on any arch but can not hurt */
2796 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002797 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002798 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002799 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 return rc;
2801}
2802
2803/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002804static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2805 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806{
2807 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002808 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2809 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 int count;
2811 int i;
2812
Steve French790fe572007-07-07 19:25:05 +00002813 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 return 0;
2815
2816 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002817 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002818 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002819 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002820 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002821 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002822 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 return 0;
2824 }
2825 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002826 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002827 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002828 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002829 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 else {
Steve French50c2f752007-07-13 00:33:32 +00002831 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 return 0;
2833 }
Steve French50c2f752007-07-13 00:33:32 +00002834 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2836 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002837 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 /* ACE not converted */
2839 break;
2840 }
2841 }
Steve French790fe572007-07-07 19:25:05 +00002842 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2844 rc += sizeof(struct cifs_posix_acl);
2845 /* BB add check to make sure ACL does not overflow SMB */
2846 }
2847 return rc;
2848}
2849
2850int
2851CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002852 const unsigned char *searchName,
2853 char *acl_inf, const int buflen, const int acl_type,
2854 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855{
2856/* SMB_QUERY_POSIX_ACL */
2857 TRANSACTION2_QPI_REQ *pSMB = NULL;
2858 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2859 int rc = 0;
2860 int bytes_returned;
2861 int name_len;
2862 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002863
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2865
2866queryAclRetry:
2867 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2868 (void **) &pSMBr);
2869 if (rc)
2870 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002871
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2873 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002874 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002875 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 name_len++; /* trailing null */
2877 name_len *= 2;
2878 pSMB->FileName[name_len] = 0;
2879 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002880 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 name_len = strnlen(searchName, PATH_MAX);
2882 name_len++; /* trailing null */
2883 strncpy(pSMB->FileName, searchName, name_len);
2884 }
2885
2886 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2887 pSMB->TotalDataCount = 0;
2888 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002889 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 pSMB->MaxDataCount = cpu_to_le16(4000);
2891 pSMB->MaxSetupCount = 0;
2892 pSMB->Reserved = 0;
2893 pSMB->Flags = 0;
2894 pSMB->Timeout = 0;
2895 pSMB->Reserved2 = 0;
2896 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002897 offsetof(struct smb_com_transaction2_qpi_req,
2898 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 pSMB->DataCount = 0;
2900 pSMB->DataOffset = 0;
2901 pSMB->SetupCount = 1;
2902 pSMB->Reserved3 = 0;
2903 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2904 byte_count = params + 1 /* pad */ ;
2905 pSMB->TotalParameterCount = cpu_to_le16(params);
2906 pSMB->ParameterCount = pSMB->TotalParameterCount;
2907 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2908 pSMB->Reserved4 = 0;
2909 pSMB->hdr.smb_buf_length += byte_count;
2910 pSMB->ByteCount = cpu_to_le16(byte_count);
2911
2912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002914 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 if (rc) {
2916 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2917 } else {
2918 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002919
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2921 if (rc || (pSMBr->ByteCount < 2))
2922 /* BB also check enough total bytes returned */
2923 rc = -EIO; /* bad smb */
2924 else {
2925 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2926 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2927 rc = cifs_copy_posix_acl(acl_inf,
2928 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002929 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 }
2931 }
2932 cifs_buf_release(pSMB);
2933 if (rc == -EAGAIN)
2934 goto queryAclRetry;
2935 return rc;
2936}
2937
2938int
2939CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002940 const unsigned char *fileName,
2941 const char *local_acl, const int buflen,
2942 const int acl_type,
2943 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944{
2945 struct smb_com_transaction2_spi_req *pSMB = NULL;
2946 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2947 char *parm_data;
2948 int name_len;
2949 int rc = 0;
2950 int bytes_returned = 0;
2951 __u16 params, byte_count, data_count, param_offset, offset;
2952
2953 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2954setAclRetry:
2955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002956 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 if (rc)
2958 return rc;
2959 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2960 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002961 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 name_len++; /* trailing null */
2964 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002965 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 name_len = strnlen(fileName, PATH_MAX);
2967 name_len++; /* trailing null */
2968 strncpy(pSMB->FileName, fileName, name_len);
2969 }
2970 params = 6 + name_len;
2971 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002972 /* BB find max SMB size from sess */
2973 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 pSMB->MaxSetupCount = 0;
2975 pSMB->Reserved = 0;
2976 pSMB->Flags = 0;
2977 pSMB->Timeout = 0;
2978 pSMB->Reserved2 = 0;
2979 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002980 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 offset = param_offset + params;
2982 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2983 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2984
2985 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002986 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987
Steve French790fe572007-07-07 19:25:05 +00002988 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 rc = -EOPNOTSUPP;
2990 goto setACLerrorExit;
2991 }
2992 pSMB->DataOffset = cpu_to_le16(offset);
2993 pSMB->SetupCount = 1;
2994 pSMB->Reserved3 = 0;
2995 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2996 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2997 byte_count = 3 /* pad */ + params + data_count;
2998 pSMB->DataCount = cpu_to_le16(data_count);
2999 pSMB->TotalDataCount = pSMB->DataCount;
3000 pSMB->ParameterCount = cpu_to_le16(params);
3001 pSMB->TotalParameterCount = pSMB->ParameterCount;
3002 pSMB->Reserved4 = 0;
3003 pSMB->hdr.smb_buf_length += byte_count;
3004 pSMB->ByteCount = cpu_to_le16(byte_count);
3005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003007 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009
3010setACLerrorExit:
3011 cifs_buf_release(pSMB);
3012 if (rc == -EAGAIN)
3013 goto setAclRetry;
3014 return rc;
3015}
3016
Steve Frenchf654bac2005-04-28 22:41:04 -07003017/* BB fix tabs in this function FIXME BB */
3018int
3019CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003020 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003021{
Steve French50c2f752007-07-13 00:33:32 +00003022 int rc = 0;
3023 struct smb_t2_qfi_req *pSMB = NULL;
3024 struct smb_t2_qfi_rsp *pSMBr = NULL;
3025 int bytes_returned;
3026 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003027
Steve French790fe572007-07-07 19:25:05 +00003028 cFYI(1, ("In GetExtAttr"));
3029 if (tcon == NULL)
3030 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003031
3032GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003033 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3034 (void **) &pSMBr);
3035 if (rc)
3036 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003037
Steve Frenchad7a2922008-02-07 23:25:02 +00003038 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003039 pSMB->t2.TotalDataCount = 0;
3040 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3041 /* BB find exact max data count below from sess structure BB */
3042 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3043 pSMB->t2.MaxSetupCount = 0;
3044 pSMB->t2.Reserved = 0;
3045 pSMB->t2.Flags = 0;
3046 pSMB->t2.Timeout = 0;
3047 pSMB->t2.Reserved2 = 0;
3048 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3049 Fid) - 4);
3050 pSMB->t2.DataCount = 0;
3051 pSMB->t2.DataOffset = 0;
3052 pSMB->t2.SetupCount = 1;
3053 pSMB->t2.Reserved3 = 0;
3054 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3055 byte_count = params + 1 /* pad */ ;
3056 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3057 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3058 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3059 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003060 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003061 pSMB->hdr.smb_buf_length += byte_count;
3062 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003063
Steve French790fe572007-07-07 19:25:05 +00003064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3066 if (rc) {
3067 cFYI(1, ("error %d in GetExtAttr", rc));
3068 } else {
3069 /* decode response */
3070 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3071 if (rc || (pSMBr->ByteCount < 2))
3072 /* BB also check enough total bytes returned */
3073 /* If rc should we check for EOPNOSUPP and
3074 disable the srvino flag? or in caller? */
3075 rc = -EIO; /* bad smb */
3076 else {
3077 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3078 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3079 struct file_chattr_info *pfinfo;
3080 /* BB Do we need a cast or hash here ? */
3081 if (count != 16) {
3082 cFYI(1, ("Illegal size ret in GetExtAttr"));
3083 rc = -EIO;
3084 goto GetExtAttrOut;
3085 }
3086 pfinfo = (struct file_chattr_info *)
3087 (data_offset + (char *) &pSMBr->hdr.Protocol);
3088 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003089 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003090 }
3091 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003092GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003093 cifs_buf_release(pSMB);
3094 if (rc == -EAGAIN)
3095 goto GetExtAttrRetry;
3096 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003097}
3098
Steve Frenchf654bac2005-04-28 22:41:04 -07003099#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100
Steve French297647c2007-10-12 04:11:59 +00003101#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003102/* Get Security Descriptor (by handle) from remote server for a file or dir */
3103int
3104CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003105 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003106{
3107 int rc = 0;
3108 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003109 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003110 struct kvec iov[1];
3111
3112 cFYI(1, ("GetCifsACL"));
3113
Steve French630f3f02007-10-25 21:17:17 +00003114 *pbuflen = 0;
3115 *acl_inf = NULL;
3116
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003117 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003118 8 /* parm len */, tcon, (void **) &pSMB);
3119 if (rc)
3120 return rc;
3121
3122 pSMB->MaxParameterCount = cpu_to_le32(4);
3123 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3124 pSMB->MaxSetupCount = 0;
3125 pSMB->Fid = fid; /* file handle always le */
3126 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3127 CIFS_ACL_DACL);
3128 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3129 pSMB->hdr.smb_buf_length += 11;
3130 iov[0].iov_base = (char *)pSMB;
3131 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3132
Steve Frencha761ac52007-10-18 21:45:27 +00003133 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003134 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003135 cifs_stats_inc(&tcon->num_acl_get);
3136 if (rc) {
3137 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3138 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003139 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003140 __u32 parm_len;
3141 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003142 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003143 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003144
3145/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003146 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003147 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003148 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003149 goto qsec_out;
3150 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3151
Steve French630f3f02007-10-25 21:17:17 +00003152 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003153
3154 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3155 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003156 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003157 goto qsec_out;
3158 }
3159
3160/* BB check that data area is minimum length and as big as acl_len */
3161
Steve Frenchaf6f4612007-10-16 18:40:37 +00003162 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003163 if (acl_len != *pbuflen) {
3164 cERROR(1, ("acl length %d does not match %d",
3165 acl_len, *pbuflen));
3166 if (*pbuflen > acl_len)
3167 *pbuflen = acl_len;
3168 }
Steve French0a4b92c2006-01-12 15:44:21 -08003169
Steve French630f3f02007-10-25 21:17:17 +00003170 /* check if buffer is big enough for the acl
3171 header followed by the smallest SID */
3172 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3173 (*pbuflen >= 64 * 1024)) {
3174 cERROR(1, ("bad acl length %d", *pbuflen));
3175 rc = -EINVAL;
3176 *pbuflen = 0;
3177 } else {
3178 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3179 if (*acl_inf == NULL) {
3180 *pbuflen = 0;
3181 rc = -ENOMEM;
3182 }
3183 memcpy(*acl_inf, pdata, *pbuflen);
3184 }
Steve French0a4b92c2006-01-12 15:44:21 -08003185 }
3186qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003187 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003188 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003189 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003190 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003191/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003192 return rc;
3193}
Steve French97837582007-12-31 07:47:21 +00003194
3195int
3196CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3197 struct cifs_ntsd *pntsd, __u32 acllen)
3198{
3199 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3200 int rc = 0;
3201 int bytes_returned = 0;
3202 SET_SEC_DESC_REQ *pSMB = NULL;
3203 NTRANSACT_RSP *pSMBr = NULL;
3204
3205setCifsAclRetry:
3206 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3207 (void **) &pSMBr);
3208 if (rc)
3209 return (rc);
3210
3211 pSMB->MaxSetupCount = 0;
3212 pSMB->Reserved = 0;
3213
3214 param_count = 8;
3215 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3216 data_count = acllen;
3217 data_offset = param_offset + param_count;
3218 byte_count = 3 /* pad */ + param_count;
3219
3220 pSMB->DataCount = cpu_to_le32(data_count);
3221 pSMB->TotalDataCount = pSMB->DataCount;
3222 pSMB->MaxParameterCount = cpu_to_le32(4);
3223 pSMB->MaxDataCount = cpu_to_le32(16384);
3224 pSMB->ParameterCount = cpu_to_le32(param_count);
3225 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3226 pSMB->TotalParameterCount = pSMB->ParameterCount;
3227 pSMB->DataOffset = cpu_to_le32(data_offset);
3228 pSMB->SetupCount = 0;
3229 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3230 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3231
3232 pSMB->Fid = fid; /* file handle always le */
3233 pSMB->Reserved2 = 0;
3234 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3235
3236 if (pntsd && acllen) {
3237 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3238 (char *) pntsd,
3239 acllen);
3240 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3241
3242 } else
3243 pSMB->hdr.smb_buf_length += byte_count;
3244
3245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3246 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3247
3248 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3249 if (rc)
3250 cFYI(1, ("Set CIFS ACL returned %d", rc));
3251 cifs_buf_release(pSMB);
3252
3253 if (rc == -EAGAIN)
3254 goto setCifsAclRetry;
3255
3256 return (rc);
3257}
3258
Steve French297647c2007-10-12 04:11:59 +00003259#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003260
Steve French6b8edfe2005-08-23 20:26:03 -07003261/* Legacy Query Path Information call for lookup to old servers such
3262 as Win9x/WinME */
3263int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003264 const unsigned char *searchName,
3265 FILE_ALL_INFO *pFinfo,
3266 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003267{
Steve Frenchad7a2922008-02-07 23:25:02 +00003268 QUERY_INFORMATION_REQ *pSMB;
3269 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003270 int rc = 0;
3271 int bytes_returned;
3272 int name_len;
3273
Steve French50c2f752007-07-13 00:33:32 +00003274 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003275QInfRetry:
3276 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003277 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003278 if (rc)
3279 return rc;
3280
3281 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3282 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003283 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3284 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003285 name_len++; /* trailing null */
3286 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003287 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003288 name_len = strnlen(searchName, PATH_MAX);
3289 name_len++; /* trailing null */
3290 strncpy(pSMB->FileName, searchName, name_len);
3291 }
3292 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003293 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003294 pSMB->hdr.smb_buf_length += (__u16) name_len;
3295 pSMB->ByteCount = cpu_to_le16(name_len);
3296
3297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003299 if (rc) {
3300 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003301 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003302 struct timespec ts;
3303 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003304
3305 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003306 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003307 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003308 ts.tv_nsec = 0;
3309 ts.tv_sec = time;
3310 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003311 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003312 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3313 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003314 pFinfo->AllocationSize =
3315 cpu_to_le64(le32_to_cpu(pSMBr->size));
3316 pFinfo->EndOfFile = pFinfo->AllocationSize;
3317 pFinfo->Attributes =
3318 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003319 } else
3320 rc = -EIO; /* bad buffer passed in */
3321
3322 cifs_buf_release(pSMB);
3323
3324 if (rc == -EAGAIN)
3325 goto QInfRetry;
3326
3327 return rc;
3328}
3329
3330
3331
3332
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333int
3334CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3335 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003336 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003337 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003338 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339{
3340/* level 263 SMB_QUERY_FILE_ALL_INFO */
3341 TRANSACTION2_QPI_REQ *pSMB = NULL;
3342 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3343 int rc = 0;
3344 int bytes_returned;
3345 int name_len;
3346 __u16 params, byte_count;
3347
3348/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3349QPathInfoRetry:
3350 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3351 (void **) &pSMBr);
3352 if (rc)
3353 return rc;
3354
3355 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3356 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003357 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003358 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 name_len++; /* trailing null */
3360 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003361 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 name_len = strnlen(searchName, PATH_MAX);
3363 name_len++; /* trailing null */
3364 strncpy(pSMB->FileName, searchName, name_len);
3365 }
3366
Steve French50c2f752007-07-13 00:33:32 +00003367 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 pSMB->TotalDataCount = 0;
3369 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003370 /* BB find exact max SMB PDU from sess structure BB */
3371 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 pSMB->MaxSetupCount = 0;
3373 pSMB->Reserved = 0;
3374 pSMB->Flags = 0;
3375 pSMB->Timeout = 0;
3376 pSMB->Reserved2 = 0;
3377 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003378 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 pSMB->DataCount = 0;
3380 pSMB->DataOffset = 0;
3381 pSMB->SetupCount = 1;
3382 pSMB->Reserved3 = 0;
3383 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3384 byte_count = params + 1 /* pad */ ;
3385 pSMB->TotalParameterCount = cpu_to_le16(params);
3386 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003387 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003388 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3389 else
3390 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 pSMB->Reserved4 = 0;
3392 pSMB->hdr.smb_buf_length += byte_count;
3393 pSMB->ByteCount = cpu_to_le16(byte_count);
3394
3395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3396 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3397 if (rc) {
3398 cFYI(1, ("Send error in QPathInfo = %d", rc));
3399 } else { /* decode response */
3400 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3401
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003402 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3403 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003404 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003406 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003407 rc = -EIO; /* 24 or 26 expected but we do not read
3408 last field */
3409 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003410 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003412
3413 /* On legacy responses we do not read the last field,
3414 EAsize, fortunately since it varies by subdialect and
3415 also note it differs on Set vs. Get, ie two bytes or 4
3416 bytes depending but we don't care here */
3417 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003418 size = sizeof(FILE_INFO_STANDARD);
3419 else
3420 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 memcpy((char *) pFindData,
3422 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003423 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 } else
3425 rc = -ENOMEM;
3426 }
3427 cifs_buf_release(pSMB);
3428 if (rc == -EAGAIN)
3429 goto QPathInfoRetry;
3430
3431 return rc;
3432}
3433
3434int
3435CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3436 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003437 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003438 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439{
3440/* SMB_QUERY_FILE_UNIX_BASIC */
3441 TRANSACTION2_QPI_REQ *pSMB = NULL;
3442 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3443 int rc = 0;
3444 int bytes_returned = 0;
3445 int name_len;
3446 __u16 params, byte_count;
3447
3448 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3449UnixQPathInfoRetry:
3450 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3451 (void **) &pSMBr);
3452 if (rc)
3453 return rc;
3454
3455 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3456 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003457 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003458 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 name_len++; /* trailing null */
3460 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003461 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 name_len = strnlen(searchName, PATH_MAX);
3463 name_len++; /* trailing null */
3464 strncpy(pSMB->FileName, searchName, name_len);
3465 }
3466
Steve French50c2f752007-07-13 00:33:32 +00003467 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 pSMB->TotalDataCount = 0;
3469 pSMB->MaxParameterCount = cpu_to_le16(2);
3470 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003471 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 pSMB->MaxSetupCount = 0;
3473 pSMB->Reserved = 0;
3474 pSMB->Flags = 0;
3475 pSMB->Timeout = 0;
3476 pSMB->Reserved2 = 0;
3477 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003478 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 pSMB->DataCount = 0;
3480 pSMB->DataOffset = 0;
3481 pSMB->SetupCount = 1;
3482 pSMB->Reserved3 = 0;
3483 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3484 byte_count = params + 1 /* pad */ ;
3485 pSMB->TotalParameterCount = cpu_to_le16(params);
3486 pSMB->ParameterCount = pSMB->TotalParameterCount;
3487 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3488 pSMB->Reserved4 = 0;
3489 pSMB->hdr.smb_buf_length += byte_count;
3490 pSMB->ByteCount = cpu_to_le16(byte_count);
3491
3492 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3493 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3494 if (rc) {
3495 cFYI(1, ("Send error in QPathInfo = %d", rc));
3496 } else { /* decode response */
3497 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3498
3499 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003500 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3501 "Unix Extensions can be disabled on mount "
3502 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 rc = -EIO; /* bad smb */
3504 } else {
3505 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3506 memcpy((char *) pFindData,
3507 (char *) &pSMBr->hdr.Protocol +
3508 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003509 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 }
3511 }
3512 cifs_buf_release(pSMB);
3513 if (rc == -EAGAIN)
3514 goto UnixQPathInfoRetry;
3515
3516 return rc;
3517}
3518
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519/* xid, tcon, searchName and codepage are input parms, rest are returned */
3520int
3521CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003522 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003524 __u16 *pnetfid,
3525 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526{
3527/* level 257 SMB_ */
3528 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3529 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003530 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 int rc = 0;
3532 int bytes_returned = 0;
3533 int name_len;
3534 __u16 params, byte_count;
3535
Steve French50c2f752007-07-13 00:33:32 +00003536 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
3538findFirstRetry:
3539 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3540 (void **) &pSMBr);
3541 if (rc)
3542 return rc;
3543
3544 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3545 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003546 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003547 PATH_MAX, nls_codepage, remap);
3548 /* We can not add the asterik earlier in case
3549 it got remapped to 0xF03A as if it were part of the
3550 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003552 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003553 pSMB->FileName[name_len+1] = 0;
3554 pSMB->FileName[name_len+2] = '*';
3555 pSMB->FileName[name_len+3] = 0;
3556 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003557 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3558 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003559 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 } else { /* BB add check for overrun of SMB buf BB */
3561 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003563 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 free buffer exit; BB */
3565 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003566 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003567 pSMB->FileName[name_len+1] = '*';
3568 pSMB->FileName[name_len+2] = 0;
3569 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 }
3571
3572 params = 12 + name_len /* includes null */ ;
3573 pSMB->TotalDataCount = 0; /* no EAs */
3574 pSMB->MaxParameterCount = cpu_to_le16(10);
3575 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3576 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3577 pSMB->MaxSetupCount = 0;
3578 pSMB->Reserved = 0;
3579 pSMB->Flags = 0;
3580 pSMB->Timeout = 0;
3581 pSMB->Reserved2 = 0;
3582 byte_count = params + 1 /* pad */ ;
3583 pSMB->TotalParameterCount = cpu_to_le16(params);
3584 pSMB->ParameterCount = pSMB->TotalParameterCount;
3585 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003586 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3587 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 pSMB->DataCount = 0;
3589 pSMB->DataOffset = 0;
3590 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3591 pSMB->Reserved3 = 0;
3592 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3593 pSMB->SearchAttributes =
3594 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3595 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003596 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3597 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 CIFS_SEARCH_RETURN_RESUME);
3599 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3600
3601 /* BB what should we set StorageType to? Does it matter? BB */
3602 pSMB->SearchStorageType = 0;
3603 pSMB->hdr.smb_buf_length += byte_count;
3604 pSMB->ByteCount = cpu_to_le16(byte_count);
3605
3606 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3607 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003608 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609
Steve French88274812006-03-09 22:21:45 +00003610 if (rc) {/* BB add logic to retry regular search if Unix search
3611 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 /* BB Add code to handle unsupported level rc */
3613 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003614
Steve French88274812006-03-09 22:21:45 +00003615 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616
3617 /* BB eventually could optimize out free and realloc of buf */
3618 /* for this case */
3619 if (rc == -EAGAIN)
3620 goto findFirstRetry;
3621 } else { /* decode response */
3622 /* BB remember to free buffer if error BB */
3623 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003624 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003625 unsigned int lnoff;
3626
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003628 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 else
Steve French4b18f2a2008-04-29 00:06:05 +00003630 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631
3632 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003633 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003634 psrch_inf->srch_entries_start =
3635 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3638 le16_to_cpu(pSMBr->t2.ParameterOffset));
3639
Steve French790fe572007-07-07 19:25:05 +00003640 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003641 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 else
Steve French4b18f2a2008-04-29 00:06:05 +00003643 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644
Steve French50c2f752007-07-13 00:33:32 +00003645 psrch_inf->entries_in_buffer =
3646 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003647 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003649 lnoff = le16_to_cpu(parms->LastNameOffset);
3650 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3651 lnoff) {
3652 cERROR(1, ("ignoring corrupt resume name"));
3653 psrch_inf->last_entry = NULL;
3654 return rc;
3655 }
3656
Steve French0752f152008-10-07 20:03:33 +00003657 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003658 lnoff;
3659
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660 *pnetfid = parms->SearchHandle;
3661 } else {
3662 cifs_buf_release(pSMB);
3663 }
3664 }
3665
3666 return rc;
3667}
3668
3669int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003670 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671{
3672 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3673 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003674 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 char *response_data;
3676 int rc = 0;
3677 int bytes_returned, name_len;
3678 __u16 params, byte_count;
3679
3680 cFYI(1, ("In FindNext"));
3681
Steve French4b18f2a2008-04-29 00:06:05 +00003682 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 return -ENOENT;
3684
3685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3686 (void **) &pSMBr);
3687 if (rc)
3688 return rc;
3689
Steve French50c2f752007-07-13 00:33:32 +00003690 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 byte_count = 0;
3692 pSMB->TotalDataCount = 0; /* no EAs */
3693 pSMB->MaxParameterCount = cpu_to_le16(8);
3694 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003695 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3696 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 pSMB->MaxSetupCount = 0;
3698 pSMB->Reserved = 0;
3699 pSMB->Flags = 0;
3700 pSMB->Timeout = 0;
3701 pSMB->Reserved2 = 0;
3702 pSMB->ParameterOffset = cpu_to_le16(
3703 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3704 pSMB->DataCount = 0;
3705 pSMB->DataOffset = 0;
3706 pSMB->SetupCount = 1;
3707 pSMB->Reserved3 = 0;
3708 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3709 pSMB->SearchHandle = searchHandle; /* always kept as le */
3710 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003711 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3713 pSMB->ResumeKey = psrch_inf->resume_key;
3714 pSMB->SearchFlags =
3715 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3716
3717 name_len = psrch_inf->resume_name_len;
3718 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003719 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3721 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003722 /* 14 byte parm len above enough for 2 byte null terminator */
3723 pSMB->ResumeFileName[name_len] = 0;
3724 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 } else {
3726 rc = -EINVAL;
3727 goto FNext2_err_exit;
3728 }
3729 byte_count = params + 1 /* pad */ ;
3730 pSMB->TotalParameterCount = cpu_to_le16(params);
3731 pSMB->ParameterCount = pSMB->TotalParameterCount;
3732 pSMB->hdr.smb_buf_length += byte_count;
3733 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003734
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3736 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003737 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 if (rc) {
3739 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003740 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003741 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003742 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 } else
3744 cFYI(1, ("FindNext returned = %d", rc));
3745 } else { /* decode response */
3746 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003747
Steve French790fe572007-07-07 19:25:05 +00003748 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003749 unsigned int lnoff;
3750
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 /* BB fixme add lock for file (srch_info) struct here */
3752 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003753 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 else
Steve French4b18f2a2008-04-29 00:06:05 +00003755 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 response_data = (char *) &pSMBr->hdr.Protocol +
3757 le16_to_cpu(pSMBr->t2.ParameterOffset);
3758 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3759 response_data = (char *)&pSMBr->hdr.Protocol +
3760 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003761 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003762 cifs_small_buf_release(
3763 psrch_inf->ntwrk_buf_start);
3764 else
3765 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 psrch_inf->srch_entries_start = response_data;
3767 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003768 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003769 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003770 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 else
Steve French4b18f2a2008-04-29 00:06:05 +00003772 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003773 psrch_inf->entries_in_buffer =
3774 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 psrch_inf->index_of_last_entry +=
3776 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003777 lnoff = le16_to_cpu(parms->LastNameOffset);
3778 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3779 lnoff) {
3780 cERROR(1, ("ignoring corrupt resume name"));
3781 psrch_inf->last_entry = NULL;
3782 return rc;
3783 } else
3784 psrch_inf->last_entry =
3785 psrch_inf->srch_entries_start + lnoff;
3786
Steve French50c2f752007-07-13 00:33:32 +00003787/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3788 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
3790 /* BB fixme add unlock here */
3791 }
3792
3793 }
3794
3795 /* BB On error, should we leave previous search buf (and count and
3796 last entry fields) intact or free the previous one? */
3797
3798 /* Note: On -EAGAIN error only caller can retry on handle based calls
3799 since file handle passed in no longer valid */
3800FNext2_err_exit:
3801 if (rc != 0)
3802 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 return rc;
3804}
3805
3806int
Steve French50c2f752007-07-13 00:33:32 +00003807CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3808 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809{
3810 int rc = 0;
3811 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812
3813 cFYI(1, ("In CIFSSMBFindClose"));
3814 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3815
3816 /* no sense returning error if session restarted
3817 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003818 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 return 0;
3820 if (rc)
3821 return rc;
3822
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 pSMB->FileID = searchHandle;
3824 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003825 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003826 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003828
Steve Frencha4544342005-08-24 13:59:35 -07003829 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830
3831 /* Since session is dead, search handle closed on server already */
3832 if (rc == -EAGAIN)
3833 rc = 0;
3834
3835 return rc;
3836}
3837
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838int
3839CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003840 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003841 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003842 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843{
3844 int rc = 0;
3845 TRANSACTION2_QPI_REQ *pSMB = NULL;
3846 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3847 int name_len, bytes_returned;
3848 __u16 params, byte_count;
3849
Steve French50c2f752007-07-13 00:33:32 +00003850 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003851 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003852 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853
3854GetInodeNumberRetry:
3855 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003856 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 if (rc)
3858 return rc;
3859
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3861 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003862 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003863 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 name_len++; /* trailing null */
3865 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003866 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 name_len = strnlen(searchName, PATH_MAX);
3868 name_len++; /* trailing null */
3869 strncpy(pSMB->FileName, searchName, name_len);
3870 }
3871
3872 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3873 pSMB->TotalDataCount = 0;
3874 pSMB->MaxParameterCount = cpu_to_le16(2);
3875 /* BB find exact max data count below from sess structure BB */
3876 pSMB->MaxDataCount = cpu_to_le16(4000);
3877 pSMB->MaxSetupCount = 0;
3878 pSMB->Reserved = 0;
3879 pSMB->Flags = 0;
3880 pSMB->Timeout = 0;
3881 pSMB->Reserved2 = 0;
3882 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003883 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 pSMB->DataCount = 0;
3885 pSMB->DataOffset = 0;
3886 pSMB->SetupCount = 1;
3887 pSMB->Reserved3 = 0;
3888 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3889 byte_count = params + 1 /* pad */ ;
3890 pSMB->TotalParameterCount = cpu_to_le16(params);
3891 pSMB->ParameterCount = pSMB->TotalParameterCount;
3892 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3893 pSMB->Reserved4 = 0;
3894 pSMB->hdr.smb_buf_length += byte_count;
3895 pSMB->ByteCount = cpu_to_le16(byte_count);
3896
3897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3899 if (rc) {
3900 cFYI(1, ("error %d in QueryInternalInfo", rc));
3901 } else {
3902 /* decode response */
3903 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3904 if (rc || (pSMBr->ByteCount < 2))
3905 /* BB also check enough total bytes returned */
3906 /* If rc should we check for EOPNOSUPP and
3907 disable the srvino flag? or in caller? */
3908 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003909 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3911 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003912 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003914 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3916 rc = -EIO;
3917 goto GetInodeNumOut;
3918 }
3919 pfinfo = (struct file_internal_info *)
3920 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003921 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 }
3923 }
3924GetInodeNumOut:
3925 cifs_buf_release(pSMB);
3926 if (rc == -EAGAIN)
3927 goto GetInodeNumberRetry;
3928 return rc;
3929}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930
Igor Mammedovfec45852008-05-16 13:06:30 +04003931/* parses DFS refferal V3 structure
3932 * caller is responsible for freeing target_nodes
3933 * returns:
3934 * on success - 0
3935 * on failure - errno
3936 */
3937static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003938parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003939 unsigned int *num_of_nodes,
3940 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003941 const struct nls_table *nls_codepage, int remap,
3942 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003943{
3944 int i, rc = 0;
3945 char *data_end;
3946 bool is_unicode;
3947 struct dfs_referral_level_3 *ref;
3948
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003949 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3950 is_unicode = true;
3951 else
3952 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003953 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3954
3955 if (*num_of_nodes < 1) {
3956 cERROR(1, ("num_referrals: must be at least > 0,"
3957 "but we get num_referrals = %d\n", *num_of_nodes));
3958 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003959 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003960 }
3961
3962 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003963 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003964 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003965 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003966 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003967 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003968 }
3969
3970 /* get the upper boundary of the resp buffer */
3971 data_end = (char *)(&(pSMBr->PathConsumed)) +
3972 le16_to_cpu(pSMBr->t2.DataCount);
3973
3974 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3975 *num_of_nodes,
3976 le16_to_cpu(pSMBr->DFSFlags)));
3977
3978 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3979 *num_of_nodes, GFP_KERNEL);
3980 if (*target_nodes == NULL) {
3981 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3982 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003983 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003984 }
3985
3986 /* collect neccessary data from referrals */
3987 for (i = 0; i < *num_of_nodes; i++) {
3988 char *temp;
3989 int max_len;
3990 struct dfs_info3_param *node = (*target_nodes)+i;
3991
3992 node->flags = le16_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003993 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003994 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3995 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003996 cifsConvertToUCS((__le16 *) tmp, searchName,
3997 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003998 node->path_consumed = cifs_ucs2_bytes(tmp,
3999 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004000 nls_codepage);
4001 kfree(tmp);
4002 } else
4003 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4004
Igor Mammedovfec45852008-05-16 13:06:30 +04004005 node->server_type = le16_to_cpu(ref->ServerType);
4006 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4007
4008 /* copy DfsPath */
4009 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4010 max_len = data_end - temp;
Suresh Jayaraman968460e2009-04-20 18:54:21 +05304011 rc = cifs_strlcpy_to_host(&(node->path_name), temp,
Igor Mammedovfec45852008-05-16 13:06:30 +04004012 max_len, is_unicode, nls_codepage);
4013 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004014 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004015
4016 /* copy link target UNC */
4017 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4018 max_len = data_end - temp;
Suresh Jayaraman968460e2009-04-20 18:54:21 +05304019 rc = cifs_strlcpy_to_host(&(node->node_name), temp,
Igor Mammedovfec45852008-05-16 13:06:30 +04004020 max_len, is_unicode, nls_codepage);
4021 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004022 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004023
Al Viro1d92cfd2008-06-02 10:59:02 +01004024 ref += le16_to_cpu(ref->Size);
Igor Mammedovfec45852008-05-16 13:06:30 +04004025 }
4026
Steve Frencha1fe78f2008-05-16 18:48:38 +00004027parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004028 if (rc) {
4029 free_dfs_info_array(*target_nodes, *num_of_nodes);
4030 *target_nodes = NULL;
4031 *num_of_nodes = 0;
4032 }
4033 return rc;
4034}
4035
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036int
4037CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4038 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004039 struct dfs_info3_param **target_nodes,
4040 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042{
4043/* TRANS2_GET_DFS_REFERRAL */
4044 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4045 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 int rc = 0;
4047 int bytes_returned;
4048 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004050 *num_of_nodes = 0;
4051 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052
4053 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4054 if (ses == NULL)
4055 return -ENODEV;
4056getDFSRetry:
4057 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4058 (void **) &pSMBr);
4059 if (rc)
4060 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004061
4062 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004063 but should never be null here anyway */
4064 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 pSMB->hdr.Tid = ses->ipc_tid;
4066 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004067 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004069 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071
4072 if (ses->capabilities & CAP_UNICODE) {
4073 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4074 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004075 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004076 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 name_len++; /* trailing null */
4078 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004079 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 name_len = strnlen(searchName, PATH_MAX);
4081 name_len++; /* trailing null */
4082 strncpy(pSMB->RequestFileName, searchName, name_len);
4083 }
4084
Steve French790fe572007-07-07 19:25:05 +00004085 if (ses->server) {
4086 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004087 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4088 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4089 }
4090
Steve French50c2f752007-07-13 00:33:32 +00004091 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004092
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 params = 2 /* level */ + name_len /*includes null */ ;
4094 pSMB->TotalDataCount = 0;
4095 pSMB->DataCount = 0;
4096 pSMB->DataOffset = 0;
4097 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004098 /* BB find exact max SMB PDU from sess structure BB */
4099 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 pSMB->MaxSetupCount = 0;
4101 pSMB->Reserved = 0;
4102 pSMB->Flags = 0;
4103 pSMB->Timeout = 0;
4104 pSMB->Reserved2 = 0;
4105 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004106 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 pSMB->SetupCount = 1;
4108 pSMB->Reserved3 = 0;
4109 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4110 byte_count = params + 3 /* pad */ ;
4111 pSMB->ParameterCount = cpu_to_le16(params);
4112 pSMB->TotalParameterCount = pSMB->ParameterCount;
4113 pSMB->MaxReferralLevel = cpu_to_le16(3);
4114 pSMB->hdr.smb_buf_length += byte_count;
4115 pSMB->ByteCount = cpu_to_le16(byte_count);
4116
4117 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4119 if (rc) {
4120 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004121 goto GetDFSRefExit;
4122 }
4123 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004125 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004126 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004127 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004128 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004130
4131 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4132 pSMBr->ByteCount,
4133 le16_to_cpu(pSMBr->t2.DataOffset)));
4134
4135 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004136 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004137 target_nodes, nls_codepage, remap,
4138 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004139
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004141 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143 if (rc == -EAGAIN)
4144 goto getDFSRetry;
4145
4146 return rc;
4147}
4148
Steve French20962432005-09-21 22:05:57 -07004149/* Query File System Info such as free space to old servers such as Win 9x */
4150int
4151SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4152{
4153/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4154 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4155 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4156 FILE_SYSTEM_ALLOC_INFO *response_data;
4157 int rc = 0;
4158 int bytes_returned = 0;
4159 __u16 params, byte_count;
4160
4161 cFYI(1, ("OldQFSInfo"));
4162oldQFSInfoRetry:
4163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4164 (void **) &pSMBr);
4165 if (rc)
4166 return rc;
Steve French20962432005-09-21 22:05:57 -07004167
4168 params = 2; /* level */
4169 pSMB->TotalDataCount = 0;
4170 pSMB->MaxParameterCount = cpu_to_le16(2);
4171 pSMB->MaxDataCount = cpu_to_le16(1000);
4172 pSMB->MaxSetupCount = 0;
4173 pSMB->Reserved = 0;
4174 pSMB->Flags = 0;
4175 pSMB->Timeout = 0;
4176 pSMB->Reserved2 = 0;
4177 byte_count = params + 1 /* pad */ ;
4178 pSMB->TotalParameterCount = cpu_to_le16(params);
4179 pSMB->ParameterCount = pSMB->TotalParameterCount;
4180 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4181 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4182 pSMB->DataCount = 0;
4183 pSMB->DataOffset = 0;
4184 pSMB->SetupCount = 1;
4185 pSMB->Reserved3 = 0;
4186 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4187 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4188 pSMB->hdr.smb_buf_length += byte_count;
4189 pSMB->ByteCount = cpu_to_le16(byte_count);
4190
4191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4193 if (rc) {
4194 cFYI(1, ("Send error in QFSInfo = %d", rc));
4195 } else { /* decode response */
4196 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4197
4198 if (rc || (pSMBr->ByteCount < 18))
4199 rc = -EIO; /* bad smb */
4200 else {
4201 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004202 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004203 pSMBr->ByteCount, data_offset));
4204
Steve French50c2f752007-07-13 00:33:32 +00004205 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004206 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4207 FSData->f_bsize =
4208 le16_to_cpu(response_data->BytesPerSector) *
4209 le32_to_cpu(response_data->
4210 SectorsPerAllocationUnit);
4211 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004212 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004213 FSData->f_bfree = FSData->f_bavail =
4214 le32_to_cpu(response_data->FreeAllocationUnits);
4215 cFYI(1,
4216 ("Blocks: %lld Free: %lld Block size %ld",
4217 (unsigned long long)FSData->f_blocks,
4218 (unsigned long long)FSData->f_bfree,
4219 FSData->f_bsize));
4220 }
4221 }
4222 cifs_buf_release(pSMB);
4223
4224 if (rc == -EAGAIN)
4225 goto oldQFSInfoRetry;
4226
4227 return rc;
4228}
4229
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230int
Steve French737b7582005-04-28 22:41:06 -07004231CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232{
4233/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4234 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4235 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4236 FILE_SYSTEM_INFO *response_data;
4237 int rc = 0;
4238 int bytes_returned = 0;
4239 __u16 params, byte_count;
4240
4241 cFYI(1, ("In QFSInfo"));
4242QFSInfoRetry:
4243 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4244 (void **) &pSMBr);
4245 if (rc)
4246 return rc;
4247
4248 params = 2; /* level */
4249 pSMB->TotalDataCount = 0;
4250 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004251 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 pSMB->MaxSetupCount = 0;
4253 pSMB->Reserved = 0;
4254 pSMB->Flags = 0;
4255 pSMB->Timeout = 0;
4256 pSMB->Reserved2 = 0;
4257 byte_count = params + 1 /* pad */ ;
4258 pSMB->TotalParameterCount = cpu_to_le16(params);
4259 pSMB->ParameterCount = pSMB->TotalParameterCount;
4260 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004261 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 pSMB->DataCount = 0;
4263 pSMB->DataOffset = 0;
4264 pSMB->SetupCount = 1;
4265 pSMB->Reserved3 = 0;
4266 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4267 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4268 pSMB->hdr.smb_buf_length += byte_count;
4269 pSMB->ByteCount = cpu_to_le16(byte_count);
4270
4271 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4272 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4273 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004274 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004276 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277
Steve French20962432005-09-21 22:05:57 -07004278 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 rc = -EIO; /* bad smb */
4280 else {
4281 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282
4283 response_data =
4284 (FILE_SYSTEM_INFO
4285 *) (((char *) &pSMBr->hdr.Protocol) +
4286 data_offset);
4287 FSData->f_bsize =
4288 le32_to_cpu(response_data->BytesPerSector) *
4289 le32_to_cpu(response_data->
4290 SectorsPerAllocationUnit);
4291 FSData->f_blocks =
4292 le64_to_cpu(response_data->TotalAllocationUnits);
4293 FSData->f_bfree = FSData->f_bavail =
4294 le64_to_cpu(response_data->FreeAllocationUnits);
4295 cFYI(1,
4296 ("Blocks: %lld Free: %lld Block size %ld",
4297 (unsigned long long)FSData->f_blocks,
4298 (unsigned long long)FSData->f_bfree,
4299 FSData->f_bsize));
4300 }
4301 }
4302 cifs_buf_release(pSMB);
4303
4304 if (rc == -EAGAIN)
4305 goto QFSInfoRetry;
4306
4307 return rc;
4308}
4309
4310int
Steve French737b7582005-04-28 22:41:06 -07004311CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312{
4313/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4314 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4315 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4316 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4317 int rc = 0;
4318 int bytes_returned = 0;
4319 __u16 params, byte_count;
4320
4321 cFYI(1, ("In QFSAttributeInfo"));
4322QFSAttributeRetry:
4323 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4324 (void **) &pSMBr);
4325 if (rc)
4326 return rc;
4327
4328 params = 2; /* level */
4329 pSMB->TotalDataCount = 0;
4330 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004331 /* BB find exact max SMB PDU from sess structure BB */
4332 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 pSMB->MaxSetupCount = 0;
4334 pSMB->Reserved = 0;
4335 pSMB->Flags = 0;
4336 pSMB->Timeout = 0;
4337 pSMB->Reserved2 = 0;
4338 byte_count = params + 1 /* pad */ ;
4339 pSMB->TotalParameterCount = cpu_to_le16(params);
4340 pSMB->ParameterCount = pSMB->TotalParameterCount;
4341 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004342 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 pSMB->DataCount = 0;
4344 pSMB->DataOffset = 0;
4345 pSMB->SetupCount = 1;
4346 pSMB->Reserved3 = 0;
4347 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4348 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4349 pSMB->hdr.smb_buf_length += byte_count;
4350 pSMB->ByteCount = cpu_to_le16(byte_count);
4351
4352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4354 if (rc) {
4355 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4356 } else { /* decode response */
4357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4358
Steve French50c2f752007-07-13 00:33:32 +00004359 if (rc || (pSMBr->ByteCount < 13)) {
4360 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361 rc = -EIO; /* bad smb */
4362 } else {
4363 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4364 response_data =
4365 (FILE_SYSTEM_ATTRIBUTE_INFO
4366 *) (((char *) &pSMBr->hdr.Protocol) +
4367 data_offset);
4368 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004369 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370 }
4371 }
4372 cifs_buf_release(pSMB);
4373
4374 if (rc == -EAGAIN)
4375 goto QFSAttributeRetry;
4376
4377 return rc;
4378}
4379
4380int
Steve French737b7582005-04-28 22:41:06 -07004381CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382{
4383/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4384 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4385 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4386 FILE_SYSTEM_DEVICE_INFO *response_data;
4387 int rc = 0;
4388 int bytes_returned = 0;
4389 __u16 params, byte_count;
4390
4391 cFYI(1, ("In QFSDeviceInfo"));
4392QFSDeviceRetry:
4393 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4394 (void **) &pSMBr);
4395 if (rc)
4396 return rc;
4397
4398 params = 2; /* level */
4399 pSMB->TotalDataCount = 0;
4400 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004401 /* BB find exact max SMB PDU from sess structure BB */
4402 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 pSMB->MaxSetupCount = 0;
4404 pSMB->Reserved = 0;
4405 pSMB->Flags = 0;
4406 pSMB->Timeout = 0;
4407 pSMB->Reserved2 = 0;
4408 byte_count = params + 1 /* pad */ ;
4409 pSMB->TotalParameterCount = cpu_to_le16(params);
4410 pSMB->ParameterCount = pSMB->TotalParameterCount;
4411 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004412 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413
4414 pSMB->DataCount = 0;
4415 pSMB->DataOffset = 0;
4416 pSMB->SetupCount = 1;
4417 pSMB->Reserved3 = 0;
4418 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4419 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4420 pSMB->hdr.smb_buf_length += byte_count;
4421 pSMB->ByteCount = cpu_to_le16(byte_count);
4422
4423 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4425 if (rc) {
4426 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4427 } else { /* decode response */
4428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4429
Steve French630f3f02007-10-25 21:17:17 +00004430 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 rc = -EIO; /* bad smb */
4432 else {
4433 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4434 response_data =
Steve French737b7582005-04-28 22:41:06 -07004435 (FILE_SYSTEM_DEVICE_INFO *)
4436 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 data_offset);
4438 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004439 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 }
4441 }
4442 cifs_buf_release(pSMB);
4443
4444 if (rc == -EAGAIN)
4445 goto QFSDeviceRetry;
4446
4447 return rc;
4448}
4449
4450int
Steve French737b7582005-04-28 22:41:06 -07004451CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452{
4453/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4454 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4455 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4456 FILE_SYSTEM_UNIX_INFO *response_data;
4457 int rc = 0;
4458 int bytes_returned = 0;
4459 __u16 params, byte_count;
4460
4461 cFYI(1, ("In QFSUnixInfo"));
4462QFSUnixRetry:
4463 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4464 (void **) &pSMBr);
4465 if (rc)
4466 return rc;
4467
4468 params = 2; /* level */
4469 pSMB->TotalDataCount = 0;
4470 pSMB->DataCount = 0;
4471 pSMB->DataOffset = 0;
4472 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004473 /* BB find exact max SMB PDU from sess structure BB */
4474 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 pSMB->MaxSetupCount = 0;
4476 pSMB->Reserved = 0;
4477 pSMB->Flags = 0;
4478 pSMB->Timeout = 0;
4479 pSMB->Reserved2 = 0;
4480 byte_count = params + 1 /* pad */ ;
4481 pSMB->ParameterCount = cpu_to_le16(params);
4482 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004483 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4484 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 pSMB->SetupCount = 1;
4486 pSMB->Reserved3 = 0;
4487 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4488 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4489 pSMB->hdr.smb_buf_length += byte_count;
4490 pSMB->ByteCount = cpu_to_le16(byte_count);
4491
4492 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4493 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4494 if (rc) {
4495 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4496 } else { /* decode response */
4497 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4498
4499 if (rc || (pSMBr->ByteCount < 13)) {
4500 rc = -EIO; /* bad smb */
4501 } else {
4502 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4503 response_data =
4504 (FILE_SYSTEM_UNIX_INFO
4505 *) (((char *) &pSMBr->hdr.Protocol) +
4506 data_offset);
4507 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004508 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 }
4510 }
4511 cifs_buf_release(pSMB);
4512
4513 if (rc == -EAGAIN)
4514 goto QFSUnixRetry;
4515
4516
4517 return rc;
4518}
4519
Jeremy Allisonac670552005-06-22 17:26:35 -07004520int
Steve French45abc6e2005-06-23 13:42:03 -05004521CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004522{
4523/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4524 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4525 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4526 int rc = 0;
4527 int bytes_returned = 0;
4528 __u16 params, param_offset, offset, byte_count;
4529
4530 cFYI(1, ("In SETFSUnixInfo"));
4531SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004532 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004533 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4534 (void **) &pSMBr);
4535 if (rc)
4536 return rc;
4537
4538 params = 4; /* 2 bytes zero followed by info level. */
4539 pSMB->MaxSetupCount = 0;
4540 pSMB->Reserved = 0;
4541 pSMB->Flags = 0;
4542 pSMB->Timeout = 0;
4543 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004544 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4545 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004546 offset = param_offset + params;
4547
4548 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004549 /* BB find exact max SMB PDU from sess structure BB */
4550 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004551 pSMB->SetupCount = 1;
4552 pSMB->Reserved3 = 0;
4553 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4554 byte_count = 1 /* pad */ + params + 12;
4555
4556 pSMB->DataCount = cpu_to_le16(12);
4557 pSMB->ParameterCount = cpu_to_le16(params);
4558 pSMB->TotalDataCount = pSMB->DataCount;
4559 pSMB->TotalParameterCount = pSMB->ParameterCount;
4560 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4561 pSMB->DataOffset = cpu_to_le16(offset);
4562
4563 /* Params. */
4564 pSMB->FileNum = 0;
4565 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4566
4567 /* Data. */
4568 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4569 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4570 pSMB->ClientUnixCap = cpu_to_le64(cap);
4571
4572 pSMB->hdr.smb_buf_length += byte_count;
4573 pSMB->ByteCount = cpu_to_le16(byte_count);
4574
4575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4576 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4577 if (rc) {
4578 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4579 } else { /* decode response */
4580 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004581 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004582 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004583 }
4584 cifs_buf_release(pSMB);
4585
4586 if (rc == -EAGAIN)
4587 goto SETFSUnixRetry;
4588
4589 return rc;
4590}
4591
4592
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593
4594int
4595CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004596 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597{
4598/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4599 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4600 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4601 FILE_SYSTEM_POSIX_INFO *response_data;
4602 int rc = 0;
4603 int bytes_returned = 0;
4604 __u16 params, byte_count;
4605
4606 cFYI(1, ("In QFSPosixInfo"));
4607QFSPosixRetry:
4608 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4609 (void **) &pSMBr);
4610 if (rc)
4611 return rc;
4612
4613 params = 2; /* level */
4614 pSMB->TotalDataCount = 0;
4615 pSMB->DataCount = 0;
4616 pSMB->DataOffset = 0;
4617 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004618 /* BB find exact max SMB PDU from sess structure BB */
4619 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->MaxSetupCount = 0;
4621 pSMB->Reserved = 0;
4622 pSMB->Flags = 0;
4623 pSMB->Timeout = 0;
4624 pSMB->Reserved2 = 0;
4625 byte_count = params + 1 /* pad */ ;
4626 pSMB->ParameterCount = cpu_to_le16(params);
4627 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004628 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4629 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 pSMB->SetupCount = 1;
4631 pSMB->Reserved3 = 0;
4632 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4633 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4634 pSMB->hdr.smb_buf_length += byte_count;
4635 pSMB->ByteCount = cpu_to_le16(byte_count);
4636
4637 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4639 if (rc) {
4640 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4641 } else { /* decode response */
4642 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4643
4644 if (rc || (pSMBr->ByteCount < 13)) {
4645 rc = -EIO; /* bad smb */
4646 } else {
4647 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4648 response_data =
4649 (FILE_SYSTEM_POSIX_INFO
4650 *) (((char *) &pSMBr->hdr.Protocol) +
4651 data_offset);
4652 FSData->f_bsize =
4653 le32_to_cpu(response_data->BlockSize);
4654 FSData->f_blocks =
4655 le64_to_cpu(response_data->TotalBlocks);
4656 FSData->f_bfree =
4657 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004658 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 FSData->f_bavail = FSData->f_bfree;
4660 } else {
4661 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004662 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 }
Steve French790fe572007-07-07 19:25:05 +00004664 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004666 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004667 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004669 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 }
4671 }
4672 cifs_buf_release(pSMB);
4673
4674 if (rc == -EAGAIN)
4675 goto QFSPosixRetry;
4676
4677 return rc;
4678}
4679
4680
Steve French50c2f752007-07-13 00:33:32 +00004681/* We can not use write of zero bytes trick to
4682 set file size due to need for large file support. Also note that
4683 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 routine which is only needed to work around a sharing violation bug
4685 in Samba which this routine can run into */
4686
4687int
4688CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004689 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004690 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
4692 struct smb_com_transaction2_spi_req *pSMB = NULL;
4693 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4694 struct file_end_of_file_info *parm_data;
4695 int name_len;
4696 int rc = 0;
4697 int bytes_returned = 0;
4698 __u16 params, byte_count, data_count, param_offset, offset;
4699
4700 cFYI(1, ("In SetEOF"));
4701SetEOFRetry:
4702 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4703 (void **) &pSMBr);
4704 if (rc)
4705 return rc;
4706
4707 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4708 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004709 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004710 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 name_len++; /* trailing null */
4712 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004713 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 name_len = strnlen(fileName, PATH_MAX);
4715 name_len++; /* trailing null */
4716 strncpy(pSMB->FileName, fileName, name_len);
4717 }
4718 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004719 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004721 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 pSMB->MaxSetupCount = 0;
4723 pSMB->Reserved = 0;
4724 pSMB->Flags = 0;
4725 pSMB->Timeout = 0;
4726 pSMB->Reserved2 = 0;
4727 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004728 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004730 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004731 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4732 pSMB->InformationLevel =
4733 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4734 else
4735 pSMB->InformationLevel =
4736 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4737 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4739 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004740 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 else
4742 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004743 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 }
4745
4746 parm_data =
4747 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4748 offset);
4749 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4750 pSMB->DataOffset = cpu_to_le16(offset);
4751 pSMB->SetupCount = 1;
4752 pSMB->Reserved3 = 0;
4753 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4754 byte_count = 3 /* pad */ + params + data_count;
4755 pSMB->DataCount = cpu_to_le16(data_count);
4756 pSMB->TotalDataCount = pSMB->DataCount;
4757 pSMB->ParameterCount = cpu_to_le16(params);
4758 pSMB->TotalParameterCount = pSMB->ParameterCount;
4759 pSMB->Reserved4 = 0;
4760 pSMB->hdr.smb_buf_length += byte_count;
4761 parm_data->FileSize = cpu_to_le64(size);
4762 pSMB->ByteCount = cpu_to_le16(byte_count);
4763 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004765 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767
4768 cifs_buf_release(pSMB);
4769
4770 if (rc == -EAGAIN)
4771 goto SetEOFRetry;
4772
4773 return rc;
4774}
4775
4776int
Steve French50c2f752007-07-13 00:33:32 +00004777CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004778 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779{
4780 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 char *data_offset;
4782 struct file_end_of_file_info *parm_data;
4783 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 __u16 params, param_offset, offset, byte_count, count;
4785
4786 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4787 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004788 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 if (rc)
4791 return rc;
4792
4793 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4794 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004795
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 params = 6;
4797 pSMB->MaxSetupCount = 0;
4798 pSMB->Reserved = 0;
4799 pSMB->Flags = 0;
4800 pSMB->Timeout = 0;
4801 pSMB->Reserved2 = 0;
4802 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4803 offset = param_offset + params;
4804
Steve French50c2f752007-07-13 00:33:32 +00004805 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806
4807 count = sizeof(struct file_end_of_file_info);
4808 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004809 /* BB find exact max SMB PDU from sess structure BB */
4810 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 pSMB->SetupCount = 1;
4812 pSMB->Reserved3 = 0;
4813 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4814 byte_count = 3 /* pad */ + params + count;
4815 pSMB->DataCount = cpu_to_le16(count);
4816 pSMB->ParameterCount = cpu_to_le16(params);
4817 pSMB->TotalDataCount = pSMB->DataCount;
4818 pSMB->TotalParameterCount = pSMB->ParameterCount;
4819 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4820 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004821 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4822 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 pSMB->DataOffset = cpu_to_le16(offset);
4824 parm_data->FileSize = cpu_to_le64(size);
4825 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004826 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4828 pSMB->InformationLevel =
4829 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4830 else
4831 pSMB->InformationLevel =
4832 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004833 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4835 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004836 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 else
4838 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004839 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 }
4841 pSMB->Reserved4 = 0;
4842 pSMB->hdr.smb_buf_length += byte_count;
4843 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004844 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 if (rc) {
4846 cFYI(1,
4847 ("Send error in SetFileInfo (SetFileSize) = %d",
4848 rc));
4849 }
4850
Steve French50c2f752007-07-13 00:33:32 +00004851 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 since file handle passed in no longer valid */
4853
4854 return rc;
4855}
4856
Steve French50c2f752007-07-13 00:33:32 +00004857/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 an open handle, rather than by pathname - this is awkward due to
4859 potential access conflicts on the open, but it is unavoidable for these
4860 old servers since the only other choice is to go from 100 nanosecond DCE
4861 time and resort to the original setpathinfo level which takes the ancient
4862 DOS time format with 2 second granularity */
4863int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004864CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4865 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866{
4867 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 char *data_offset;
4869 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 __u16 params, param_offset, offset, byte_count, count;
4871
4872 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004873 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4874
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 if (rc)
4876 return rc;
4877
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004878 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4879 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004880
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 params = 6;
4882 pSMB->MaxSetupCount = 0;
4883 pSMB->Reserved = 0;
4884 pSMB->Flags = 0;
4885 pSMB->Timeout = 0;
4886 pSMB->Reserved2 = 0;
4887 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4888 offset = param_offset + params;
4889
Steve French50c2f752007-07-13 00:33:32 +00004890 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891
Steve French26f57362007-08-30 22:09:15 +00004892 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004894 /* BB find max SMB PDU from sess */
4895 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 pSMB->SetupCount = 1;
4897 pSMB->Reserved3 = 0;
4898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4899 byte_count = 3 /* pad */ + params + count;
4900 pSMB->DataCount = cpu_to_le16(count);
4901 pSMB->ParameterCount = cpu_to_le16(params);
4902 pSMB->TotalDataCount = pSMB->DataCount;
4903 pSMB->TotalParameterCount = pSMB->ParameterCount;
4904 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4905 pSMB->DataOffset = cpu_to_le16(offset);
4906 pSMB->Fid = fid;
4907 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4908 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4909 else
4910 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4911 pSMB->Reserved4 = 0;
4912 pSMB->hdr.smb_buf_length += byte_count;
4913 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004914 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004915 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004916 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004917 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918
Steve French50c2f752007-07-13 00:33:32 +00004919 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004920 since file handle passed in no longer valid */
4921
4922 return rc;
4923}
4924
Jeff Layton6d22f092008-09-23 11:48:35 -04004925int
4926CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4927 bool delete_file, __u16 fid, __u32 pid_of_opener)
4928{
4929 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4930 char *data_offset;
4931 int rc = 0;
4932 __u16 params, param_offset, offset, byte_count, count;
4933
4934 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4935 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4936
4937 if (rc)
4938 return rc;
4939
4940 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4941 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4942
4943 params = 6;
4944 pSMB->MaxSetupCount = 0;
4945 pSMB->Reserved = 0;
4946 pSMB->Flags = 0;
4947 pSMB->Timeout = 0;
4948 pSMB->Reserved2 = 0;
4949 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4950 offset = param_offset + params;
4951
4952 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4953
4954 count = 1;
4955 pSMB->MaxParameterCount = cpu_to_le16(2);
4956 /* BB find max SMB PDU from sess */
4957 pSMB->MaxDataCount = cpu_to_le16(1000);
4958 pSMB->SetupCount = 1;
4959 pSMB->Reserved3 = 0;
4960 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4961 byte_count = 3 /* pad */ + params + count;
4962 pSMB->DataCount = cpu_to_le16(count);
4963 pSMB->ParameterCount = cpu_to_le16(params);
4964 pSMB->TotalDataCount = pSMB->DataCount;
4965 pSMB->TotalParameterCount = pSMB->ParameterCount;
4966 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4967 pSMB->DataOffset = cpu_to_le16(offset);
4968 pSMB->Fid = fid;
4969 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4970 pSMB->Reserved4 = 0;
4971 pSMB->hdr.smb_buf_length += byte_count;
4972 pSMB->ByteCount = cpu_to_le16(byte_count);
4973 *data_offset = delete_file ? 1 : 0;
4974 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4975 if (rc)
4976 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4977
4978 return rc;
4979}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980
4981int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004982CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4983 const char *fileName, const FILE_BASIC_INFO *data,
4984 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985{
4986 TRANSACTION2_SPI_REQ *pSMB = NULL;
4987 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4988 int name_len;
4989 int rc = 0;
4990 int bytes_returned = 0;
4991 char *data_offset;
4992 __u16 params, param_offset, offset, byte_count, count;
4993
4994 cFYI(1, ("In SetTimes"));
4995
4996SetTimesRetry:
4997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4998 (void **) &pSMBr);
4999 if (rc)
5000 return rc;
5001
5002 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5003 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005004 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 name_len++; /* trailing null */
5007 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005008 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009 name_len = strnlen(fileName, PATH_MAX);
5010 name_len++; /* trailing null */
5011 strncpy(pSMB->FileName, fileName, name_len);
5012 }
5013
5014 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005015 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005017 /* BB find max SMB PDU from sess structure BB */
5018 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 pSMB->MaxSetupCount = 0;
5020 pSMB->Reserved = 0;
5021 pSMB->Flags = 0;
5022 pSMB->Timeout = 0;
5023 pSMB->Reserved2 = 0;
5024 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005025 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 offset = param_offset + params;
5027 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5028 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5029 pSMB->DataOffset = cpu_to_le16(offset);
5030 pSMB->SetupCount = 1;
5031 pSMB->Reserved3 = 0;
5032 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5033 byte_count = 3 /* pad */ + params + count;
5034
5035 pSMB->DataCount = cpu_to_le16(count);
5036 pSMB->ParameterCount = cpu_to_le16(params);
5037 pSMB->TotalDataCount = pSMB->DataCount;
5038 pSMB->TotalParameterCount = pSMB->ParameterCount;
5039 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5041 else
5042 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5043 pSMB->Reserved4 = 0;
5044 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005045 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 pSMB->ByteCount = cpu_to_le16(byte_count);
5047 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5048 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005049 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
5052 cifs_buf_release(pSMB);
5053
5054 if (rc == -EAGAIN)
5055 goto SetTimesRetry;
5056
5057 return rc;
5058}
5059
5060/* Can not be used to set time stamps yet (due to old DOS time format) */
5061/* Can be used to set attributes */
5062#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5063 handling it anyway and NT4 was what we thought it would be needed for
5064 Do not delete it until we prove whether needed for Win9x though */
5065int
5066CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5067 __u16 dos_attrs, const struct nls_table *nls_codepage)
5068{
5069 SETATTR_REQ *pSMB = NULL;
5070 SETATTR_RSP *pSMBr = NULL;
5071 int rc = 0;
5072 int bytes_returned;
5073 int name_len;
5074
5075 cFYI(1, ("In SetAttrLegacy"));
5076
5077SetAttrLgcyRetry:
5078 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5079 (void **) &pSMBr);
5080 if (rc)
5081 return rc;
5082
5083 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5084 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005085 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086 PATH_MAX, nls_codepage);
5087 name_len++; /* trailing null */
5088 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005089 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 name_len = strnlen(fileName, PATH_MAX);
5091 name_len++; /* trailing null */
5092 strncpy(pSMB->fileName, fileName, name_len);
5093 }
5094 pSMB->attr = cpu_to_le16(dos_attrs);
5095 pSMB->BufferFormat = 0x04;
5096 pSMB->hdr.smb_buf_length += name_len + 1;
5097 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005100 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102
5103 cifs_buf_release(pSMB);
5104
5105 if (rc == -EAGAIN)
5106 goto SetAttrLgcyRetry;
5107
5108 return rc;
5109}
5110#endif /* temporarily unneeded SetAttr legacy function */
5111
5112int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005113CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005114 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005115 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116{
5117 TRANSACTION2_SPI_REQ *pSMB = NULL;
5118 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5119 int name_len;
5120 int rc = 0;
5121 int bytes_returned = 0;
5122 FILE_UNIX_BASIC_INFO *data_offset;
5123 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005124 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125
5126 cFYI(1, ("In SetUID/GID/Mode"));
5127setPermsRetry:
5128 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5129 (void **) &pSMBr);
5130 if (rc)
5131 return rc;
5132
5133 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5134 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005135 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005136 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 name_len++; /* trailing null */
5138 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005139 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005140 name_len = strnlen(fileName, PATH_MAX);
5141 name_len++; /* trailing null */
5142 strncpy(pSMB->FileName, fileName, name_len);
5143 }
5144
5145 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005146 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005148 /* BB find max SMB PDU from sess structure BB */
5149 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 pSMB->MaxSetupCount = 0;
5151 pSMB->Reserved = 0;
5152 pSMB->Flags = 0;
5153 pSMB->Timeout = 0;
5154 pSMB->Reserved2 = 0;
5155 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005156 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 offset = param_offset + params;
5158 data_offset =
5159 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5160 offset);
5161 memset(data_offset, 0, count);
5162 pSMB->DataOffset = cpu_to_le16(offset);
5163 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5164 pSMB->SetupCount = 1;
5165 pSMB->Reserved3 = 0;
5166 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5167 byte_count = 3 /* pad */ + params + count;
5168 pSMB->ParameterCount = cpu_to_le16(params);
5169 pSMB->DataCount = cpu_to_le16(count);
5170 pSMB->TotalParameterCount = pSMB->ParameterCount;
5171 pSMB->TotalDataCount = pSMB->DataCount;
5172 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5173 pSMB->Reserved4 = 0;
5174 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005175 /* Samba server ignores set of file size to zero due to bugs in some
5176 older clients, but we should be precise - we use SetFileSize to
5177 set file size and do not want to truncate file size to zero
5178 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005179 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005180 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5181 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5182 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5183 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5184 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5185 data_offset->Uid = cpu_to_le64(args->uid);
5186 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005188 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5189 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005191
Steve French790fe572007-07-07 19:25:05 +00005192 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005194 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005196 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005198 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005200 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005202 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005204 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5206
5207
5208 pSMB->ByteCount = cpu_to_le16(byte_count);
5209 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5210 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005211 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213
Steve French0d817bc2008-05-22 02:02:03 +00005214 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 if (rc == -EAGAIN)
5216 goto setPermsRetry;
5217 return rc;
5218}
5219
Steve French50c2f752007-07-13 00:33:32 +00005220int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005221 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005222 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005223 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224{
5225 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005226 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5227 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005228 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 int bytes_returned;
5230
Steve French50c2f752007-07-13 00:33:32 +00005231 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005233 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 if (rc)
5235 return rc;
5236
5237 pSMB->TotalParameterCount = 0 ;
5238 pSMB->TotalDataCount = 0;
5239 pSMB->MaxParameterCount = cpu_to_le32(2);
5240 /* BB find exact data count max from sess structure BB */
5241 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005242/* BB VERIFY verify which is correct for above BB */
5243 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5244 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5245
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 pSMB->MaxSetupCount = 4;
5247 pSMB->Reserved = 0;
5248 pSMB->ParameterOffset = 0;
5249 pSMB->DataCount = 0;
5250 pSMB->DataOffset = 0;
5251 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5252 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5253 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005254 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5256 pSMB->Reserved2 = 0;
5257 pSMB->CompletionFilter = cpu_to_le32(filter);
5258 pSMB->Fid = netfid; /* file handle always le */
5259 pSMB->ByteCount = 0;
5260
5261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005262 (struct smb_hdr *)pSMBr, &bytes_returned,
5263 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 if (rc) {
5265 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005266 } else {
5267 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005268 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005269 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005270 sizeof(struct dir_notify_req),
5271 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005272 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005273 dnotify_req->Pid = pSMB->hdr.Pid;
5274 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5275 dnotify_req->Mid = pSMB->hdr.Mid;
5276 dnotify_req->Tid = pSMB->hdr.Tid;
5277 dnotify_req->Uid = pSMB->hdr.Uid;
5278 dnotify_req->netfid = netfid;
5279 dnotify_req->pfile = pfile;
5280 dnotify_req->filter = filter;
5281 dnotify_req->multishot = multishot;
5282 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005283 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005284 &GlobalDnotifyReqList);
5285 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005286 } else
Steve French47c786e2005-10-11 20:03:18 -07005287 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 }
5289 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005290 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291}
5292#ifdef CONFIG_CIFS_XATTR
5293ssize_t
5294CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5295 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005296 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005297 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298{
5299 /* BB assumes one setup word */
5300 TRANSACTION2_QPI_REQ *pSMB = NULL;
5301 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5302 int rc = 0;
5303 int bytes_returned;
5304 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005305 struct fea *temp_fea;
5306 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 __u16 params, byte_count;
5308
5309 cFYI(1, ("In Query All EAs path %s", searchName));
5310QAllEAsRetry:
5311 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5312 (void **) &pSMBr);
5313 if (rc)
5314 return rc;
5315
5316 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5317 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005318 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005319 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005320 name_len++; /* trailing null */
5321 name_len *= 2;
5322 } else { /* BB improve the check for buffer overruns BB */
5323 name_len = strnlen(searchName, PATH_MAX);
5324 name_len++; /* trailing null */
5325 strncpy(pSMB->FileName, searchName, name_len);
5326 }
5327
Steve French50c2f752007-07-13 00:33:32 +00005328 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 pSMB->TotalDataCount = 0;
5330 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005331 /* BB find exact max SMB PDU from sess structure BB */
5332 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 pSMB->MaxSetupCount = 0;
5334 pSMB->Reserved = 0;
5335 pSMB->Flags = 0;
5336 pSMB->Timeout = 0;
5337 pSMB->Reserved2 = 0;
5338 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005339 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 pSMB->DataCount = 0;
5341 pSMB->DataOffset = 0;
5342 pSMB->SetupCount = 1;
5343 pSMB->Reserved3 = 0;
5344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5345 byte_count = params + 1 /* pad */ ;
5346 pSMB->TotalParameterCount = cpu_to_le16(params);
5347 pSMB->ParameterCount = pSMB->TotalParameterCount;
5348 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5349 pSMB->Reserved4 = 0;
5350 pSMB->hdr.smb_buf_length += byte_count;
5351 pSMB->ByteCount = cpu_to_le16(byte_count);
5352
5353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5355 if (rc) {
5356 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5357 } else { /* decode response */
5358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5359
5360 /* BB also check enough total bytes returned */
5361 /* BB we need to improve the validity checking
5362 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005363 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 rc = -EIO; /* bad smb */
5365 /* else if (pFindData){
5366 memcpy((char *) pFindData,
5367 (char *) &pSMBr->hdr.Protocol +
5368 data_offset, kl);
5369 }*/ else {
5370 /* check that length of list is not more than bcc */
5371 /* check that each entry does not go beyond length
5372 of list */
5373 /* check that each element of each entry does not
5374 go beyond end of list */
5375 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005376 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 rc = 0;
5378 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005379 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 ea_response_data = (struct fealist *)
5381 (((char *) &pSMBr->hdr.Protocol) +
5382 data_offset);
5383 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005384 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005385 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005387 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 } else {
5389 /* account for ea list len */
5390 name_len -= 4;
5391 temp_fea = ea_response_data->list;
5392 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005393 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 __u16 value_len;
5395 name_len -= 4;
5396 temp_ptr += 4;
5397 rc += temp_fea->name_len;
5398 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005399 rc = rc + 5 + 1;
5400 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005401 memcpy(EAData, "user.", 5);
5402 EAData += 5;
5403 memcpy(EAData, temp_ptr,
5404 temp_fea->name_len);
5405 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 /* null terminate name */
5407 *EAData = 0;
5408 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005409 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 /* skip copy - calc size only */
5411 } else {
5412 /* stop before overrun buffer */
5413 rc = -ERANGE;
5414 break;
5415 }
5416 name_len -= temp_fea->name_len;
5417 temp_ptr += temp_fea->name_len;
5418 /* account for trailing null */
5419 name_len--;
5420 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005421 value_len =
5422 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 name_len -= value_len;
5424 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005425 /* BB check that temp_ptr is still
5426 within the SMB BB*/
5427
5428 /* no trailing null to account for
5429 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 /* go on to next EA */
5431 temp_fea = (struct fea *)temp_ptr;
5432 }
5433 }
5434 }
5435 }
Steve French0d817bc2008-05-22 02:02:03 +00005436 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 if (rc == -EAGAIN)
5438 goto QAllEAsRetry;
5439
5440 return (ssize_t)rc;
5441}
5442
Steve French50c2f752007-07-13 00:33:32 +00005443ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5444 const unsigned char *searchName, const unsigned char *ea_name,
5445 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005446 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447{
5448 TRANSACTION2_QPI_REQ *pSMB = NULL;
5449 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5450 int rc = 0;
5451 int bytes_returned;
5452 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005453 struct fea *temp_fea;
5454 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 __u16 params, byte_count;
5456
5457 cFYI(1, ("In Query EA path %s", searchName));
5458QEARetry:
5459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5460 (void **) &pSMBr);
5461 if (rc)
5462 return rc;
5463
5464 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5465 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005466 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005467 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 name_len++; /* trailing null */
5469 name_len *= 2;
5470 } else { /* BB improve the check for buffer overruns BB */
5471 name_len = strnlen(searchName, PATH_MAX);
5472 name_len++; /* trailing null */
5473 strncpy(pSMB->FileName, searchName, name_len);
5474 }
5475
Steve French50c2f752007-07-13 00:33:32 +00005476 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 pSMB->TotalDataCount = 0;
5478 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005479 /* BB find exact max SMB PDU from sess structure BB */
5480 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 pSMB->MaxSetupCount = 0;
5482 pSMB->Reserved = 0;
5483 pSMB->Flags = 0;
5484 pSMB->Timeout = 0;
5485 pSMB->Reserved2 = 0;
5486 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005487 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 pSMB->DataCount = 0;
5489 pSMB->DataOffset = 0;
5490 pSMB->SetupCount = 1;
5491 pSMB->Reserved3 = 0;
5492 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5493 byte_count = params + 1 /* pad */ ;
5494 pSMB->TotalParameterCount = cpu_to_le16(params);
5495 pSMB->ParameterCount = pSMB->TotalParameterCount;
5496 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5497 pSMB->Reserved4 = 0;
5498 pSMB->hdr.smb_buf_length += byte_count;
5499 pSMB->ByteCount = cpu_to_le16(byte_count);
5500
5501 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5502 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5503 if (rc) {
5504 cFYI(1, ("Send error in Query EA = %d", rc));
5505 } else { /* decode response */
5506 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5507
5508 /* BB also check enough total bytes returned */
5509 /* BB we need to improve the validity checking
5510 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005511 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005512 rc = -EIO; /* bad smb */
5513 /* else if (pFindData){
5514 memcpy((char *) pFindData,
5515 (char *) &pSMBr->hdr.Protocol +
5516 data_offset, kl);
5517 }*/ else {
5518 /* check that length of list is not more than bcc */
5519 /* check that each entry does not go beyond length
5520 of list */
5521 /* check that each element of each entry does not
5522 go beyond end of list */
5523 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005524 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 rc = -ENODATA;
5526 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005527 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 ea_response_data = (struct fealist *)
5529 (((char *) &pSMBr->hdr.Protocol) +
5530 data_offset);
5531 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005532 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005533 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005535 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 } else {
5537 /* account for ea list len */
5538 name_len -= 4;
5539 temp_fea = ea_response_data->list;
5540 temp_ptr = (char *)temp_fea;
5541 /* loop through checking if we have a matching
5542 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005543 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 __u16 value_len;
5545 name_len -= 4;
5546 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005547 value_len =
5548 le16_to_cpu(temp_fea->value_len);
5549 /* BB validate that value_len falls within SMB,
5550 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005551 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 temp_fea->name_len) == 0) {
5553 /* found a match */
5554 rc = value_len;
5555 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005556 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 memcpy(ea_value,
5558 temp_fea->name+temp_fea->name_len+1,
5559 rc);
Steve French50c2f752007-07-13 00:33:32 +00005560 /* ea values, unlike ea
5561 names, are not null
5562 terminated */
Steve French790fe572007-07-07 19:25:05 +00005563 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005564 /* skip copy - calc size only */
5565 } else {
Steve French50c2f752007-07-13 00:33:32 +00005566 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567 rc = -ERANGE;
5568 }
5569 break;
5570 }
5571 name_len -= temp_fea->name_len;
5572 temp_ptr += temp_fea->name_len;
5573 /* account for trailing null */
5574 name_len--;
5575 temp_ptr++;
5576 name_len -= value_len;
5577 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005578 /* No trailing null to account for in
5579 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005580 temp_fea = (struct fea *)temp_ptr;
5581 }
Steve French50c2f752007-07-13 00:33:32 +00005582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 }
5584 }
Steve French0d817bc2008-05-22 02:02:03 +00005585 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 if (rc == -EAGAIN)
5587 goto QEARetry;
5588
5589 return (ssize_t)rc;
5590}
5591
5592int
5593CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005594 const char *ea_name, const void *ea_value,
5595 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5596 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597{
5598 struct smb_com_transaction2_spi_req *pSMB = NULL;
5599 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5600 struct fealist *parm_data;
5601 int name_len;
5602 int rc = 0;
5603 int bytes_returned = 0;
5604 __u16 params, param_offset, byte_count, offset, count;
5605
5606 cFYI(1, ("In SetEA"));
5607SetEARetry:
5608 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5609 (void **) &pSMBr);
5610 if (rc)
5611 return rc;
5612
5613 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5614 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005615 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005616 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005617 name_len++; /* trailing null */
5618 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005619 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 name_len = strnlen(fileName, PATH_MAX);
5621 name_len++; /* trailing null */
5622 strncpy(pSMB->FileName, fileName, name_len);
5623 }
5624
5625 params = 6 + name_len;
5626
5627 /* done calculating parms using name_len of file name,
5628 now use name_len to calculate length of ea name
5629 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005630 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 name_len = 0;
5632 else
Steve French50c2f752007-07-13 00:33:32 +00005633 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005635 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005637 /* BB find max SMB PDU from sess */
5638 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 pSMB->MaxSetupCount = 0;
5640 pSMB->Reserved = 0;
5641 pSMB->Flags = 0;
5642 pSMB->Timeout = 0;
5643 pSMB->Reserved2 = 0;
5644 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005645 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 offset = param_offset + params;
5647 pSMB->InformationLevel =
5648 cpu_to_le16(SMB_SET_FILE_EA);
5649
5650 parm_data =
5651 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5652 offset);
5653 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5654 pSMB->DataOffset = cpu_to_le16(offset);
5655 pSMB->SetupCount = 1;
5656 pSMB->Reserved3 = 0;
5657 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5658 byte_count = 3 /* pad */ + params + count;
5659 pSMB->DataCount = cpu_to_le16(count);
5660 parm_data->list_len = cpu_to_le32(count);
5661 parm_data->list[0].EA_flags = 0;
5662 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005663 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005665 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005666 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 parm_data->list[0].name[name_len] = 0;
5668 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5669 /* caller ensures that ea_value_len is less than 64K but
5670 we need to ensure that it fits within the smb */
5671
Steve French50c2f752007-07-13 00:33:32 +00005672 /*BB add length check to see if it would fit in
5673 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005674 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5675 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005676 memcpy(parm_data->list[0].name+name_len+1,
5677 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678
5679 pSMB->TotalDataCount = pSMB->DataCount;
5680 pSMB->ParameterCount = cpu_to_le16(params);
5681 pSMB->TotalParameterCount = pSMB->ParameterCount;
5682 pSMB->Reserved4 = 0;
5683 pSMB->hdr.smb_buf_length += byte_count;
5684 pSMB->ByteCount = cpu_to_le16(byte_count);
5685 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5686 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005687 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
5690 cifs_buf_release(pSMB);
5691
5692 if (rc == -EAGAIN)
5693 goto SetEARetry;
5694
5695 return rc;
5696}
5697
5698#endif