blob: 6d51696dc762d3b6656ed027fe2d7ed40d549409 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchad7a2922008-02-07 23:25:02 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Igor Mammedovfec45852008-05-16 13:06:30 +040084/* Allocates buffer into dst and copies smb string from src to it.
85 * caller is responsible for freeing dst if function returned 0.
86 * returns:
87 * on success - 0
88 * on failure - errno
89 */
90static int
91cifs_strncpy_to_host(char **dst, const char *src, const int maxlen,
92 const bool is_unicode, const struct nls_table *nls_codepage)
93{
94 int plen;
95
96 if (is_unicode) {
97 plen = UniStrnlen((wchar_t *)src, maxlen);
98 *dst = kmalloc(plen + 2, GFP_KERNEL);
99 if (!*dst)
100 goto cifs_strncpy_to_host_ErrExit;
101 cifs_strfromUCS_le(*dst, (__le16 *)src, plen, nls_codepage);
102 } else {
103 plen = strnlen(src, maxlen);
104 *dst = kmalloc(plen + 2, GFP_KERNEL);
105 if (!*dst)
106 goto cifs_strncpy_to_host_ErrExit;
107 strncpy(*dst, src, plen);
108 }
109 (*dst)[plen] = 0;
Steve Frencha1fe78f2008-05-16 18:48:38 +0000110 (*dst)[plen+1] = 0; /* harmless for ASCII case, needed for Unicode */
Igor Mammedovfec45852008-05-16 13:06:30 +0400111 return 0;
112
113cifs_strncpy_to_host_ErrExit:
114 cERROR(1, ("Failed to allocate buffer for string\n"));
115 return -ENOMEM;
116}
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
119/* Mark as invalid, all open files on tree connections since they
120 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +0000121static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +0000124 struct list_head *tmp;
125 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127/* list all files open on tree connection and mark them invalid */
128 write_lock(&GlobalSMBSeslock);
129 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +0000130 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +0000131 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700134 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
135 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136}
137
Steve Frenchad7a2922008-02-07 23:25:02 +0000138/* Allocate and return pointer to an SMB request buffer, and set basic
139 SMB information in the SMB header. If the return code is zero, this
140 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141static int
142small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000143 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144{
145 int rc = 0;
146
147 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
148 check for tcp and smb session status done differently
149 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000150 if (tcon) {
151 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800152 /* only tree disconnect, open, and write,
153 (and ulogoff which does not have tcon)
154 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000155 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000156 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800157 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000158 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800159 smb_command));
160 return -ENODEV;
161 }
162 }
Steve French790fe572007-07-07 19:25:05 +0000163 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000164 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000166 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700167 reconnect, should be greater than cifs socket
168 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000169 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000170 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000172 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000173 CifsGood), 10 * HZ);
174 if (tcon->ses->server->tcpStatus ==
175 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000177 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000179 cFYI(1, ("gave up waiting on "
180 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700182 } /* else "hard" mount - keep retrying
183 until process is killed or server
184 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 } else /* TCP session is reestablished now */
186 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 }
Steve French50c2f752007-07-13 00:33:32 +0000188
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 nls_codepage = load_nls_default();
190 /* need to prevent multiple threads trying to
191 simultaneously reconnect the same SMB session */
192 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000193 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000194 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700195 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000196 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000198 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000199 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700201 /* BB FIXME add code to check if wsize needs
202 update due to negotiated smb buffer size
203 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000204 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000206 /* tell server Unix caps we support */
207 if (tcon->ses->capabilities & CAP_UNIX)
208 reset_cifs_unix_caps(
209 0 /* no xid */,
210 tcon,
211 NULL /* we do not know sb */,
212 NULL /* no vol info */);
213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000216 /* Removed call to reopen open files here.
217 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700218 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Steve French50c2f752007-07-13 00:33:32 +0000220 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700221 know whether we can continue or not without
222 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000223 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 case SMB_COM_READ_ANDX:
225 case SMB_COM_WRITE_ANDX:
226 case SMB_COM_CLOSE:
227 case SMB_COM_FIND_CLOSE2:
228 case SMB_COM_LOCKING_ANDX: {
229 unload_nls(nls_codepage);
230 return -EAGAIN;
231 }
232 }
233 } else {
234 up(&tcon->ses->sesSem);
235 }
236 unload_nls(nls_codepage);
237
238 } else {
239 return -EIO;
240 }
241 }
Steve French790fe572007-07-07 19:25:05 +0000242 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 return rc;
244
245 *request_buf = cifs_small_buf_get();
246 if (*request_buf == NULL) {
247 /* BB should we add a retry in here if not a writepage? */
248 return -ENOMEM;
249 }
250
Steve French63135e02007-07-17 17:34:02 +0000251 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000252 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
Steve French790fe572007-07-07 19:25:05 +0000254 if (tcon != NULL)
255 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700256
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000258}
259
Steve French12b3b8f2006-02-09 21:12:47 +0000260int
Steve French50c2f752007-07-13 00:33:32 +0000261small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000262 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000263{
264 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000265 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000266
Steve French5815449d2006-02-14 01:36:20 +0000267 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000268 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 return rc;
270
Steve French04fdabe2006-02-10 05:52:50 +0000271 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000272 buffer->Mid = GetNextMid(ses->server);
273 if (ses->capabilities & CAP_UNICODE)
274 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000275 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000276 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
277
278 /* uid, tid can stay at zero as set in header assemble */
279
Steve French50c2f752007-07-13 00:33:32 +0000280 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000281 this function is used after 1st of session setup requests */
282
283 return rc;
284}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
286/* If the return code is zero, this function must fill in request_buf pointer */
287static int
288smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
289 void **request_buf /* returned */ ,
290 void **response_buf /* returned */ )
291{
292 int rc = 0;
293
294 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
295 check for tcp and smb session status done differently
296 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000297 if (tcon) {
Steve Frenchbfb598202008-11-18 16:33:48 +0000298 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800299 /* only tree disconnect, open, and write,
300 (and ulogoff which does not have tcon)
301 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000302 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800303 (smb_command != SMB_COM_OPEN_ANDX) &&
304 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000305 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800306 smb_command));
307 return -ENODEV;
308 }
309 }
310
Steve French790fe572007-07-07 19:25:05 +0000311 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000312 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700314 /* Give Demultiplex thread up to 10 seconds to
315 reconnect, should be greater than cifs socket
316 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000317 while (tcon->ses->server->tcpStatus ==
318 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000320 (tcon->ses->server->tcpStatus ==
321 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000322 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700323 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000325 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000327 cFYI(1, ("gave up waiting on "
328 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700330 } /* else "hard" mount - keep retrying
331 until process is killed or server
332 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 } else /* TCP session is reestablished now */
334 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 nls_codepage = load_nls_default();
337 /* need to prevent multiple threads trying to
338 simultaneously reconnect the same SMB session */
339 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000340 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000341 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700342 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000343 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700345 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
346 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700348 /* BB FIXME add code to check if wsize needs
349 update due to negotiated smb buffer size
350 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000351 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000353 /* tell server Unix caps we support */
354 if (tcon->ses->capabilities & CAP_UNIX)
355 reset_cifs_unix_caps(
356 0 /* no xid */,
357 tcon,
358 NULL /* do not know sb */,
359 NULL /* no vol info */);
360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000363 /* Removed call to reopen open files here.
364 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700365 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
Steve French50c2f752007-07-13 00:33:32 +0000367 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700368 know whether we can continue or not without
369 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000370 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 case SMB_COM_READ_ANDX:
372 case SMB_COM_WRITE_ANDX:
373 case SMB_COM_CLOSE:
374 case SMB_COM_FIND_CLOSE2:
375 case SMB_COM_LOCKING_ANDX: {
376 unload_nls(nls_codepage);
377 return -EAGAIN;
378 }
379 }
380 } else {
381 up(&tcon->ses->sesSem);
382 }
383 unload_nls(nls_codepage);
384
385 } else {
386 return -EIO;
387 }
388 }
Steve French790fe572007-07-07 19:25:05 +0000389 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return rc;
391
392 *request_buf = cifs_buf_get();
393 if (*request_buf == NULL) {
394 /* BB should we add a retry in here if not a writepage? */
395 return -ENOMEM;
396 }
397 /* Although the original thought was we needed the response buf for */
398 /* potential retries of smb operations it turns out we can determine */
399 /* from the mid flags when the request buffer can be resent without */
400 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000401 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000402 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403
404 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000405 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Steve French790fe572007-07-07 19:25:05 +0000407 if (tcon != NULL)
408 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700409
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 return rc;
411}
412
Steve French50c2f752007-07-13 00:33:32 +0000413static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414{
415 int rc = -EINVAL;
416 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000417 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /* check for plausible wct, bcc and t2 data and parm sizes */
420 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000421 if (pSMB->hdr.WordCount >= 10) {
422 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
424 /* check that bcc is at least as big as parms + data */
425 /* check that bcc is less than negotiated smb buffer */
426 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000427 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000428 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000429 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000431 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700432 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000434 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000435 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
437 return 0;
438 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 }
440 }
441 }
Steve French50c2f752007-07-13 00:33:32 +0000442 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 sizeof(struct smb_t2_rsp) + 16);
444 return rc;
445}
446int
447CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
448{
449 NEGOTIATE_REQ *pSMB;
450 NEGOTIATE_RSP *pSMBr;
451 int rc = 0;
452 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000453 int i;
Steve French50c2f752007-07-13 00:33:32 +0000454 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000456 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100457 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
Steve French790fe572007-07-07 19:25:05 +0000459 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 server = ses->server;
461 else {
462 rc = -EIO;
463 return rc;
464 }
465 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
466 (void **) &pSMB, (void **) &pSMBr);
467 if (rc)
468 return rc;
Steve French750d1152006-06-27 06:28:30 +0000469
470 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000471 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000472 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000473 else /* if override flags set only sign/seal OR them with global auth */
474 secFlags = extended_security | ses->overrideSecFlg;
475
Steve French762e5ab2007-06-28 18:41:42 +0000476 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000477
Steve French1982c342005-08-17 12:38:22 -0700478 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000479 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000480
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000481 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000482 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000483 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
484 cFYI(1, ("Kerberos only mechanism, enable extended security"));
485 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
486 }
Steve French50c2f752007-07-13 00:33:32 +0000487
Steve French39798772006-05-31 22:40:51 +0000488 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000489 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000490 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
491 count += strlen(protocols[i].name) + 1;
492 /* null at end of source and target buffers anyway */
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 pSMB->hdr.smb_buf_length += count;
495 pSMB->ByteCount = cpu_to_le16(count);
496
497 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000499 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000500 goto neg_err_exit;
501
Al Viro733f99a2006-10-14 16:48:26 +0100502 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000503 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000504 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000505 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000506 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000507 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000508 could not negotiate a common dialect */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000511#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000512 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100513 && ((dialect == LANMAN_PROT)
514 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000515 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000516 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000517
Steve French790fe572007-07-07 19:25:05 +0000518 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000519 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000520 server->secType = LANMAN;
521 else {
522 cERROR(1, ("mount failed weak security disabled"
523 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000524 rc = -EOPNOTSUPP;
525 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000526 }
Steve French254e55e2006-06-04 05:53:15 +0000527 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
528 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
529 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000530 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000531 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
532 /* even though we do not use raw we might as well set this
533 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000534 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000535 server->maxRw = 0xFF00;
536 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
537 } else {
538 server->maxRw = 0;/* we do not need to use raw anyway */
539 server->capabilities = CAP_MPX_MODE;
540 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000541 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000542 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000543 /* OS/2 often does not set timezone therefore
544 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000545 * Could deviate slightly from the right zone.
546 * Smallest defined timezone difference is 15 minutes
547 * (i.e. Nepal). Rounding up/down is done to match
548 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000549 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000550 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000551 struct timespec ts, utc;
552 utc = CURRENT_TIME;
553 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
554 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000555 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
556 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000557 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000558 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000559 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000560 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000561 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000562 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000563 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000564 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000565 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000566 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000567 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000568 server->timeAdj = (int)tmp;
569 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000570 }
Steve French790fe572007-07-07 19:25:05 +0000571 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000572
Steve French39798772006-05-31 22:40:51 +0000573
Steve French254e55e2006-06-04 05:53:15 +0000574 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000575 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000576
Steve French50c2f752007-07-13 00:33:32 +0000577 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000578 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000579 memcpy(server->cryptKey, rsp->EncryptionKey,
580 CIFS_CRYPTO_KEY_SIZE);
581 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
582 rc = -EIO; /* need cryptkey unless plain text */
583 goto neg_err_exit;
584 }
Steve French39798772006-05-31 22:40:51 +0000585
Steve French790fe572007-07-07 19:25:05 +0000586 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000587 /* we will not end up setting signing flags - as no signing
588 was in LANMAN and server did not return the flags on */
589 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000590#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000591 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000592 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000593 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000594 rc = -EOPNOTSUPP;
595#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000596 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000597 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000598 /* unknown wct */
599 rc = -EOPNOTSUPP;
600 goto neg_err_exit;
601 }
602 /* else wct == 17 NTLM */
603 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000604 if ((server->secMode & SECMODE_USER) == 0)
605 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000606
Steve French790fe572007-07-07 19:25:05 +0000607 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000608#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000609 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000610#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000611 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000612 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000613
Steve French790fe572007-07-07 19:25:05 +0000614 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000615 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000616 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000617 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000618 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000619 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000620 else if (secFlags & CIFSSEC_MAY_KRB5)
621 server->secType = Kerberos;
622 else if (secFlags & CIFSSEC_MAY_LANMAN)
623 server->secType = LANMAN;
624/* #ifdef CONFIG_CIFS_EXPERIMENTAL
625 else if (secFlags & CIFSSEC_MAY_PLNTXT)
626 server->secType = ??
627#endif */
628 else {
629 rc = -EOPNOTSUPP;
630 cERROR(1, ("Invalid security type"));
631 goto neg_err_exit;
632 }
633 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000634
Steve French254e55e2006-06-04 05:53:15 +0000635 /* one byte, so no need to convert this or EncryptionKeyLen from
636 little endian */
637 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
638 /* probably no need to store and check maxvcs */
639 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000641 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000642 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000643 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
644 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000645 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
646 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000647 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
648 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
649 CIFS_CRYPTO_KEY_SIZE);
650 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
651 && (pSMBr->EncryptionKeyLength == 0)) {
652 /* decode security blob */
653 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
654 rc = -EIO; /* no crypt key only if plain text pwd */
655 goto neg_err_exit;
656 }
657
658 /* BB might be helpful to save off the domain of server here */
659
Steve French50c2f752007-07-13 00:33:32 +0000660 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000661 (server->capabilities & CAP_EXTENDED_SECURITY)) {
662 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000663 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000665 goto neg_err_exit;
666 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500667 read_lock(&cifs_tcp_ses_lock);
668 if (server->srv_count > 1) {
669 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000670 if (memcmp(server->server_GUID,
671 pSMBr->u.extended_response.
672 GUID, 16) != 0) {
673 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000674 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000675 pSMBr->u.extended_response.GUID,
676 16);
677 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500678 } else {
679 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000680 memcpy(server->server_GUID,
681 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500682 }
Jeff Laytone187e442007-10-16 17:10:44 +0000683
684 if (count == 16) {
685 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000686 } else {
687 rc = decode_negTokenInit(pSMBr->u.extended_response.
688 SecurityBlob,
689 count - 16,
690 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000691 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000692 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000693 else
Steve French254e55e2006-06-04 05:53:15 +0000694 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
Steve French254e55e2006-06-04 05:53:15 +0000696 } else
697 server->capabilities &= ~CAP_EXTENDED_SECURITY;
698
Steve French6344a422006-06-12 04:18:35 +0000699#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000700signing_check:
Steve French6344a422006-06-12 04:18:35 +0000701#endif
Steve French762e5ab2007-06-28 18:41:42 +0000702 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
703 /* MUST_SIGN already includes the MAY_SIGN FLAG
704 so if this is zero it means that signing is disabled */
705 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000706 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000707 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000708 "packet signing to be enabled in "
709 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000710 rc = -EOPNOTSUPP;
711 }
Steve French50c2f752007-07-13 00:33:32 +0000712 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000713 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000714 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
715 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000716 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000717 if ((server->secMode &
718 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
719 cERROR(1,
720 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000721 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000722 } else
723 server->secMode |= SECMODE_SIGN_REQUIRED;
724 } else {
725 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000726 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000727 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000728 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 }
Steve French50c2f752007-07-13 00:33:32 +0000730
731neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700732 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000733
Steve French790fe572007-07-07 19:25:05 +0000734 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 return rc;
736}
737
738int
739CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
740{
741 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
744 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500745
746 /* BB: do we need to check this? These should never be NULL. */
747 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
748 return -EIO;
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500751 * No need to return error on this operation if tid invalidated and
752 * closed on server already e.g. due to tcp session crashing. Also,
753 * the tcon is no longer on the list, so no need to take lock before
754 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 */
Jeff Laytonf1987b42008-11-15 11:12:47 -0500756 if (tcon->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000757 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Steve French50c2f752007-07-13 00:33:32 +0000759 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700760 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500761 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return rc;
Steve French133672e2007-11-13 22:41:37 +0000763
764 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700766 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Steve French50c2f752007-07-13 00:33:32 +0000768 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500769 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (rc == -EAGAIN)
771 rc = 0;
772
773 return rc;
774}
775
776int
777CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
778{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 LOGOFF_ANDX_REQ *pSMB;
780 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500783
784 /*
785 * BB: do we need to check validity of ses and server? They should
786 * always be valid since we have an active reference. If not, that
787 * should probably be a BUG()
788 */
789 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return -EIO;
791
Jeff Layton14fbf502008-11-14 13:53:46 -0500792 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000793 if (ses->need_reconnect)
794 goto session_already_dead; /* no need to send SMBlogoff if uid
795 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
797 if (rc) {
798 up(&ses->sesSem);
799 return rc;
800 }
801
Steve French3b795212008-11-13 19:45:32 +0000802 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700803
Steve French3b795212008-11-13 19:45:32 +0000804 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
806 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 pSMB->hdr.Uid = ses->Suid;
809
810 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000811 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000812session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700813 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814
815 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000816 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 error */
818 if (rc == -EAGAIN)
819 rc = 0;
820 return rc;
821}
822
823int
Steve French2d785a52007-07-15 01:48:57 +0000824CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
825 __u16 type, const struct nls_table *nls_codepage, int remap)
826{
827 TRANSACTION2_SPI_REQ *pSMB = NULL;
828 TRANSACTION2_SPI_RSP *pSMBr = NULL;
829 struct unlink_psx_rq *pRqD;
830 int name_len;
831 int rc = 0;
832 int bytes_returned = 0;
833 __u16 params, param_offset, offset, byte_count;
834
835 cFYI(1, ("In POSIX delete"));
836PsxDelete:
837 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
838 (void **) &pSMBr);
839 if (rc)
840 return rc;
841
842 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
843 name_len =
844 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
845 PATH_MAX, nls_codepage, remap);
846 name_len++; /* trailing null */
847 name_len *= 2;
848 } else { /* BB add path length overrun check */
849 name_len = strnlen(fileName, PATH_MAX);
850 name_len++; /* trailing null */
851 strncpy(pSMB->FileName, fileName, name_len);
852 }
853
854 params = 6 + name_len;
855 pSMB->MaxParameterCount = cpu_to_le16(2);
856 pSMB->MaxDataCount = 0; /* BB double check this with jra */
857 pSMB->MaxSetupCount = 0;
858 pSMB->Reserved = 0;
859 pSMB->Flags = 0;
860 pSMB->Timeout = 0;
861 pSMB->Reserved2 = 0;
862 param_offset = offsetof(struct smb_com_transaction2_spi_req,
863 InformationLevel) - 4;
864 offset = param_offset + params;
865
866 /* Setup pointer to Request Data (inode type) */
867 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
868 pRqD->type = cpu_to_le16(type);
869 pSMB->ParameterOffset = cpu_to_le16(param_offset);
870 pSMB->DataOffset = cpu_to_le16(offset);
871 pSMB->SetupCount = 1;
872 pSMB->Reserved3 = 0;
873 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
874 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
875
876 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
877 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
878 pSMB->ParameterCount = cpu_to_le16(params);
879 pSMB->TotalParameterCount = pSMB->ParameterCount;
880 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
881 pSMB->Reserved4 = 0;
882 pSMB->hdr.smb_buf_length += byte_count;
883 pSMB->ByteCount = cpu_to_le16(byte_count);
884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000886 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000887 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000888 cifs_buf_release(pSMB);
889
890 cifs_stats_inc(&tcon->num_deletes);
891
892 if (rc == -EAGAIN)
893 goto PsxDelete;
894
895 return rc;
896}
897
898int
Steve French737b7582005-04-28 22:41:06 -0700899CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
900 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 DELETE_FILE_REQ *pSMB = NULL;
903 DELETE_FILE_RSP *pSMBr = NULL;
904 int rc = 0;
905 int bytes_returned;
906 int name_len;
907
908DelFileRetry:
909 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
910 (void **) &pSMBr);
911 if (rc)
912 return rc;
913
914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
915 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000916 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700917 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 name_len++; /* trailing null */
919 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700920 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 name_len = strnlen(fileName, PATH_MAX);
922 name_len++; /* trailing null */
923 strncpy(pSMB->fileName, fileName, name_len);
924 }
925 pSMB->SearchAttributes =
926 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
927 pSMB->BufferFormat = 0x04;
928 pSMB->hdr.smb_buf_length += name_len + 1;
929 pSMB->ByteCount = cpu_to_le16(name_len + 1);
930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700932 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000933 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 cifs_buf_release(pSMB);
937 if (rc == -EAGAIN)
938 goto DelFileRetry;
939
940 return rc;
941}
942
943int
Steve French50c2f752007-07-13 00:33:32 +0000944CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 DELETE_DIRECTORY_REQ *pSMB = NULL;
948 DELETE_DIRECTORY_RSP *pSMBr = NULL;
949 int rc = 0;
950 int bytes_returned;
951 int name_len;
952
953 cFYI(1, ("In CIFSSMBRmDir"));
954RmDirRetry:
955 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
959
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700961 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 name_len++; /* trailing null */
964 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700965 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name_len = strnlen(dirName, PATH_MAX);
967 name_len++; /* trailing null */
968 strncpy(pSMB->DirName, dirName, name_len);
969 }
970
971 pSMB->BufferFormat = 0x04;
972 pSMB->hdr.smb_buf_length += name_len + 1;
973 pSMB->ByteCount = cpu_to_le16(name_len + 1);
974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700976 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000977 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980 cifs_buf_release(pSMB);
981 if (rc == -EAGAIN)
982 goto RmDirRetry;
983 return rc;
984}
985
986int
987CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700988 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
990 int rc = 0;
991 CREATE_DIRECTORY_REQ *pSMB = NULL;
992 CREATE_DIRECTORY_RSP *pSMBr = NULL;
993 int bytes_returned;
994 int name_len;
995
996 cFYI(1, ("In CIFSSMBMkDir"));
997MkDirRetry:
998 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
999 (void **) &pSMBr);
1000 if (rc)
1001 return rc;
1002
1003 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001004 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001005 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 name_len++; /* trailing null */
1007 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001008 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 name_len = strnlen(name, PATH_MAX);
1010 name_len++; /* trailing null */
1011 strncpy(pSMB->DirName, name, name_len);
1012 }
1013
1014 pSMB->BufferFormat = 0x04;
1015 pSMB->hdr.smb_buf_length += name_len + 1;
1016 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1017 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1018 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001019 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001020 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07001022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 cifs_buf_release(pSMB);
1024 if (rc == -EAGAIN)
1025 goto MkDirRetry;
1026 return rc;
1027}
1028
Steve French2dd29d32007-04-23 22:07:35 +00001029int
1030CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001031 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001032 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001033 const struct nls_table *nls_codepage, int remap)
1034{
1035 TRANSACTION2_SPI_REQ *pSMB = NULL;
1036 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1037 int name_len;
1038 int rc = 0;
1039 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001040 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001041 OPEN_PSX_REQ *pdata;
1042 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001043
1044 cFYI(1, ("In POSIX Create"));
1045PsxCreat:
1046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1047 (void **) &pSMBr);
1048 if (rc)
1049 return rc;
1050
1051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1052 name_len =
1053 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1054 PATH_MAX, nls_codepage, remap);
1055 name_len++; /* trailing null */
1056 name_len *= 2;
1057 } else { /* BB improve the check for buffer overruns BB */
1058 name_len = strnlen(name, PATH_MAX);
1059 name_len++; /* trailing null */
1060 strncpy(pSMB->FileName, name, name_len);
1061 }
1062
1063 params = 6 + name_len;
1064 count = sizeof(OPEN_PSX_REQ);
1065 pSMB->MaxParameterCount = cpu_to_le16(2);
1066 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1067 pSMB->MaxSetupCount = 0;
1068 pSMB->Reserved = 0;
1069 pSMB->Flags = 0;
1070 pSMB->Timeout = 0;
1071 pSMB->Reserved2 = 0;
1072 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001073 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001074 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001075 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001076 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001078 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->OpenFlags = cpu_to_le32(*pOplock);
1080 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1081 pSMB->DataOffset = cpu_to_le16(offset);
1082 pSMB->SetupCount = 1;
1083 pSMB->Reserved3 = 0;
1084 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1085 byte_count = 3 /* pad */ + params + count;
1086
1087 pSMB->DataCount = cpu_to_le16(count);
1088 pSMB->ParameterCount = cpu_to_le16(params);
1089 pSMB->TotalDataCount = pSMB->DataCount;
1090 pSMB->TotalParameterCount = pSMB->ParameterCount;
1091 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1092 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001093 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001094 pSMB->ByteCount = cpu_to_le16(byte_count);
1095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1097 if (rc) {
1098 cFYI(1, ("Posix create returned %d", rc));
1099 goto psx_create_err;
1100 }
1101
Steve French790fe572007-07-07 19:25:05 +00001102 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1104
1105 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1106 rc = -EIO; /* bad smb */
1107 goto psx_create_err;
1108 }
1109
1110 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001111 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001112 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001113
Steve French2dd29d32007-04-23 22:07:35 +00001114 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001115 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001116 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1117 /* Let caller know file was created so we can set the mode. */
1118 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001119 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001120 *pOplock |= CIFS_CREATE_ACTION;
1121 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001122 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1123 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001124 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001125 } else {
Steve French790fe572007-07-07 19:25:05 +00001126 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001127 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001128 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001129 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001130 goto psx_create_err;
1131 }
Steve French50c2f752007-07-13 00:33:32 +00001132 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001133 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001134 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001135 }
Steve French2dd29d32007-04-23 22:07:35 +00001136
1137psx_create_err:
1138 cifs_buf_release(pSMB);
1139
1140 cifs_stats_inc(&tcon->num_mkdirs);
1141
1142 if (rc == -EAGAIN)
1143 goto PsxCreat;
1144
Steve French50c2f752007-07-13 00:33:32 +00001145 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001146}
1147
Steve Frencha9d02ad2005-08-24 23:06:05 -07001148static __u16 convert_disposition(int disposition)
1149{
1150 __u16 ofun = 0;
1151
1152 switch (disposition) {
1153 case FILE_SUPERSEDE:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1155 break;
1156 case FILE_OPEN:
1157 ofun = SMBOPEN_OAPPEND;
1158 break;
1159 case FILE_CREATE:
1160 ofun = SMBOPEN_OCREATE;
1161 break;
1162 case FILE_OPEN_IF:
1163 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1164 break;
1165 case FILE_OVERWRITE:
1166 ofun = SMBOPEN_OTRUNC;
1167 break;
1168 case FILE_OVERWRITE_IF:
1169 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1170 break;
1171 default:
Steve French790fe572007-07-07 19:25:05 +00001172 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 ofun = SMBOPEN_OAPPEND; /* regular open */
1174 }
1175 return ofun;
1176}
1177
Jeff Layton35fc37d2008-05-14 10:22:03 -07001178static int
1179access_flags_to_smbopen_mode(const int access_flags)
1180{
1181 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1182
1183 if (masked_flags == GENERIC_READ)
1184 return SMBOPEN_READ;
1185 else if (masked_flags == GENERIC_WRITE)
1186 return SMBOPEN_WRITE;
1187
1188 /* just go for read/write */
1189 return SMBOPEN_READWRITE;
1190}
1191
Steve Frencha9d02ad2005-08-24 23:06:05 -07001192int
1193SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1194 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001195 const int access_flags, const int create_options, __u16 *netfid,
1196 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 const struct nls_table *nls_codepage, int remap)
1198{
1199 int rc = -EACCES;
1200 OPENX_REQ *pSMB = NULL;
1201 OPENX_RSP *pSMBr = NULL;
1202 int bytes_returned;
1203 int name_len;
1204 __u16 count;
1205
1206OldOpenRetry:
1207 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1208 (void **) &pSMBr);
1209 if (rc)
1210 return rc;
1211
1212 pSMB->AndXCommand = 0xFF; /* none */
1213
1214 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1215 count = 1; /* account for one byte pad to word boundary */
1216 name_len =
1217 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1218 fileName, PATH_MAX, nls_codepage, remap);
1219 name_len++; /* trailing null */
1220 name_len *= 2;
1221 } else { /* BB improve check for buffer overruns BB */
1222 count = 0; /* no pad */
1223 name_len = strnlen(fileName, PATH_MAX);
1224 name_len++; /* trailing null */
1225 strncpy(pSMB->fileName, fileName, name_len);
1226 }
1227 if (*pOplock & REQ_OPLOCK)
1228 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001229 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001231
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001233 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1235 /* set file as system file if special file such
1236 as fifo and server expecting SFU style and
1237 no Unix extensions */
1238
Steve French790fe572007-07-07 19:25:05 +00001239 if (create_options & CREATE_OPTION_SPECIAL)
1240 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001241 else /* BB FIXME BB */
1242 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243
Jeff Layton67750fb2008-05-09 22:28:02 +00001244 if (create_options & CREATE_OPTION_READONLY)
1245 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246
1247 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001248/* pSMB->CreateOptions = cpu_to_le32(create_options &
1249 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001251
1252 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001253 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 count += name_len;
1255 pSMB->hdr.smb_buf_length += count;
1256
1257 pSMB->ByteCount = cpu_to_le16(count);
1258 /* long_op set to 1 to allow for oplock break timeouts */
1259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001260 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 cifs_stats_inc(&tcon->num_opens);
1262 if (rc) {
1263 cFYI(1, ("Error in Open = %d", rc));
1264 } else {
1265 /* BB verify if wct == 15 */
1266
Steve French582d21e2008-05-13 04:54:12 +00001267/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268
1269 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1270 /* Let caller know file was created so we can set the mode. */
1271 /* Do we care about the CreateAction in any other cases? */
1272 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001273/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 *pOplock |= CIFS_CREATE_ACTION; */
1275 /* BB FIXME END */
1276
Steve French790fe572007-07-07 19:25:05 +00001277 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001278 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1279 pfile_info->LastAccessTime = 0; /* BB fixme */
1280 pfile_info->LastWriteTime = 0; /* BB fixme */
1281 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001282 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001283 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001284 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001285 pfile_info->AllocationSize =
1286 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1287 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001288 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001289 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001290 }
1291 }
1292
1293 cifs_buf_release(pSMB);
1294 if (rc == -EAGAIN)
1295 goto OldOpenRetry;
1296 return rc;
1297}
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299int
1300CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1301 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001302 const int access_flags, const int create_options, __u16 *netfid,
1303 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001304 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305{
1306 int rc = -EACCES;
1307 OPEN_REQ *pSMB = NULL;
1308 OPEN_RSP *pSMBr = NULL;
1309 int bytes_returned;
1310 int name_len;
1311 __u16 count;
1312
1313openRetry:
1314 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1315 (void **) &pSMBr);
1316 if (rc)
1317 return rc;
1318
1319 pSMB->AndXCommand = 0xFF; /* none */
1320
1321 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1322 count = 1; /* account for one byte pad to word boundary */
1323 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001324 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001325 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 name_len++; /* trailing null */
1327 name_len *= 2;
1328 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001329 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 count = 0; /* no pad */
1331 name_len = strnlen(fileName, PATH_MAX);
1332 name_len++; /* trailing null */
1333 pSMB->NameLength = cpu_to_le16(name_len);
1334 strncpy(pSMB->fileName, fileName, name_len);
1335 }
1336 if (*pOplock & REQ_OPLOCK)
1337 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001338 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1341 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001342 /* set file as system file if special file such
1343 as fifo and server expecting SFU style and
1344 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001345 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001346 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1347 else
1348 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001349
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 /* XP does not handle ATTR_POSIX_SEMANTICS */
1351 /* but it helps speed up case sensitive checks for other
1352 servers such as Samba */
1353 if (tcon->ses->capabilities & CAP_UNIX)
1354 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1355
Jeff Layton67750fb2008-05-09 22:28:02 +00001356 if (create_options & CREATE_OPTION_READONLY)
1357 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1358
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1360 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001361 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001362 /* BB Expirement with various impersonation levels and verify */
1363 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 pSMB->SecurityFlags =
1365 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1366
1367 count += name_len;
1368 pSMB->hdr.smb_buf_length += count;
1369
1370 pSMB->ByteCount = cpu_to_le16(count);
1371 /* long_op set to 1 to allow for oplock break timeouts */
1372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001373 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001374 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if (rc) {
1376 cFYI(1, ("Error in Open = %d", rc));
1377 } else {
Steve French09d1db52005-04-28 22:41:08 -07001378 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1380 /* Let caller know file was created so we can set the mode. */
1381 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001382 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001383 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001384 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001385 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 36 /* CreationTime to Attributes */);
1387 /* the file_info buf is endian converted by caller */
1388 pfile_info->AllocationSize = pSMBr->AllocationSize;
1389 pfile_info->EndOfFile = pSMBr->EndOfFile;
1390 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001391 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001394
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 cifs_buf_release(pSMB);
1396 if (rc == -EAGAIN)
1397 goto openRetry;
1398 return rc;
1399}
1400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401int
Steve French50c2f752007-07-13 00:33:32 +00001402CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1403 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1404 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405{
1406 int rc = -EACCES;
1407 READ_REQ *pSMB = NULL;
1408 READ_RSP *pSMBr = NULL;
1409 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001410 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001411 int resp_buf_type = 0;
1412 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413
Steve French790fe572007-07-07 19:25:05 +00001414 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1415 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001416 wct = 12;
1417 else
1418 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
1420 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001421 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 if (rc)
1423 return rc;
1424
1425 /* tcon and ses pointer are checked in smb_init */
1426 if (tcon->ses->server == NULL)
1427 return -ECONNABORTED;
1428
Steve Frenchec637e32005-12-12 20:53:18 -08001429 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 pSMB->Fid = netfid;
1431 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001432 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001434 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001435 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001436
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 pSMB->Remaining = 0;
1438 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1439 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001440 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001441 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1442 else {
1443 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001444 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001445 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001446 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001447 }
Steve Frenchec637e32005-12-12 20:53:18 -08001448
1449 iov[0].iov_base = (char *)pSMB;
1450 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001451 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001452 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001453 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001454 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 if (rc) {
1456 cERROR(1, ("Send error in read = %d", rc));
1457 } else {
1458 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1459 data_length = data_length << 16;
1460 data_length += le16_to_cpu(pSMBr->DataLength);
1461 *nbytes = data_length;
1462
1463 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001464 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001466 cFYI(1, ("bad length %d for count %d",
1467 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 rc = -EIO;
1469 *nbytes = 0;
1470 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001471 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001472 le16_to_cpu(pSMBr->DataOffset);
1473/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001474 cERROR(1,("Faulting on read rc = %d",rc));
1475 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001476 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001477 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001478 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479 }
1480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481
Steve French4b8f9302006-02-26 16:41:18 +00001482/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001483 if (*buf) {
1484 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001485 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001486 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001487 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001488 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001489 /* return buffer to caller to free */
1490 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001491 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001492 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001493 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001494 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001495 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001496
1497 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 since file handle passed in no longer valid */
1499 return rc;
1500}
1501
Steve Frenchec637e32005-12-12 20:53:18 -08001502
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503int
1504CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1505 const int netfid, const unsigned int count,
1506 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001507 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508{
1509 int rc = -EACCES;
1510 WRITE_REQ *pSMB = NULL;
1511 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001512 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 __u32 bytes_sent;
1514 __u16 byte_count;
1515
Steve French61de8002008-10-30 20:15:22 +00001516 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001517 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001518 return -ECONNABORTED;
1519
Steve French790fe572007-07-07 19:25:05 +00001520 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001521 wct = 14;
1522 else
1523 wct = 12;
1524
1525 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 (void **) &pSMBr);
1527 if (rc)
1528 return rc;
1529 /* tcon and ses pointer are checked in smb_init */
1530 if (tcon->ses->server == NULL)
1531 return -ECONNABORTED;
1532
1533 pSMB->AndXCommand = 0xFF; /* none */
1534 pSMB->Fid = netfid;
1535 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001536 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001537 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001538 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001539 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 pSMB->Reserved = 0xFFFFFFFF;
1542 pSMB->WriteMode = 0;
1543 pSMB->Remaining = 0;
1544
Steve French50c2f752007-07-13 00:33:32 +00001545 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 can send more if LARGE_WRITE_X capability returned by the server and if
1547 our buffer is big enough or if we convert to iovecs on socket writes
1548 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001549 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1551 } else {
1552 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1553 & ~0xFF;
1554 }
1555
1556 if (bytes_sent > count)
1557 bytes_sent = count;
1558 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001559 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001560 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001561 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001562 else if (ubuf) {
1563 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 cifs_buf_release(pSMB);
1565 return -EFAULT;
1566 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001567 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 /* No buffer */
1569 cifs_buf_release(pSMB);
1570 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001571 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001572 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001573 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001574 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001575 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1578 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001579 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001580
Steve French790fe572007-07-07 19:25:05 +00001581 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001582 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001583 else { /* old style write has byte count 4 bytes earlier
1584 so 4 bytes pad */
1585 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001586 (struct smb_com_writex_req *)pSMB;
1587 pSMBW->ByteCount = cpu_to_le16(byte_count);
1588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1591 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001592 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 if (rc) {
1594 cFYI(1, ("Send error in write = %d", rc));
1595 *nbytes = 0;
1596 } else {
1597 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1598 *nbytes = (*nbytes) << 16;
1599 *nbytes += le16_to_cpu(pSMBr->Count);
1600 }
1601
1602 cifs_buf_release(pSMB);
1603
Steve French50c2f752007-07-13 00:33:32 +00001604 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 since file handle passed in no longer valid */
1606
1607 return rc;
1608}
1609
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001610int
1611CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001613 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1614 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
1616 int rc = -EACCES;
1617 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001618 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001619 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001620 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
Steve French790fe572007-07-07 19:25:05 +00001622 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001623
Steve French790fe572007-07-07 19:25:05 +00001624 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001625 wct = 14;
1626 else
1627 wct = 12;
1628 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 if (rc)
1630 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 /* tcon and ses pointer are checked in smb_init */
1632 if (tcon->ses->server == NULL)
1633 return -ECONNABORTED;
1634
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001635 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 pSMB->Fid = netfid;
1637 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001638 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001639 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001640 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001641 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 pSMB->Reserved = 0xFFFFFFFF;
1643 pSMB->WriteMode = 0;
1644 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001645
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001647 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648
Steve French3e844692005-10-03 13:37:24 -07001649 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1650 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001651 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001652 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001653 pSMB->hdr.smb_buf_length += count+1;
1654 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001655 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1656 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001657 pSMB->ByteCount = cpu_to_le16(count + 1);
1658 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001659 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001660 (struct smb_com_writex_req *)pSMB;
1661 pSMBW->ByteCount = cpu_to_le16(count + 5);
1662 }
Steve French3e844692005-10-03 13:37:24 -07001663 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001664 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001665 iov[0].iov_len = smb_hdr_len + 4;
1666 else /* wct == 12 pad bigger by four bytes */
1667 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001668
Steve French3e844692005-10-03 13:37:24 -07001669
Steve Frenchec637e32005-12-12 20:53:18 -08001670 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001671 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001672 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001674 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001676 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001677 /* presumably this can not happen, but best to be safe */
1678 rc = -EIO;
1679 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001680 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001681 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001682 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1683 *nbytes = (*nbytes) << 16;
1684 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Steve French4b8f9302006-02-26 16:41:18 +00001687/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001688 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001689 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001690 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001691 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
Steve French50c2f752007-07-13 00:33:32 +00001693 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 since file handle passed in no longer valid */
1695
1696 return rc;
1697}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001698
1699
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700int
1701CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1702 const __u16 smb_file_id, const __u64 len,
1703 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001704 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705{
1706 int rc = 0;
1707 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001708/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 int bytes_returned;
1710 int timeout = 0;
1711 __u16 count;
1712
Steve French4b18f2a2008-04-29 00:06:05 +00001713 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001714 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1715
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 if (rc)
1717 return rc;
1718
Steve French790fe572007-07-07 19:25:05 +00001719 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001720 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001722 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001723 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1725 } else {
1726 pSMB->Timeout = 0;
1727 }
1728
1729 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1730 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1731 pSMB->LockType = lockType;
1732 pSMB->AndXCommand = 0xFF; /* none */
1733 pSMB->Fid = smb_file_id; /* netfid stays le */
1734
Steve French790fe572007-07-07 19:25:05 +00001735 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1737 /* BB where to store pid high? */
1738 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1739 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1740 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1741 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1742 count = sizeof(LOCKING_ANDX_RANGE);
1743 } else {
1744 /* oplock break */
1745 count = 0;
1746 }
1747 pSMB->hdr.smb_buf_length += count;
1748 pSMB->ByteCount = cpu_to_le16(count);
1749
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001750 if (waitFlag) {
1751 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001752 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001753 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001754 } else {
Steve French133672e2007-11-13 22:41:37 +00001755 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1756 timeout);
1757 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001758 }
Steve Frencha4544342005-08-24 13:59:35 -07001759 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001760 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
Steve French50c2f752007-07-13 00:33:32 +00001763 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 since file handle passed in no longer valid */
1765 return rc;
1766}
1767
1768int
Steve French08547b02006-02-28 22:39:25 +00001769CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1770 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001771 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001772 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001773{
1774 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1775 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001776 struct cifs_posix_lock *parm_data;
1777 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001778 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001779 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001780 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001781 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001782 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001783
1784 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001785
Steve French790fe572007-07-07 19:25:05 +00001786 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001787 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001788
Steve French08547b02006-02-28 22:39:25 +00001789 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1790
1791 if (rc)
1792 return rc;
1793
1794 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1795
Steve French50c2f752007-07-13 00:33:32 +00001796 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001797 pSMB->MaxSetupCount = 0;
1798 pSMB->Reserved = 0;
1799 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001800 pSMB->Reserved2 = 0;
1801 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1802 offset = param_offset + params;
1803
Steve French08547b02006-02-28 22:39:25 +00001804 count = sizeof(struct cifs_posix_lock);
1805 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001806 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001807 pSMB->SetupCount = 1;
1808 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001809 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001810 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1811 else
1812 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1813 byte_count = 3 /* pad */ + params + count;
1814 pSMB->DataCount = cpu_to_le16(count);
1815 pSMB->ParameterCount = cpu_to_le16(params);
1816 pSMB->TotalDataCount = pSMB->DataCount;
1817 pSMB->TotalParameterCount = pSMB->ParameterCount;
1818 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001819 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001820 (((char *) &pSMB->hdr.Protocol) + offset);
1821
1822 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001823 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001824 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001825 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001826 pSMB->Timeout = cpu_to_le32(-1);
1827 } else
1828 pSMB->Timeout = 0;
1829
Steve French08547b02006-02-28 22:39:25 +00001830 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001831 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001832 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001833
1834 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001835 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001836 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1837 pSMB->Reserved4 = 0;
1838 pSMB->hdr.smb_buf_length += byte_count;
1839 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001840 if (waitFlag) {
1841 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1842 (struct smb_hdr *) pSMBr, &bytes_returned);
1843 } else {
Steve French133672e2007-11-13 22:41:37 +00001844 iov[0].iov_base = (char *)pSMB;
1845 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1846 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1847 &resp_buf_type, timeout);
1848 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1849 not try to free it twice below on exit */
1850 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001851 }
1852
Steve French08547b02006-02-28 22:39:25 +00001853 if (rc) {
1854 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001855 } else if (get_flag) {
1856 /* lock structure can be returned on get */
1857 __u16 data_offset;
1858 __u16 data_count;
1859 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001860
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001861 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1862 rc = -EIO; /* bad smb */
1863 goto plk_err_exit;
1864 }
Steve French790fe572007-07-07 19:25:05 +00001865 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001866 rc = -EINVAL;
1867 goto plk_err_exit;
1868 }
1869 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1870 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001871 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001872 rc = -EIO;
1873 goto plk_err_exit;
1874 }
1875 parm_data = (struct cifs_posix_lock *)
1876 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001877 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001878 pLockData->fl_type = F_UNLCK;
1879 }
Steve French50c2f752007-07-13 00:33:32 +00001880
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001881plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001882 if (pSMB)
1883 cifs_small_buf_release(pSMB);
1884
Steve French133672e2007-11-13 22:41:37 +00001885 if (resp_buf_type == CIFS_SMALL_BUFFER)
1886 cifs_small_buf_release(iov[0].iov_base);
1887 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1888 cifs_buf_release(iov[0].iov_base);
1889
Steve French08547b02006-02-28 22:39:25 +00001890 /* Note: On -EAGAIN error only caller can retry on handle based calls
1891 since file handle passed in no longer valid */
1892
1893 return rc;
1894}
1895
1896
1897int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1899{
1900 int rc = 0;
1901 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 cFYI(1, ("In CIFSSMBClose"));
1903
1904/* do not retry on dead session on close */
1905 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001906 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 return 0;
1908 if (rc)
1909 return rc;
1910
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001912 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001914 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001915 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001917 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 /* EINTR is expected when user ctl-c to kill app */
1919 cERROR(1, ("Send error in Close = %d", rc));
1920 }
1921 }
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001924 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 rc = 0;
1926
1927 return rc;
1928}
1929
1930int
1931CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1932 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001933 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934{
1935 int rc = 0;
1936 RENAME_REQ *pSMB = NULL;
1937 RENAME_RSP *pSMBr = NULL;
1938 int bytes_returned;
1939 int name_len, name_len2;
1940 __u16 count;
1941
1942 cFYI(1, ("In CIFSSMBRename"));
1943renameRetry:
1944 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1945 (void **) &pSMBr);
1946 if (rc)
1947 return rc;
1948
1949 pSMB->BufferFormat = 0x04;
1950 pSMB->SearchAttributes =
1951 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1952 ATTR_DIRECTORY);
1953
1954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1955 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001956 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001957 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 name_len++; /* trailing null */
1959 name_len *= 2;
1960 pSMB->OldFileName[name_len] = 0x04; /* pad */
1961 /* protocol requires ASCII signature byte on Unicode string */
1962 pSMB->OldFileName[name_len + 1] = 0x00;
1963 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001964 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001965 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1967 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001968 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 name_len = strnlen(fromName, PATH_MAX);
1970 name_len++; /* trailing null */
1971 strncpy(pSMB->OldFileName, fromName, name_len);
1972 name_len2 = strnlen(toName, PATH_MAX);
1973 name_len2++; /* trailing null */
1974 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1975 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1976 name_len2++; /* trailing null */
1977 name_len2++; /* signature byte */
1978 }
1979
1980 count = 1 /* 1st signature byte */ + name_len + name_len2;
1981 pSMB->hdr.smb_buf_length += count;
1982 pSMB->ByteCount = cpu_to_le16(count);
1983
1984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001986 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001987 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 cifs_buf_release(pSMB);
1991
1992 if (rc == -EAGAIN)
1993 goto renameRetry;
1994
1995 return rc;
1996}
1997
Steve French50c2f752007-07-13 00:33:32 +00001998int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001999 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002000 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
2002 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2003 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002004 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 char *data_offset;
2006 char dummy_string[30];
2007 int rc = 0;
2008 int bytes_returned = 0;
2009 int len_of_str;
2010 __u16 params, param_offset, offset, count, byte_count;
2011
2012 cFYI(1, ("Rename to File by handle"));
2013 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2014 (void **) &pSMBr);
2015 if (rc)
2016 return rc;
2017
2018 params = 6;
2019 pSMB->MaxSetupCount = 0;
2020 pSMB->Reserved = 0;
2021 pSMB->Flags = 0;
2022 pSMB->Timeout = 0;
2023 pSMB->Reserved2 = 0;
2024 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2025 offset = param_offset + params;
2026
2027 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2028 rename_info = (struct set_file_rename *) data_offset;
2029 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002030 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 pSMB->SetupCount = 1;
2032 pSMB->Reserved3 = 0;
2033 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2034 byte_count = 3 /* pad */ + params;
2035 pSMB->ParameterCount = cpu_to_le16(params);
2036 pSMB->TotalParameterCount = pSMB->ParameterCount;
2037 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2038 pSMB->DataOffset = cpu_to_le16(offset);
2039 /* construct random name ".cifs_tmp<inodenum><mid>" */
2040 rename_info->overwrite = cpu_to_le32(1);
2041 rename_info->root_fid = 0;
2042 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002043 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002044 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2045 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002046 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002048 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002049 target_name, PATH_MAX, nls_codepage,
2050 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 }
2052 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002053 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 byte_count += count;
2055 pSMB->DataCount = cpu_to_le16(count);
2056 pSMB->TotalDataCount = pSMB->DataCount;
2057 pSMB->Fid = netfid;
2058 pSMB->InformationLevel =
2059 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2060 pSMB->Reserved4 = 0;
2061 pSMB->hdr.smb_buf_length += byte_count;
2062 pSMB->ByteCount = cpu_to_le16(byte_count);
2063 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002064 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002065 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002066 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002067 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002068
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 cifs_buf_release(pSMB);
2070
2071 /* Note: On -EAGAIN error only caller can retry on handle based calls
2072 since file handle passed in no longer valid */
2073
2074 return rc;
2075}
2076
2077int
Steve French50c2f752007-07-13 00:33:32 +00002078CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2079 const __u16 target_tid, const char *toName, const int flags,
2080 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081{
2082 int rc = 0;
2083 COPY_REQ *pSMB = NULL;
2084 COPY_RSP *pSMBr = NULL;
2085 int bytes_returned;
2086 int name_len, name_len2;
2087 __u16 count;
2088
2089 cFYI(1, ("In CIFSSMBCopy"));
2090copyRetry:
2091 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2092 (void **) &pSMBr);
2093 if (rc)
2094 return rc;
2095
2096 pSMB->BufferFormat = 0x04;
2097 pSMB->Tid2 = target_tid;
2098
2099 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2100
2101 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002102 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002103 fromName, PATH_MAX, nls_codepage,
2104 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 name_len++; /* trailing null */
2106 name_len *= 2;
2107 pSMB->OldFileName[name_len] = 0x04; /* pad */
2108 /* protocol requires ASCII signature byte on Unicode string */
2109 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002110 name_len2 =
2111 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002112 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2114 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002115 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 name_len = strnlen(fromName, PATH_MAX);
2117 name_len++; /* trailing null */
2118 strncpy(pSMB->OldFileName, fromName, name_len);
2119 name_len2 = strnlen(toName, PATH_MAX);
2120 name_len2++; /* trailing null */
2121 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2122 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2123 name_len2++; /* trailing null */
2124 name_len2++; /* signature byte */
2125 }
2126
2127 count = 1 /* 1st signature byte */ + name_len + name_len2;
2128 pSMB->hdr.smb_buf_length += count;
2129 pSMB->ByteCount = cpu_to_le16(count);
2130
2131 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2132 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2133 if (rc) {
2134 cFYI(1, ("Send error in copy = %d with %d files copied",
2135 rc, le16_to_cpu(pSMBr->CopyCount)));
2136 }
Steve French0d817bc2008-05-22 02:02:03 +00002137 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138
2139 if (rc == -EAGAIN)
2140 goto copyRetry;
2141
2142 return rc;
2143}
2144
2145int
2146CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2147 const char *fromName, const char *toName,
2148 const struct nls_table *nls_codepage)
2149{
2150 TRANSACTION2_SPI_REQ *pSMB = NULL;
2151 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2152 char *data_offset;
2153 int name_len;
2154 int name_len_target;
2155 int rc = 0;
2156 int bytes_returned = 0;
2157 __u16 params, param_offset, offset, byte_count;
2158
2159 cFYI(1, ("In Symlink Unix style"));
2160createSymLinkRetry:
2161 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2162 (void **) &pSMBr);
2163 if (rc)
2164 return rc;
2165
2166 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2167 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002168 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 /* find define for this maxpathcomponent */
2170 , nls_codepage);
2171 name_len++; /* trailing null */
2172 name_len *= 2;
2173
Steve French50c2f752007-07-13 00:33:32 +00002174 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 name_len = strnlen(fromName, PATH_MAX);
2176 name_len++; /* trailing null */
2177 strncpy(pSMB->FileName, fromName, name_len);
2178 }
2179 params = 6 + name_len;
2180 pSMB->MaxSetupCount = 0;
2181 pSMB->Reserved = 0;
2182 pSMB->Flags = 0;
2183 pSMB->Timeout = 0;
2184 pSMB->Reserved2 = 0;
2185 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002186 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 offset = param_offset + params;
2188
2189 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2191 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002192 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 /* find define for this maxpathcomponent */
2194 , nls_codepage);
2195 name_len_target++; /* trailing null */
2196 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002197 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 name_len_target = strnlen(toName, PATH_MAX);
2199 name_len_target++; /* trailing null */
2200 strncpy(data_offset, toName, name_len_target);
2201 }
2202
2203 pSMB->MaxParameterCount = cpu_to_le16(2);
2204 /* BB find exact max on data count below from sess */
2205 pSMB->MaxDataCount = cpu_to_le16(1000);
2206 pSMB->SetupCount = 1;
2207 pSMB->Reserved3 = 0;
2208 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2209 byte_count = 3 /* pad */ + params + name_len_target;
2210 pSMB->DataCount = cpu_to_le16(name_len_target);
2211 pSMB->ParameterCount = cpu_to_le16(params);
2212 pSMB->TotalDataCount = pSMB->DataCount;
2213 pSMB->TotalParameterCount = pSMB->ParameterCount;
2214 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2215 pSMB->DataOffset = cpu_to_le16(offset);
2216 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2217 pSMB->Reserved4 = 0;
2218 pSMB->hdr.smb_buf_length += byte_count;
2219 pSMB->ByteCount = cpu_to_le16(byte_count);
2220 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2221 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002222 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002223 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002224 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225
Steve French0d817bc2008-05-22 02:02:03 +00002226 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
2228 if (rc == -EAGAIN)
2229 goto createSymLinkRetry;
2230
2231 return rc;
2232}
2233
2234int
2235CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2236 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002237 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238{
2239 TRANSACTION2_SPI_REQ *pSMB = NULL;
2240 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2241 char *data_offset;
2242 int name_len;
2243 int name_len_target;
2244 int rc = 0;
2245 int bytes_returned = 0;
2246 __u16 params, param_offset, offset, byte_count;
2247
2248 cFYI(1, ("In Create Hard link Unix style"));
2249createHardLinkRetry:
2250 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2251 (void **) &pSMBr);
2252 if (rc)
2253 return rc;
2254
2255 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002256 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002257 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 name_len++; /* trailing null */
2259 name_len *= 2;
2260
Steve French50c2f752007-07-13 00:33:32 +00002261 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len = strnlen(toName, PATH_MAX);
2263 name_len++; /* trailing null */
2264 strncpy(pSMB->FileName, toName, name_len);
2265 }
2266 params = 6 + name_len;
2267 pSMB->MaxSetupCount = 0;
2268 pSMB->Reserved = 0;
2269 pSMB->Flags = 0;
2270 pSMB->Timeout = 0;
2271 pSMB->Reserved2 = 0;
2272 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002273 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 offset = param_offset + params;
2275
2276 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2278 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002279 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002280 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 name_len_target++; /* trailing null */
2282 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002283 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 name_len_target = strnlen(fromName, PATH_MAX);
2285 name_len_target++; /* trailing null */
2286 strncpy(data_offset, fromName, name_len_target);
2287 }
2288
2289 pSMB->MaxParameterCount = cpu_to_le16(2);
2290 /* BB find exact max on data count below from sess*/
2291 pSMB->MaxDataCount = cpu_to_le16(1000);
2292 pSMB->SetupCount = 1;
2293 pSMB->Reserved3 = 0;
2294 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2295 byte_count = 3 /* pad */ + params + name_len_target;
2296 pSMB->ParameterCount = cpu_to_le16(params);
2297 pSMB->TotalParameterCount = pSMB->ParameterCount;
2298 pSMB->DataCount = cpu_to_le16(name_len_target);
2299 pSMB->TotalDataCount = pSMB->DataCount;
2300 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2301 pSMB->DataOffset = cpu_to_le16(offset);
2302 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2303 pSMB->Reserved4 = 0;
2304 pSMB->hdr.smb_buf_length += byte_count;
2305 pSMB->ByteCount = cpu_to_le16(byte_count);
2306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2307 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002308 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002309 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
2312 cifs_buf_release(pSMB);
2313 if (rc == -EAGAIN)
2314 goto createHardLinkRetry;
2315
2316 return rc;
2317}
2318
2319int
2320CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2321 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002322 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323{
2324 int rc = 0;
2325 NT_RENAME_REQ *pSMB = NULL;
2326 RENAME_RSP *pSMBr = NULL;
2327 int bytes_returned;
2328 int name_len, name_len2;
2329 __u16 count;
2330
2331 cFYI(1, ("In CIFSCreateHardLink"));
2332winCreateHardLinkRetry:
2333
2334 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2335 (void **) &pSMBr);
2336 if (rc)
2337 return rc;
2338
2339 pSMB->SearchAttributes =
2340 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2341 ATTR_DIRECTORY);
2342 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2343 pSMB->ClusterCount = 0;
2344
2345 pSMB->BufferFormat = 0x04;
2346
2347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2348 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002349 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002350 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 name_len++; /* trailing null */
2352 name_len *= 2;
2353 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002354 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002356 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002357 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2359 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002360 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 name_len = strnlen(fromName, PATH_MAX);
2362 name_len++; /* trailing null */
2363 strncpy(pSMB->OldFileName, fromName, name_len);
2364 name_len2 = strnlen(toName, PATH_MAX);
2365 name_len2++; /* trailing null */
2366 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2367 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2368 name_len2++; /* trailing null */
2369 name_len2++; /* signature byte */
2370 }
2371
2372 count = 1 /* string type byte */ + name_len + name_len2;
2373 pSMB->hdr.smb_buf_length += count;
2374 pSMB->ByteCount = cpu_to_le16(count);
2375
2376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002378 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002379 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002381
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 cifs_buf_release(pSMB);
2383 if (rc == -EAGAIN)
2384 goto winCreateHardLinkRetry;
2385
2386 return rc;
2387}
2388
2389int
2390CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2391 const unsigned char *searchName,
2392 char *symlinkinfo, const int buflen,
2393 const struct nls_table *nls_codepage)
2394{
2395/* SMB_QUERY_FILE_UNIX_LINK */
2396 TRANSACTION2_QPI_REQ *pSMB = NULL;
2397 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2398 int rc = 0;
2399 int bytes_returned;
2400 int name_len;
2401 __u16 params, byte_count;
2402
2403 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2404
2405querySymLinkRetry:
2406 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2407 (void **) &pSMBr);
2408 if (rc)
2409 return rc;
2410
2411 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2412 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002413 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2414 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 name_len++; /* trailing null */
2416 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002417 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 name_len = strnlen(searchName, PATH_MAX);
2419 name_len++; /* trailing null */
2420 strncpy(pSMB->FileName, searchName, name_len);
2421 }
2422
2423 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2424 pSMB->TotalDataCount = 0;
2425 pSMB->MaxParameterCount = cpu_to_le16(2);
2426 /* BB find exact max data count below from sess structure BB */
2427 pSMB->MaxDataCount = cpu_to_le16(4000);
2428 pSMB->MaxSetupCount = 0;
2429 pSMB->Reserved = 0;
2430 pSMB->Flags = 0;
2431 pSMB->Timeout = 0;
2432 pSMB->Reserved2 = 0;
2433 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002434 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 pSMB->DataCount = 0;
2436 pSMB->DataOffset = 0;
2437 pSMB->SetupCount = 1;
2438 pSMB->Reserved3 = 0;
2439 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2440 byte_count = params + 1 /* pad */ ;
2441 pSMB->TotalParameterCount = cpu_to_le16(params);
2442 pSMB->ParameterCount = pSMB->TotalParameterCount;
2443 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2444 pSMB->Reserved4 = 0;
2445 pSMB->hdr.smb_buf_length += byte_count;
2446 pSMB->ByteCount = cpu_to_le16(byte_count);
2447
2448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2450 if (rc) {
2451 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2452 } else {
2453 /* decode response */
2454
2455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2456 if (rc || (pSMBr->ByteCount < 2))
2457 /* BB also check enough total bytes returned */
2458 rc = -EIO; /* bad smb */
2459 else {
2460 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2461 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2462
2463 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2464 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002465 &pSMBr->hdr.Protocol + data_offset),
2466 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002467 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002469 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2470 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 name_len, nls_codepage);
2472 } else {
2473 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002474 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 data_offset,
2476 min_t(const int, buflen, count));
2477 }
2478 symlinkinfo[buflen] = 0;
2479 /* just in case so calling code does not go off the end of buffer */
2480 }
2481 }
2482 cifs_buf_release(pSMB);
2483 if (rc == -EAGAIN)
2484 goto querySymLinkRetry;
2485 return rc;
2486}
2487
Parag Warudkarc9489772007-10-23 18:09:48 +00002488#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002489/* Initialize NT TRANSACT SMB into small smb request buffer.
2490 This assumes that all NT TRANSACTS that we init here have
2491 total parm and data under about 400 bytes (to fit in small cifs
2492 buffer size), which is the case so far, it easily fits. NB:
2493 Setup words themselves and ByteCount
2494 MaxSetupCount (size of returned setup area) and
2495 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002496static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002497smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002498 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002499 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002500{
2501 int rc;
2502 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002503 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002504
2505 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2506 (void **)&pSMB);
2507 if (rc)
2508 return rc;
2509 *ret_buf = (void *)pSMB;
2510 pSMB->Reserved = 0;
2511 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2512 pSMB->TotalDataCount = 0;
2513 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2514 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2515 pSMB->ParameterCount = pSMB->TotalParameterCount;
2516 pSMB->DataCount = pSMB->TotalDataCount;
2517 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2518 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2519 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2520 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2521 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2522 pSMB->SubCommand = cpu_to_le16(sub_command);
2523 return 0;
2524}
2525
2526static int
Steve French50c2f752007-07-13 00:33:32 +00002527validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002528 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002529{
Steve French50c2f752007-07-13 00:33:32 +00002530 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002531 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002532 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002533
Steve French630f3f0c2007-10-25 21:17:17 +00002534 *pdatalen = 0;
2535 *pparmlen = 0;
2536
Steve French790fe572007-07-07 19:25:05 +00002537 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002538 return -EINVAL;
2539
2540 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2541
2542 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002543 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002544 (char *)&pSMBr->ByteCount;
2545
Steve French0a4b92c2006-01-12 15:44:21 -08002546 data_offset = le32_to_cpu(pSMBr->DataOffset);
2547 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002548 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002549 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2550
2551 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2552 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2553
2554 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002555 if (*ppparm > end_of_smb) {
2556 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002558 } else if (parm_count + *ppparm > end_of_smb) {
2559 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002560 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002561 } else if (*ppdata > end_of_smb) {
2562 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002563 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002564 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002565 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002566 *ppdata, data_count, (data_count + *ppdata),
2567 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002568 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002569 } else if (parm_count + data_count > pSMBr->ByteCount) {
2570 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002571 return -EINVAL;
2572 }
Steve French630f3f0c2007-10-25 21:17:17 +00002573 *pdatalen = data_count;
2574 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002575 return 0;
2576}
Parag Warudkarc9489772007-10-23 18:09:48 +00002577#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002578
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579int
2580CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2581 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002582 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 const struct nls_table *nls_codepage)
2584{
2585 int rc = 0;
2586 int bytes_returned;
2587 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002588 struct smb_com_transaction_ioctl_req *pSMB;
2589 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
2591 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2592 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2593 (void **) &pSMBr);
2594 if (rc)
2595 return rc;
2596
2597 pSMB->TotalParameterCount = 0 ;
2598 pSMB->TotalDataCount = 0;
2599 pSMB->MaxParameterCount = cpu_to_le32(2);
2600 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002601 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2602 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 pSMB->MaxSetupCount = 4;
2604 pSMB->Reserved = 0;
2605 pSMB->ParameterOffset = 0;
2606 pSMB->DataCount = 0;
2607 pSMB->DataOffset = 0;
2608 pSMB->SetupCount = 4;
2609 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2610 pSMB->ParameterCount = pSMB->TotalParameterCount;
2611 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2612 pSMB->IsFsctl = 1; /* FSCTL */
2613 pSMB->IsRootFlag = 0;
2614 pSMB->Fid = fid; /* file handle always le */
2615 pSMB->ByteCount = 0;
2616
2617 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2618 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2619 if (rc) {
2620 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2621 } else { /* decode response */
2622 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2623 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2624 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2625 /* BB also check enough total bytes returned */
2626 rc = -EIO; /* bad smb */
2627 else {
Steve French790fe572007-07-07 19:25:05 +00002628 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002629 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002630 pSMBr->ByteCount +
2631 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
Steve French50c2f752007-07-13 00:33:32 +00002633 struct reparse_data *reparse_buf =
2634 (struct reparse_data *)
2635 ((char *)&pSMBr->hdr.Protocol
2636 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002637 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 rc = -EIO;
2639 goto qreparse_out;
2640 }
Steve French790fe572007-07-07 19:25:05 +00002641 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 reparse_buf->TargetNameOffset +
2643 reparse_buf->TargetNameLen) >
2644 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002645 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 rc = -EIO;
2647 goto qreparse_out;
2648 }
Steve French50c2f752007-07-13 00:33:32 +00002649
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2651 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002652 (reparse_buf->LinkNamesBuf +
2653 reparse_buf->TargetNameOffset),
2654 min(buflen/2,
2655 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002657 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 reparse_buf->TargetNameOffset),
2659 name_len, nls_codepage);
2660 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002661 strncpy(symlinkinfo,
2662 reparse_buf->LinkNamesBuf +
2663 reparse_buf->TargetNameOffset,
2664 min_t(const int, buflen,
2665 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 }
2667 } else {
2668 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002669 cFYI(1, ("Invalid return data count on "
2670 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 }
2672 symlinkinfo[buflen] = 0; /* just in case so the caller
2673 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002674 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 }
2676 }
2677qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002678 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679
2680 /* Note: On -EAGAIN error only caller can retry on handle based calls
2681 since file handle passed in no longer valid */
2682
2683 return rc;
2684}
2685
2686#ifdef CONFIG_CIFS_POSIX
2687
2688/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002689static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2690 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691{
2692 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002693 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2694 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2695 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2697
2698 return;
2699}
2700
2701/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002702static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2703 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704{
2705 int size = 0;
2706 int i;
2707 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002708 struct cifs_posix_ace *pACE;
2709 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2710 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
2712 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2713 return -EOPNOTSUPP;
2714
Steve French790fe572007-07-07 19:25:05 +00002715 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 count = le16_to_cpu(cifs_acl->access_entry_count);
2717 pACE = &cifs_acl->ace_array[0];
2718 size = sizeof(struct cifs_posix_acl);
2719 size += sizeof(struct cifs_posix_ace) * count;
2720 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002721 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002722 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2723 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 return -EINVAL;
2725 }
Steve French790fe572007-07-07 19:25:05 +00002726 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 count = le16_to_cpu(cifs_acl->access_entry_count);
2728 size = sizeof(struct cifs_posix_acl);
2729 size += sizeof(struct cifs_posix_ace) * count;
2730/* skip past access ACEs to get to default ACEs */
2731 pACE = &cifs_acl->ace_array[count];
2732 count = le16_to_cpu(cifs_acl->default_entry_count);
2733 size += sizeof(struct cifs_posix_ace) * count;
2734 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002735 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 return -EINVAL;
2737 } else {
2738 /* illegal type */
2739 return -EINVAL;
2740 }
2741
2742 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002743 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002744 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002745 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 return -ERANGE;
2747 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002748 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002749 for (i = 0; i < count ; i++) {
2750 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2751 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 }
2753 }
2754 return size;
2755}
2756
Steve French50c2f752007-07-13 00:33:32 +00002757static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2758 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759{
2760 __u16 rc = 0; /* 0 = ACL converted ok */
2761
Steve Frenchff7feac2005-11-15 16:45:16 -08002762 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2763 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002765 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 /* Probably no need to le convert -1 on any arch but can not hurt */
2767 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002768 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002769 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002770 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 return rc;
2772}
2773
2774/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002775static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2776 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777{
2778 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002779 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2780 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 int count;
2782 int i;
2783
Steve French790fe572007-07-07 19:25:05 +00002784 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 return 0;
2786
2787 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002788 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002789 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002790 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002791 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002792 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002793 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 return 0;
2795 }
2796 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002797 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002798 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002799 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002800 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 else {
Steve French50c2f752007-07-13 00:33:32 +00002802 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 return 0;
2804 }
Steve French50c2f752007-07-13 00:33:32 +00002805 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2807 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002808 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 /* ACE not converted */
2810 break;
2811 }
2812 }
Steve French790fe572007-07-07 19:25:05 +00002813 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2815 rc += sizeof(struct cifs_posix_acl);
2816 /* BB add check to make sure ACL does not overflow SMB */
2817 }
2818 return rc;
2819}
2820
2821int
2822CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002823 const unsigned char *searchName,
2824 char *acl_inf, const int buflen, const int acl_type,
2825 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826{
2827/* SMB_QUERY_POSIX_ACL */
2828 TRANSACTION2_QPI_REQ *pSMB = NULL;
2829 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2830 int rc = 0;
2831 int bytes_returned;
2832 int name_len;
2833 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002834
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2836
2837queryAclRetry:
2838 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2839 (void **) &pSMBr);
2840 if (rc)
2841 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002842
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2844 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002845 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002846 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 name_len++; /* trailing null */
2848 name_len *= 2;
2849 pSMB->FileName[name_len] = 0;
2850 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002851 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 name_len = strnlen(searchName, PATH_MAX);
2853 name_len++; /* trailing null */
2854 strncpy(pSMB->FileName, searchName, name_len);
2855 }
2856
2857 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2858 pSMB->TotalDataCount = 0;
2859 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002860 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 pSMB->MaxDataCount = cpu_to_le16(4000);
2862 pSMB->MaxSetupCount = 0;
2863 pSMB->Reserved = 0;
2864 pSMB->Flags = 0;
2865 pSMB->Timeout = 0;
2866 pSMB->Reserved2 = 0;
2867 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002868 offsetof(struct smb_com_transaction2_qpi_req,
2869 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 pSMB->DataCount = 0;
2871 pSMB->DataOffset = 0;
2872 pSMB->SetupCount = 1;
2873 pSMB->Reserved3 = 0;
2874 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2875 byte_count = params + 1 /* pad */ ;
2876 pSMB->TotalParameterCount = cpu_to_le16(params);
2877 pSMB->ParameterCount = pSMB->TotalParameterCount;
2878 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2879 pSMB->Reserved4 = 0;
2880 pSMB->hdr.smb_buf_length += byte_count;
2881 pSMB->ByteCount = cpu_to_le16(byte_count);
2882
2883 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2884 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002885 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 if (rc) {
2887 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2888 } else {
2889 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002890
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2892 if (rc || (pSMBr->ByteCount < 2))
2893 /* BB also check enough total bytes returned */
2894 rc = -EIO; /* bad smb */
2895 else {
2896 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2897 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2898 rc = cifs_copy_posix_acl(acl_inf,
2899 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002900 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 }
2902 }
2903 cifs_buf_release(pSMB);
2904 if (rc == -EAGAIN)
2905 goto queryAclRetry;
2906 return rc;
2907}
2908
2909int
2910CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002911 const unsigned char *fileName,
2912 const char *local_acl, const int buflen,
2913 const int acl_type,
2914 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916 struct smb_com_transaction2_spi_req *pSMB = NULL;
2917 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2918 char *parm_data;
2919 int name_len;
2920 int rc = 0;
2921 int bytes_returned = 0;
2922 __u16 params, byte_count, data_count, param_offset, offset;
2923
2924 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2925setAclRetry:
2926 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002927 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 if (rc)
2929 return rc;
2930 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2931 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002932 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002933 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 name_len++; /* trailing null */
2935 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002936 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 name_len = strnlen(fileName, PATH_MAX);
2938 name_len++; /* trailing null */
2939 strncpy(pSMB->FileName, fileName, name_len);
2940 }
2941 params = 6 + name_len;
2942 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002943 /* BB find max SMB size from sess */
2944 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 pSMB->MaxSetupCount = 0;
2946 pSMB->Reserved = 0;
2947 pSMB->Flags = 0;
2948 pSMB->Timeout = 0;
2949 pSMB->Reserved2 = 0;
2950 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002951 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 offset = param_offset + params;
2953 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2954 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2955
2956 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002957 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
Steve French790fe572007-07-07 19:25:05 +00002959 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 rc = -EOPNOTSUPP;
2961 goto setACLerrorExit;
2962 }
2963 pSMB->DataOffset = cpu_to_le16(offset);
2964 pSMB->SetupCount = 1;
2965 pSMB->Reserved3 = 0;
2966 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2967 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2968 byte_count = 3 /* pad */ + params + data_count;
2969 pSMB->DataCount = cpu_to_le16(data_count);
2970 pSMB->TotalDataCount = pSMB->DataCount;
2971 pSMB->ParameterCount = cpu_to_le16(params);
2972 pSMB->TotalParameterCount = pSMB->ParameterCount;
2973 pSMB->Reserved4 = 0;
2974 pSMB->hdr.smb_buf_length += byte_count;
2975 pSMB->ByteCount = cpu_to_le16(byte_count);
2976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002978 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980
2981setACLerrorExit:
2982 cifs_buf_release(pSMB);
2983 if (rc == -EAGAIN)
2984 goto setAclRetry;
2985 return rc;
2986}
2987
Steve Frenchf654bac2005-04-28 22:41:04 -07002988/* BB fix tabs in this function FIXME BB */
2989int
2990CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002991 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002992{
Steve French50c2f752007-07-13 00:33:32 +00002993 int rc = 0;
2994 struct smb_t2_qfi_req *pSMB = NULL;
2995 struct smb_t2_qfi_rsp *pSMBr = NULL;
2996 int bytes_returned;
2997 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002998
Steve French790fe572007-07-07 19:25:05 +00002999 cFYI(1, ("In GetExtAttr"));
3000 if (tcon == NULL)
3001 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003002
3003GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003004 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3005 (void **) &pSMBr);
3006 if (rc)
3007 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003008
Steve Frenchad7a2922008-02-07 23:25:02 +00003009 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003010 pSMB->t2.TotalDataCount = 0;
3011 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3012 /* BB find exact max data count below from sess structure BB */
3013 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3014 pSMB->t2.MaxSetupCount = 0;
3015 pSMB->t2.Reserved = 0;
3016 pSMB->t2.Flags = 0;
3017 pSMB->t2.Timeout = 0;
3018 pSMB->t2.Reserved2 = 0;
3019 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3020 Fid) - 4);
3021 pSMB->t2.DataCount = 0;
3022 pSMB->t2.DataOffset = 0;
3023 pSMB->t2.SetupCount = 1;
3024 pSMB->t2.Reserved3 = 0;
3025 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3026 byte_count = params + 1 /* pad */ ;
3027 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3028 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3029 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3030 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003031 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003032 pSMB->hdr.smb_buf_length += byte_count;
3033 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003034
Steve French790fe572007-07-07 19:25:05 +00003035 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3036 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3037 if (rc) {
3038 cFYI(1, ("error %d in GetExtAttr", rc));
3039 } else {
3040 /* decode response */
3041 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3042 if (rc || (pSMBr->ByteCount < 2))
3043 /* BB also check enough total bytes returned */
3044 /* If rc should we check for EOPNOSUPP and
3045 disable the srvino flag? or in caller? */
3046 rc = -EIO; /* bad smb */
3047 else {
3048 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3049 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3050 struct file_chattr_info *pfinfo;
3051 /* BB Do we need a cast or hash here ? */
3052 if (count != 16) {
3053 cFYI(1, ("Illegal size ret in GetExtAttr"));
3054 rc = -EIO;
3055 goto GetExtAttrOut;
3056 }
3057 pfinfo = (struct file_chattr_info *)
3058 (data_offset + (char *) &pSMBr->hdr.Protocol);
3059 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003060 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003061 }
3062 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003063GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003064 cifs_buf_release(pSMB);
3065 if (rc == -EAGAIN)
3066 goto GetExtAttrRetry;
3067 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003068}
3069
Steve Frenchf654bac2005-04-28 22:41:04 -07003070#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071
Steve French297647c2007-10-12 04:11:59 +00003072#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003073/* Get Security Descriptor (by handle) from remote server for a file or dir */
3074int
3075CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003076 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003077{
3078 int rc = 0;
3079 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003080 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003081 struct kvec iov[1];
3082
3083 cFYI(1, ("GetCifsACL"));
3084
Steve French630f3f0c2007-10-25 21:17:17 +00003085 *pbuflen = 0;
3086 *acl_inf = NULL;
3087
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003088 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003089 8 /* parm len */, tcon, (void **) &pSMB);
3090 if (rc)
3091 return rc;
3092
3093 pSMB->MaxParameterCount = cpu_to_le32(4);
3094 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3095 pSMB->MaxSetupCount = 0;
3096 pSMB->Fid = fid; /* file handle always le */
3097 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3098 CIFS_ACL_DACL);
3099 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3100 pSMB->hdr.smb_buf_length += 11;
3101 iov[0].iov_base = (char *)pSMB;
3102 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3103
Steve Frencha761ac52007-10-18 21:45:27 +00003104 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003105 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003106 cifs_stats_inc(&tcon->num_acl_get);
3107 if (rc) {
3108 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3109 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003110 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003111 __u32 parm_len;
3112 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003113 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003114 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003115
3116/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003117 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003118 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003119 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003120 goto qsec_out;
3121 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3122
Steve French630f3f0c2007-10-25 21:17:17 +00003123 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003124
3125 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3126 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003127 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003128 goto qsec_out;
3129 }
3130
3131/* BB check that data area is minimum length and as big as acl_len */
3132
Steve Frenchaf6f4612007-10-16 18:40:37 +00003133 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003134 if (acl_len != *pbuflen) {
3135 cERROR(1, ("acl length %d does not match %d",
3136 acl_len, *pbuflen));
3137 if (*pbuflen > acl_len)
3138 *pbuflen = acl_len;
3139 }
Steve French0a4b92c2006-01-12 15:44:21 -08003140
Steve French630f3f0c2007-10-25 21:17:17 +00003141 /* check if buffer is big enough for the acl
3142 header followed by the smallest SID */
3143 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3144 (*pbuflen >= 64 * 1024)) {
3145 cERROR(1, ("bad acl length %d", *pbuflen));
3146 rc = -EINVAL;
3147 *pbuflen = 0;
3148 } else {
3149 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3150 if (*acl_inf == NULL) {
3151 *pbuflen = 0;
3152 rc = -ENOMEM;
3153 }
3154 memcpy(*acl_inf, pdata, *pbuflen);
3155 }
Steve French0a4b92c2006-01-12 15:44:21 -08003156 }
3157qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003158 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003159 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003160 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003161 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003162/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003163 return rc;
3164}
Steve French97837582007-12-31 07:47:21 +00003165
3166int
3167CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3168 struct cifs_ntsd *pntsd, __u32 acllen)
3169{
3170 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3171 int rc = 0;
3172 int bytes_returned = 0;
3173 SET_SEC_DESC_REQ *pSMB = NULL;
3174 NTRANSACT_RSP *pSMBr = NULL;
3175
3176setCifsAclRetry:
3177 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3178 (void **) &pSMBr);
3179 if (rc)
3180 return (rc);
3181
3182 pSMB->MaxSetupCount = 0;
3183 pSMB->Reserved = 0;
3184
3185 param_count = 8;
3186 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3187 data_count = acllen;
3188 data_offset = param_offset + param_count;
3189 byte_count = 3 /* pad */ + param_count;
3190
3191 pSMB->DataCount = cpu_to_le32(data_count);
3192 pSMB->TotalDataCount = pSMB->DataCount;
3193 pSMB->MaxParameterCount = cpu_to_le32(4);
3194 pSMB->MaxDataCount = cpu_to_le32(16384);
3195 pSMB->ParameterCount = cpu_to_le32(param_count);
3196 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3197 pSMB->TotalParameterCount = pSMB->ParameterCount;
3198 pSMB->DataOffset = cpu_to_le32(data_offset);
3199 pSMB->SetupCount = 0;
3200 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3201 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3202
3203 pSMB->Fid = fid; /* file handle always le */
3204 pSMB->Reserved2 = 0;
3205 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3206
3207 if (pntsd && acllen) {
3208 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3209 (char *) pntsd,
3210 acllen);
3211 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3212
3213 } else
3214 pSMB->hdr.smb_buf_length += byte_count;
3215
3216 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3217 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3218
3219 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3220 if (rc)
3221 cFYI(1, ("Set CIFS ACL returned %d", rc));
3222 cifs_buf_release(pSMB);
3223
3224 if (rc == -EAGAIN)
3225 goto setCifsAclRetry;
3226
3227 return (rc);
3228}
3229
Steve French297647c2007-10-12 04:11:59 +00003230#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003231
Steve French6b8edfe2005-08-23 20:26:03 -07003232/* Legacy Query Path Information call for lookup to old servers such
3233 as Win9x/WinME */
3234int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003235 const unsigned char *searchName,
3236 FILE_ALL_INFO *pFinfo,
3237 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003238{
Steve Frenchad7a2922008-02-07 23:25:02 +00003239 QUERY_INFORMATION_REQ *pSMB;
3240 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003241 int rc = 0;
3242 int bytes_returned;
3243 int name_len;
3244
Steve French50c2f752007-07-13 00:33:32 +00003245 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003246QInfRetry:
3247 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003248 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003249 if (rc)
3250 return rc;
3251
3252 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3253 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003254 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3255 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003256 name_len++; /* trailing null */
3257 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003258 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003259 name_len = strnlen(searchName, PATH_MAX);
3260 name_len++; /* trailing null */
3261 strncpy(pSMB->FileName, searchName, name_len);
3262 }
3263 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003264 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003265 pSMB->hdr.smb_buf_length += (__u16) name_len;
3266 pSMB->ByteCount = cpu_to_le16(name_len);
3267
3268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003269 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003270 if (rc) {
3271 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003272 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003273 struct timespec ts;
3274 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003275
3276 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003277 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003278 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003279 ts.tv_nsec = 0;
3280 ts.tv_sec = time;
3281 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003282 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003283 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3284 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003285 pFinfo->AllocationSize =
3286 cpu_to_le64(le32_to_cpu(pSMBr->size));
3287 pFinfo->EndOfFile = pFinfo->AllocationSize;
3288 pFinfo->Attributes =
3289 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003290 } else
3291 rc = -EIO; /* bad buffer passed in */
3292
3293 cifs_buf_release(pSMB);
3294
3295 if (rc == -EAGAIN)
3296 goto QInfRetry;
3297
3298 return rc;
3299}
3300
3301
3302
3303
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304int
3305CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3306 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003307 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003308 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003309 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310{
3311/* level 263 SMB_QUERY_FILE_ALL_INFO */
3312 TRANSACTION2_QPI_REQ *pSMB = NULL;
3313 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3314 int rc = 0;
3315 int bytes_returned;
3316 int name_len;
3317 __u16 params, byte_count;
3318
3319/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3320QPathInfoRetry:
3321 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3322 (void **) &pSMBr);
3323 if (rc)
3324 return rc;
3325
3326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3327 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003328 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003329 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 name_len++; /* trailing null */
3331 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003332 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 name_len = strnlen(searchName, PATH_MAX);
3334 name_len++; /* trailing null */
3335 strncpy(pSMB->FileName, searchName, name_len);
3336 }
3337
Steve French50c2f752007-07-13 00:33:32 +00003338 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 pSMB->TotalDataCount = 0;
3340 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003341 /* BB find exact max SMB PDU from sess structure BB */
3342 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 pSMB->MaxSetupCount = 0;
3344 pSMB->Reserved = 0;
3345 pSMB->Flags = 0;
3346 pSMB->Timeout = 0;
3347 pSMB->Reserved2 = 0;
3348 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003349 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 pSMB->DataCount = 0;
3351 pSMB->DataOffset = 0;
3352 pSMB->SetupCount = 1;
3353 pSMB->Reserved3 = 0;
3354 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3355 byte_count = params + 1 /* pad */ ;
3356 pSMB->TotalParameterCount = cpu_to_le16(params);
3357 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003358 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003359 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3360 else
3361 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 pSMB->Reserved4 = 0;
3363 pSMB->hdr.smb_buf_length += byte_count;
3364 pSMB->ByteCount = cpu_to_le16(byte_count);
3365
3366 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3367 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3368 if (rc) {
3369 cFYI(1, ("Send error in QPathInfo = %d", rc));
3370 } else { /* decode response */
3371 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3372
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003373 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3374 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003375 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003377 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003378 rc = -EIO; /* 24 or 26 expected but we do not read
3379 last field */
3380 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003381 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003383
3384 /* On legacy responses we do not read the last field,
3385 EAsize, fortunately since it varies by subdialect and
3386 also note it differs on Set vs. Get, ie two bytes or 4
3387 bytes depending but we don't care here */
3388 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003389 size = sizeof(FILE_INFO_STANDARD);
3390 else
3391 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 memcpy((char *) pFindData,
3393 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003394 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 } else
3396 rc = -ENOMEM;
3397 }
3398 cifs_buf_release(pSMB);
3399 if (rc == -EAGAIN)
3400 goto QPathInfoRetry;
3401
3402 return rc;
3403}
3404
3405int
3406CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3407 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003408 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003409 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410{
3411/* SMB_QUERY_FILE_UNIX_BASIC */
3412 TRANSACTION2_QPI_REQ *pSMB = NULL;
3413 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3414 int rc = 0;
3415 int bytes_returned = 0;
3416 int name_len;
3417 __u16 params, byte_count;
3418
3419 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3420UnixQPathInfoRetry:
3421 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3422 (void **) &pSMBr);
3423 if (rc)
3424 return rc;
3425
3426 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3427 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003428 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003429 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 name_len++; /* trailing null */
3431 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003432 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 name_len = strnlen(searchName, PATH_MAX);
3434 name_len++; /* trailing null */
3435 strncpy(pSMB->FileName, searchName, name_len);
3436 }
3437
Steve French50c2f752007-07-13 00:33:32 +00003438 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 pSMB->TotalDataCount = 0;
3440 pSMB->MaxParameterCount = cpu_to_le16(2);
3441 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003442 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 pSMB->MaxSetupCount = 0;
3444 pSMB->Reserved = 0;
3445 pSMB->Flags = 0;
3446 pSMB->Timeout = 0;
3447 pSMB->Reserved2 = 0;
3448 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003449 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 pSMB->DataCount = 0;
3451 pSMB->DataOffset = 0;
3452 pSMB->SetupCount = 1;
3453 pSMB->Reserved3 = 0;
3454 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3455 byte_count = params + 1 /* pad */ ;
3456 pSMB->TotalParameterCount = cpu_to_le16(params);
3457 pSMB->ParameterCount = pSMB->TotalParameterCount;
3458 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3459 pSMB->Reserved4 = 0;
3460 pSMB->hdr.smb_buf_length += byte_count;
3461 pSMB->ByteCount = cpu_to_le16(byte_count);
3462
3463 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3464 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3465 if (rc) {
3466 cFYI(1, ("Send error in QPathInfo = %d", rc));
3467 } else { /* decode response */
3468 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3469
3470 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003471 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3472 "Unix Extensions can be disabled on mount "
3473 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474 rc = -EIO; /* bad smb */
3475 } else {
3476 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3477 memcpy((char *) pFindData,
3478 (char *) &pSMBr->hdr.Protocol +
3479 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003480 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 }
3482 }
3483 cifs_buf_release(pSMB);
3484 if (rc == -EAGAIN)
3485 goto UnixQPathInfoRetry;
3486
3487 return rc;
3488}
3489
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490/* xid, tcon, searchName and codepage are input parms, rest are returned */
3491int
3492CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003493 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003495 __u16 *pnetfid,
3496 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497{
3498/* level 257 SMB_ */
3499 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3500 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003501 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 int rc = 0;
3503 int bytes_returned = 0;
3504 int name_len;
3505 __u16 params, byte_count;
3506
Steve French50c2f752007-07-13 00:33:32 +00003507 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508
3509findFirstRetry:
3510 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3511 (void **) &pSMBr);
3512 if (rc)
3513 return rc;
3514
3515 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3516 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003517 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003518 PATH_MAX, nls_codepage, remap);
3519 /* We can not add the asterik earlier in case
3520 it got remapped to 0xF03A as if it were part of the
3521 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003523 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003524 pSMB->FileName[name_len+1] = 0;
3525 pSMB->FileName[name_len+2] = '*';
3526 pSMB->FileName[name_len+3] = 0;
3527 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3529 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003530 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 } else { /* BB add check for overrun of SMB buf BB */
3532 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003534 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 free buffer exit; BB */
3536 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003537 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003538 pSMB->FileName[name_len+1] = '*';
3539 pSMB->FileName[name_len+2] = 0;
3540 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 }
3542
3543 params = 12 + name_len /* includes null */ ;
3544 pSMB->TotalDataCount = 0; /* no EAs */
3545 pSMB->MaxParameterCount = cpu_to_le16(10);
3546 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3547 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3548 pSMB->MaxSetupCount = 0;
3549 pSMB->Reserved = 0;
3550 pSMB->Flags = 0;
3551 pSMB->Timeout = 0;
3552 pSMB->Reserved2 = 0;
3553 byte_count = params + 1 /* pad */ ;
3554 pSMB->TotalParameterCount = cpu_to_le16(params);
3555 pSMB->ParameterCount = pSMB->TotalParameterCount;
3556 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003557 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3558 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 pSMB->DataCount = 0;
3560 pSMB->DataOffset = 0;
3561 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3562 pSMB->Reserved3 = 0;
3563 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3564 pSMB->SearchAttributes =
3565 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3566 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003567 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3568 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 CIFS_SEARCH_RETURN_RESUME);
3570 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3571
3572 /* BB what should we set StorageType to? Does it matter? BB */
3573 pSMB->SearchStorageType = 0;
3574 pSMB->hdr.smb_buf_length += byte_count;
3575 pSMB->ByteCount = cpu_to_le16(byte_count);
3576
3577 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3578 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003579 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
Steve French88274812006-03-09 22:21:45 +00003581 if (rc) {/* BB add logic to retry regular search if Unix search
3582 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 /* BB Add code to handle unsupported level rc */
3584 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003585
Steve French88274812006-03-09 22:21:45 +00003586 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587
3588 /* BB eventually could optimize out free and realloc of buf */
3589 /* for this case */
3590 if (rc == -EAGAIN)
3591 goto findFirstRetry;
3592 } else { /* decode response */
3593 /* BB remember to free buffer if error BB */
3594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003595 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003596 unsigned int lnoff;
3597
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003599 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 else
Steve French4b18f2a2008-04-29 00:06:05 +00003601 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
3603 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003604 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003605 psrch_inf->srch_entries_start =
3606 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3609 le16_to_cpu(pSMBr->t2.ParameterOffset));
3610
Steve French790fe572007-07-07 19:25:05 +00003611 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003612 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 else
Steve French4b18f2a2008-04-29 00:06:05 +00003614 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615
Steve French50c2f752007-07-13 00:33:32 +00003616 psrch_inf->entries_in_buffer =
3617 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003618 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003619 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003620 lnoff = le16_to_cpu(parms->LastNameOffset);
3621 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3622 lnoff) {
3623 cERROR(1, ("ignoring corrupt resume name"));
3624 psrch_inf->last_entry = NULL;
3625 return rc;
3626 }
3627
Steve French0752f152008-10-07 20:03:33 +00003628 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003629 lnoff;
3630
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 *pnetfid = parms->SearchHandle;
3632 } else {
3633 cifs_buf_release(pSMB);
3634 }
3635 }
3636
3637 return rc;
3638}
3639
3640int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003641 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642{
3643 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3644 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003645 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 char *response_data;
3647 int rc = 0;
3648 int bytes_returned, name_len;
3649 __u16 params, byte_count;
3650
3651 cFYI(1, ("In FindNext"));
3652
Steve French4b18f2a2008-04-29 00:06:05 +00003653 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 return -ENOENT;
3655
3656 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3657 (void **) &pSMBr);
3658 if (rc)
3659 return rc;
3660
Steve French50c2f752007-07-13 00:33:32 +00003661 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 byte_count = 0;
3663 pSMB->TotalDataCount = 0; /* no EAs */
3664 pSMB->MaxParameterCount = cpu_to_le16(8);
3665 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003666 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3667 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 pSMB->MaxSetupCount = 0;
3669 pSMB->Reserved = 0;
3670 pSMB->Flags = 0;
3671 pSMB->Timeout = 0;
3672 pSMB->Reserved2 = 0;
3673 pSMB->ParameterOffset = cpu_to_le16(
3674 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3675 pSMB->DataCount = 0;
3676 pSMB->DataOffset = 0;
3677 pSMB->SetupCount = 1;
3678 pSMB->Reserved3 = 0;
3679 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3680 pSMB->SearchHandle = searchHandle; /* always kept as le */
3681 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003682 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3684 pSMB->ResumeKey = psrch_inf->resume_key;
3685 pSMB->SearchFlags =
3686 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3687
3688 name_len = psrch_inf->resume_name_len;
3689 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003690 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3692 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003693 /* 14 byte parm len above enough for 2 byte null terminator */
3694 pSMB->ResumeFileName[name_len] = 0;
3695 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 } else {
3697 rc = -EINVAL;
3698 goto FNext2_err_exit;
3699 }
3700 byte_count = params + 1 /* pad */ ;
3701 pSMB->TotalParameterCount = cpu_to_le16(params);
3702 pSMB->ParameterCount = pSMB->TotalParameterCount;
3703 pSMB->hdr.smb_buf_length += byte_count;
3704 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003705
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3707 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003708 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 if (rc) {
3710 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003711 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003712 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003713 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 } else
3715 cFYI(1, ("FindNext returned = %d", rc));
3716 } else { /* decode response */
3717 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003718
Steve French790fe572007-07-07 19:25:05 +00003719 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003720 unsigned int lnoff;
3721
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 /* BB fixme add lock for file (srch_info) struct here */
3723 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003724 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 else
Steve French4b18f2a2008-04-29 00:06:05 +00003726 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 response_data = (char *) &pSMBr->hdr.Protocol +
3728 le16_to_cpu(pSMBr->t2.ParameterOffset);
3729 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3730 response_data = (char *)&pSMBr->hdr.Protocol +
3731 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003732 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003733 cifs_small_buf_release(
3734 psrch_inf->ntwrk_buf_start);
3735 else
3736 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 psrch_inf->srch_entries_start = response_data;
3738 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003739 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003740 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003741 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 else
Steve French4b18f2a2008-04-29 00:06:05 +00003743 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003744 psrch_inf->entries_in_buffer =
3745 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 psrch_inf->index_of_last_entry +=
3747 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003748 lnoff = le16_to_cpu(parms->LastNameOffset);
3749 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3750 lnoff) {
3751 cERROR(1, ("ignoring corrupt resume name"));
3752 psrch_inf->last_entry = NULL;
3753 return rc;
3754 } else
3755 psrch_inf->last_entry =
3756 psrch_inf->srch_entries_start + lnoff;
3757
Steve French50c2f752007-07-13 00:33:32 +00003758/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3759 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760
3761 /* BB fixme add unlock here */
3762 }
3763
3764 }
3765
3766 /* BB On error, should we leave previous search buf (and count and
3767 last entry fields) intact or free the previous one? */
3768
3769 /* Note: On -EAGAIN error only caller can retry on handle based calls
3770 since file handle passed in no longer valid */
3771FNext2_err_exit:
3772 if (rc != 0)
3773 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 return rc;
3775}
3776
3777int
Steve French50c2f752007-07-13 00:33:32 +00003778CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3779 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780{
3781 int rc = 0;
3782 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783
3784 cFYI(1, ("In CIFSSMBFindClose"));
3785 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3786
3787 /* no sense returning error if session restarted
3788 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003789 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 return 0;
3791 if (rc)
3792 return rc;
3793
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 pSMB->FileID = searchHandle;
3795 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003796 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003797 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003799
Steve Frencha4544342005-08-24 13:59:35 -07003800 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801
3802 /* Since session is dead, search handle closed on server already */
3803 if (rc == -EAGAIN)
3804 rc = 0;
3805
3806 return rc;
3807}
3808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809int
3810CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003811 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003812 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003813 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814{
3815 int rc = 0;
3816 TRANSACTION2_QPI_REQ *pSMB = NULL;
3817 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3818 int name_len, bytes_returned;
3819 __u16 params, byte_count;
3820
Steve French50c2f752007-07-13 00:33:32 +00003821 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003822 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003823 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824
3825GetInodeNumberRetry:
3826 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003827 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 if (rc)
3829 return rc;
3830
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3832 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003833 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003834 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 name_len++; /* trailing null */
3836 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003837 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 name_len = strnlen(searchName, PATH_MAX);
3839 name_len++; /* trailing null */
3840 strncpy(pSMB->FileName, searchName, name_len);
3841 }
3842
3843 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3844 pSMB->TotalDataCount = 0;
3845 pSMB->MaxParameterCount = cpu_to_le16(2);
3846 /* BB find exact max data count below from sess structure BB */
3847 pSMB->MaxDataCount = cpu_to_le16(4000);
3848 pSMB->MaxSetupCount = 0;
3849 pSMB->Reserved = 0;
3850 pSMB->Flags = 0;
3851 pSMB->Timeout = 0;
3852 pSMB->Reserved2 = 0;
3853 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003854 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 pSMB->DataCount = 0;
3856 pSMB->DataOffset = 0;
3857 pSMB->SetupCount = 1;
3858 pSMB->Reserved3 = 0;
3859 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3860 byte_count = params + 1 /* pad */ ;
3861 pSMB->TotalParameterCount = cpu_to_le16(params);
3862 pSMB->ParameterCount = pSMB->TotalParameterCount;
3863 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3864 pSMB->Reserved4 = 0;
3865 pSMB->hdr.smb_buf_length += byte_count;
3866 pSMB->ByteCount = cpu_to_le16(byte_count);
3867
3868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3870 if (rc) {
3871 cFYI(1, ("error %d in QueryInternalInfo", rc));
3872 } else {
3873 /* decode response */
3874 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3875 if (rc || (pSMBr->ByteCount < 2))
3876 /* BB also check enough total bytes returned */
3877 /* If rc should we check for EOPNOSUPP and
3878 disable the srvino flag? or in caller? */
3879 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003880 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3882 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003883 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003885 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3887 rc = -EIO;
3888 goto GetInodeNumOut;
3889 }
3890 pfinfo = (struct file_internal_info *)
3891 (data_offset + (char *) &pSMBr->hdr.Protocol);
3892 *inode_number = pfinfo->UniqueId;
3893 }
3894 }
3895GetInodeNumOut:
3896 cifs_buf_release(pSMB);
3897 if (rc == -EAGAIN)
3898 goto GetInodeNumberRetry;
3899 return rc;
3900}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901
Igor Mammedov2c556082008-10-23 13:58:42 +04003902/* computes length of UCS string converted to host codepage
3903 * @src: UCS string
3904 * @maxlen: length of the input string in UCS characters
3905 * (not in bytes)
3906 *
3907 * return: size of input string in host codepage
3908 */
3909static int hostlen_fromUCS(const __le16 *src, const int maxlen,
3910 const struct nls_table *nls_codepage) {
3911 int i;
3912 int hostlen = 0;
3913 char to[4];
3914 int charlen;
3915 for (i = 0; (i < maxlen) && src[i]; ++i) {
3916 charlen = nls_codepage->uni2char(le16_to_cpu(src[i]),
3917 to, NLS_MAX_CHARSET_SIZE);
3918 hostlen += charlen > 0 ? charlen : 1;
3919 }
3920 return hostlen;
3921}
3922
Igor Mammedovfec45852008-05-16 13:06:30 +04003923/* parses DFS refferal V3 structure
3924 * caller is responsible for freeing target_nodes
3925 * returns:
3926 * on success - 0
3927 * on failure - errno
3928 */
3929static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003930parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003931 unsigned int *num_of_nodes,
3932 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003933 const struct nls_table *nls_codepage, int remap,
3934 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003935{
3936 int i, rc = 0;
3937 char *data_end;
3938 bool is_unicode;
3939 struct dfs_referral_level_3 *ref;
3940
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003941 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3942 is_unicode = true;
3943 else
3944 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003945 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3946
3947 if (*num_of_nodes < 1) {
3948 cERROR(1, ("num_referrals: must be at least > 0,"
3949 "but we get num_referrals = %d\n", *num_of_nodes));
3950 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003951 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003952 }
3953
3954 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003955 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003956 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003957 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003958 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 /* get the upper boundary of the resp buffer */
3963 data_end = (char *)(&(pSMBr->PathConsumed)) +
3964 le16_to_cpu(pSMBr->t2.DataCount);
3965
3966 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3967 *num_of_nodes,
3968 le16_to_cpu(pSMBr->DFSFlags)));
3969
3970 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3971 *num_of_nodes, GFP_KERNEL);
3972 if (*target_nodes == NULL) {
3973 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3974 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003975 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003976 }
3977
3978 /* collect neccessary data from referrals */
3979 for (i = 0; i < *num_of_nodes; i++) {
3980 char *temp;
3981 int max_len;
3982 struct dfs_info3_param *node = (*target_nodes)+i;
3983
3984 node->flags = le16_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003985 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003986 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3987 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003988 cifsConvertToUCS((__le16 *) tmp, searchName,
3989 PATH_MAX, nls_codepage, remap);
3990 node->path_consumed = hostlen_fromUCS(tmp,
3991 le16_to_cpu(pSMBr->PathConsumed)/2,
3992 nls_codepage);
3993 kfree(tmp);
3994 } else
3995 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3996
Igor Mammedovfec45852008-05-16 13:06:30 +04003997 node->server_type = le16_to_cpu(ref->ServerType);
3998 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3999
4000 /* copy DfsPath */
4001 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4002 max_len = data_end - temp;
4003 rc = cifs_strncpy_to_host(&(node->path_name), temp,
4004 max_len, is_unicode, nls_codepage);
4005 if (rc)
Steve Frencha1fe78f2008-05-16 18:48:38 +00004006 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004007
4008 /* copy link target UNC */
4009 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4010 max_len = data_end - temp;
4011 rc = cifs_strncpy_to_host(&(node->node_name), temp,
4012 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
Al Viro1d92cfd2008-06-02 10:59:02 +01004016 ref += le16_to_cpu(ref->Size);
Igor Mammedovfec45852008-05-16 13:06:30 +04004017 }
4018
Steve Frencha1fe78f2008-05-16 18:48:38 +00004019parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004020 if (rc) {
4021 free_dfs_info_array(*target_nodes, *num_of_nodes);
4022 *target_nodes = NULL;
4023 *num_of_nodes = 0;
4024 }
4025 return rc;
4026}
4027
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028int
4029CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4030 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004031 struct dfs_info3_param **target_nodes,
4032 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004033 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034{
4035/* TRANS2_GET_DFS_REFERRAL */
4036 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4037 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 int rc = 0;
4039 int bytes_returned;
4040 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004042 *num_of_nodes = 0;
4043 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
4045 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4046 if (ses == NULL)
4047 return -ENODEV;
4048getDFSRetry:
4049 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4050 (void **) &pSMBr);
4051 if (rc)
4052 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004053
4054 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004055 but should never be null here anyway */
4056 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 pSMB->hdr.Tid = ses->ipc_tid;
4058 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004059 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004061 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063
4064 if (ses->capabilities & CAP_UNICODE) {
4065 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4066 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004067 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004068 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 name_len++; /* trailing null */
4070 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004071 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 name_len = strnlen(searchName, PATH_MAX);
4073 name_len++; /* trailing null */
4074 strncpy(pSMB->RequestFileName, searchName, name_len);
4075 }
4076
Steve French790fe572007-07-07 19:25:05 +00004077 if (ses->server) {
4078 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004079 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4080 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4081 }
4082
Steve French50c2f752007-07-13 00:33:32 +00004083 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004084
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 params = 2 /* level */ + name_len /*includes null */ ;
4086 pSMB->TotalDataCount = 0;
4087 pSMB->DataCount = 0;
4088 pSMB->DataOffset = 0;
4089 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004090 /* BB find exact max SMB PDU from sess structure BB */
4091 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 pSMB->MaxSetupCount = 0;
4093 pSMB->Reserved = 0;
4094 pSMB->Flags = 0;
4095 pSMB->Timeout = 0;
4096 pSMB->Reserved2 = 0;
4097 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004098 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 pSMB->SetupCount = 1;
4100 pSMB->Reserved3 = 0;
4101 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4102 byte_count = params + 3 /* pad */ ;
4103 pSMB->ParameterCount = cpu_to_le16(params);
4104 pSMB->TotalParameterCount = pSMB->ParameterCount;
4105 pSMB->MaxReferralLevel = cpu_to_le16(3);
4106 pSMB->hdr.smb_buf_length += byte_count;
4107 pSMB->ByteCount = cpu_to_le16(byte_count);
4108
4109 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4110 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4111 if (rc) {
4112 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004113 goto GetDFSRefExit;
4114 }
4115 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004117 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004118 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004119 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004120 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004122
4123 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4124 pSMBr->ByteCount,
4125 le16_to_cpu(pSMBr->t2.DataOffset)));
4126
4127 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004128 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004129 target_nodes, nls_codepage, remap,
4130 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004131
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004133 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134
4135 if (rc == -EAGAIN)
4136 goto getDFSRetry;
4137
4138 return rc;
4139}
4140
Steve French20962432005-09-21 22:05:57 -07004141/* Query File System Info such as free space to old servers such as Win 9x */
4142int
4143SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4144{
4145/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4146 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4147 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4148 FILE_SYSTEM_ALLOC_INFO *response_data;
4149 int rc = 0;
4150 int bytes_returned = 0;
4151 __u16 params, byte_count;
4152
4153 cFYI(1, ("OldQFSInfo"));
4154oldQFSInfoRetry:
4155 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4156 (void **) &pSMBr);
4157 if (rc)
4158 return rc;
Steve French20962432005-09-21 22:05:57 -07004159
4160 params = 2; /* level */
4161 pSMB->TotalDataCount = 0;
4162 pSMB->MaxParameterCount = cpu_to_le16(2);
4163 pSMB->MaxDataCount = cpu_to_le16(1000);
4164 pSMB->MaxSetupCount = 0;
4165 pSMB->Reserved = 0;
4166 pSMB->Flags = 0;
4167 pSMB->Timeout = 0;
4168 pSMB->Reserved2 = 0;
4169 byte_count = params + 1 /* pad */ ;
4170 pSMB->TotalParameterCount = cpu_to_le16(params);
4171 pSMB->ParameterCount = pSMB->TotalParameterCount;
4172 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4173 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4174 pSMB->DataCount = 0;
4175 pSMB->DataOffset = 0;
4176 pSMB->SetupCount = 1;
4177 pSMB->Reserved3 = 0;
4178 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4179 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4180 pSMB->hdr.smb_buf_length += byte_count;
4181 pSMB->ByteCount = cpu_to_le16(byte_count);
4182
4183 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4184 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4185 if (rc) {
4186 cFYI(1, ("Send error in QFSInfo = %d", rc));
4187 } else { /* decode response */
4188 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4189
4190 if (rc || (pSMBr->ByteCount < 18))
4191 rc = -EIO; /* bad smb */
4192 else {
4193 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004194 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004195 pSMBr->ByteCount, data_offset));
4196
Steve French50c2f752007-07-13 00:33:32 +00004197 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004198 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4199 FSData->f_bsize =
4200 le16_to_cpu(response_data->BytesPerSector) *
4201 le32_to_cpu(response_data->
4202 SectorsPerAllocationUnit);
4203 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004204 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004205 FSData->f_bfree = FSData->f_bavail =
4206 le32_to_cpu(response_data->FreeAllocationUnits);
4207 cFYI(1,
4208 ("Blocks: %lld Free: %lld Block size %ld",
4209 (unsigned long long)FSData->f_blocks,
4210 (unsigned long long)FSData->f_bfree,
4211 FSData->f_bsize));
4212 }
4213 }
4214 cifs_buf_release(pSMB);
4215
4216 if (rc == -EAGAIN)
4217 goto oldQFSInfoRetry;
4218
4219 return rc;
4220}
4221
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222int
Steve French737b7582005-04-28 22:41:06 -07004223CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224{
4225/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4226 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4227 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4228 FILE_SYSTEM_INFO *response_data;
4229 int rc = 0;
4230 int bytes_returned = 0;
4231 __u16 params, byte_count;
4232
4233 cFYI(1, ("In QFSInfo"));
4234QFSInfoRetry:
4235 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4236 (void **) &pSMBr);
4237 if (rc)
4238 return rc;
4239
4240 params = 2; /* level */
4241 pSMB->TotalDataCount = 0;
4242 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004243 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 pSMB->MaxSetupCount = 0;
4245 pSMB->Reserved = 0;
4246 pSMB->Flags = 0;
4247 pSMB->Timeout = 0;
4248 pSMB->Reserved2 = 0;
4249 byte_count = params + 1 /* pad */ ;
4250 pSMB->TotalParameterCount = cpu_to_le16(params);
4251 pSMB->ParameterCount = pSMB->TotalParameterCount;
4252 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004253 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 pSMB->DataCount = 0;
4255 pSMB->DataOffset = 0;
4256 pSMB->SetupCount = 1;
4257 pSMB->Reserved3 = 0;
4258 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4259 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4260 pSMB->hdr.smb_buf_length += byte_count;
4261 pSMB->ByteCount = cpu_to_le16(byte_count);
4262
4263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4265 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004266 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004268 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Steve French20962432005-09-21 22:05:57 -07004270 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 rc = -EIO; /* bad smb */
4272 else {
4273 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
4275 response_data =
4276 (FILE_SYSTEM_INFO
4277 *) (((char *) &pSMBr->hdr.Protocol) +
4278 data_offset);
4279 FSData->f_bsize =
4280 le32_to_cpu(response_data->BytesPerSector) *
4281 le32_to_cpu(response_data->
4282 SectorsPerAllocationUnit);
4283 FSData->f_blocks =
4284 le64_to_cpu(response_data->TotalAllocationUnits);
4285 FSData->f_bfree = FSData->f_bavail =
4286 le64_to_cpu(response_data->FreeAllocationUnits);
4287 cFYI(1,
4288 ("Blocks: %lld Free: %lld Block size %ld",
4289 (unsigned long long)FSData->f_blocks,
4290 (unsigned long long)FSData->f_bfree,
4291 FSData->f_bsize));
4292 }
4293 }
4294 cifs_buf_release(pSMB);
4295
4296 if (rc == -EAGAIN)
4297 goto QFSInfoRetry;
4298
4299 return rc;
4300}
4301
4302int
Steve French737b7582005-04-28 22:41:06 -07004303CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304{
4305/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4306 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4307 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4308 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4309 int rc = 0;
4310 int bytes_returned = 0;
4311 __u16 params, byte_count;
4312
4313 cFYI(1, ("In QFSAttributeInfo"));
4314QFSAttributeRetry:
4315 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4316 (void **) &pSMBr);
4317 if (rc)
4318 return rc;
4319
4320 params = 2; /* level */
4321 pSMB->TotalDataCount = 0;
4322 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004323 /* BB find exact max SMB PDU from sess structure BB */
4324 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 pSMB->MaxSetupCount = 0;
4326 pSMB->Reserved = 0;
4327 pSMB->Flags = 0;
4328 pSMB->Timeout = 0;
4329 pSMB->Reserved2 = 0;
4330 byte_count = params + 1 /* pad */ ;
4331 pSMB->TotalParameterCount = cpu_to_le16(params);
4332 pSMB->ParameterCount = pSMB->TotalParameterCount;
4333 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004334 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 pSMB->DataCount = 0;
4336 pSMB->DataOffset = 0;
4337 pSMB->SetupCount = 1;
4338 pSMB->Reserved3 = 0;
4339 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4340 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4341 pSMB->hdr.smb_buf_length += byte_count;
4342 pSMB->ByteCount = cpu_to_le16(byte_count);
4343
4344 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4345 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4346 if (rc) {
4347 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4348 } else { /* decode response */
4349 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4350
Steve French50c2f752007-07-13 00:33:32 +00004351 if (rc || (pSMBr->ByteCount < 13)) {
4352 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 rc = -EIO; /* bad smb */
4354 } else {
4355 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4356 response_data =
4357 (FILE_SYSTEM_ATTRIBUTE_INFO
4358 *) (((char *) &pSMBr->hdr.Protocol) +
4359 data_offset);
4360 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004361 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 }
4363 }
4364 cifs_buf_release(pSMB);
4365
4366 if (rc == -EAGAIN)
4367 goto QFSAttributeRetry;
4368
4369 return rc;
4370}
4371
4372int
Steve French737b7582005-04-28 22:41:06 -07004373CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374{
4375/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4376 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4377 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4378 FILE_SYSTEM_DEVICE_INFO *response_data;
4379 int rc = 0;
4380 int bytes_returned = 0;
4381 __u16 params, byte_count;
4382
4383 cFYI(1, ("In QFSDeviceInfo"));
4384QFSDeviceRetry:
4385 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4386 (void **) &pSMBr);
4387 if (rc)
4388 return rc;
4389
4390 params = 2; /* level */
4391 pSMB->TotalDataCount = 0;
4392 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004393 /* BB find exact max SMB PDU from sess structure BB */
4394 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 pSMB->MaxSetupCount = 0;
4396 pSMB->Reserved = 0;
4397 pSMB->Flags = 0;
4398 pSMB->Timeout = 0;
4399 pSMB->Reserved2 = 0;
4400 byte_count = params + 1 /* pad */ ;
4401 pSMB->TotalParameterCount = cpu_to_le16(params);
4402 pSMB->ParameterCount = pSMB->TotalParameterCount;
4403 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004404 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405
4406 pSMB->DataCount = 0;
4407 pSMB->DataOffset = 0;
4408 pSMB->SetupCount = 1;
4409 pSMB->Reserved3 = 0;
4410 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4411 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4412 pSMB->hdr.smb_buf_length += byte_count;
4413 pSMB->ByteCount = cpu_to_le16(byte_count);
4414
4415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4417 if (rc) {
4418 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4419 } else { /* decode response */
4420 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4421
Steve French630f3f0c2007-10-25 21:17:17 +00004422 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 rc = -EIO; /* bad smb */
4424 else {
4425 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4426 response_data =
Steve French737b7582005-04-28 22:41:06 -07004427 (FILE_SYSTEM_DEVICE_INFO *)
4428 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 data_offset);
4430 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004431 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 }
4433 }
4434 cifs_buf_release(pSMB);
4435
4436 if (rc == -EAGAIN)
4437 goto QFSDeviceRetry;
4438
4439 return rc;
4440}
4441
4442int
Steve French737b7582005-04-28 22:41:06 -07004443CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444{
4445/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4446 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4447 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4448 FILE_SYSTEM_UNIX_INFO *response_data;
4449 int rc = 0;
4450 int bytes_returned = 0;
4451 __u16 params, byte_count;
4452
4453 cFYI(1, ("In QFSUnixInfo"));
4454QFSUnixRetry:
4455 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4456 (void **) &pSMBr);
4457 if (rc)
4458 return rc;
4459
4460 params = 2; /* level */
4461 pSMB->TotalDataCount = 0;
4462 pSMB->DataCount = 0;
4463 pSMB->DataOffset = 0;
4464 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004465 /* BB find exact max SMB PDU from sess structure BB */
4466 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 pSMB->MaxSetupCount = 0;
4468 pSMB->Reserved = 0;
4469 pSMB->Flags = 0;
4470 pSMB->Timeout = 0;
4471 pSMB->Reserved2 = 0;
4472 byte_count = params + 1 /* pad */ ;
4473 pSMB->ParameterCount = cpu_to_le16(params);
4474 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004475 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4476 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 pSMB->SetupCount = 1;
4478 pSMB->Reserved3 = 0;
4479 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4480 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4481 pSMB->hdr.smb_buf_length += byte_count;
4482 pSMB->ByteCount = cpu_to_le16(byte_count);
4483
4484 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4485 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4486 if (rc) {
4487 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4488 } else { /* decode response */
4489 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4490
4491 if (rc || (pSMBr->ByteCount < 13)) {
4492 rc = -EIO; /* bad smb */
4493 } else {
4494 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4495 response_data =
4496 (FILE_SYSTEM_UNIX_INFO
4497 *) (((char *) &pSMBr->hdr.Protocol) +
4498 data_offset);
4499 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004500 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 }
4502 }
4503 cifs_buf_release(pSMB);
4504
4505 if (rc == -EAGAIN)
4506 goto QFSUnixRetry;
4507
4508
4509 return rc;
4510}
4511
Jeremy Allisonac670552005-06-22 17:26:35 -07004512int
Steve French45abc6e2005-06-23 13:42:03 -05004513CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004514{
4515/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4516 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4517 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4518 int rc = 0;
4519 int bytes_returned = 0;
4520 __u16 params, param_offset, offset, byte_count;
4521
4522 cFYI(1, ("In SETFSUnixInfo"));
4523SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004524 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004525 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4526 (void **) &pSMBr);
4527 if (rc)
4528 return rc;
4529
4530 params = 4; /* 2 bytes zero followed by info level. */
4531 pSMB->MaxSetupCount = 0;
4532 pSMB->Reserved = 0;
4533 pSMB->Flags = 0;
4534 pSMB->Timeout = 0;
4535 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004536 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4537 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004538 offset = param_offset + params;
4539
4540 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004541 /* BB find exact max SMB PDU from sess structure BB */
4542 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004543 pSMB->SetupCount = 1;
4544 pSMB->Reserved3 = 0;
4545 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4546 byte_count = 1 /* pad */ + params + 12;
4547
4548 pSMB->DataCount = cpu_to_le16(12);
4549 pSMB->ParameterCount = cpu_to_le16(params);
4550 pSMB->TotalDataCount = pSMB->DataCount;
4551 pSMB->TotalParameterCount = pSMB->ParameterCount;
4552 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4553 pSMB->DataOffset = cpu_to_le16(offset);
4554
4555 /* Params. */
4556 pSMB->FileNum = 0;
4557 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4558
4559 /* Data. */
4560 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4561 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4562 pSMB->ClientUnixCap = cpu_to_le64(cap);
4563
4564 pSMB->hdr.smb_buf_length += byte_count;
4565 pSMB->ByteCount = cpu_to_le16(byte_count);
4566
4567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4569 if (rc) {
4570 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4571 } else { /* decode response */
4572 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004573 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004574 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004575 }
4576 cifs_buf_release(pSMB);
4577
4578 if (rc == -EAGAIN)
4579 goto SETFSUnixRetry;
4580
4581 return rc;
4582}
4583
4584
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585
4586int
4587CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004588 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589{
4590/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4591 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4592 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4593 FILE_SYSTEM_POSIX_INFO *response_data;
4594 int rc = 0;
4595 int bytes_returned = 0;
4596 __u16 params, byte_count;
4597
4598 cFYI(1, ("In QFSPosixInfo"));
4599QFSPosixRetry:
4600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4601 (void **) &pSMBr);
4602 if (rc)
4603 return rc;
4604
4605 params = 2; /* level */
4606 pSMB->TotalDataCount = 0;
4607 pSMB->DataCount = 0;
4608 pSMB->DataOffset = 0;
4609 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004610 /* BB find exact max SMB PDU from sess structure BB */
4611 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 pSMB->MaxSetupCount = 0;
4613 pSMB->Reserved = 0;
4614 pSMB->Flags = 0;
4615 pSMB->Timeout = 0;
4616 pSMB->Reserved2 = 0;
4617 byte_count = params + 1 /* pad */ ;
4618 pSMB->ParameterCount = cpu_to_le16(params);
4619 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004620 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4621 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 pSMB->SetupCount = 1;
4623 pSMB->Reserved3 = 0;
4624 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4625 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4626 pSMB->hdr.smb_buf_length += byte_count;
4627 pSMB->ByteCount = cpu_to_le16(byte_count);
4628
4629 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4630 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4631 if (rc) {
4632 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4633 } else { /* decode response */
4634 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4635
4636 if (rc || (pSMBr->ByteCount < 13)) {
4637 rc = -EIO; /* bad smb */
4638 } else {
4639 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4640 response_data =
4641 (FILE_SYSTEM_POSIX_INFO
4642 *) (((char *) &pSMBr->hdr.Protocol) +
4643 data_offset);
4644 FSData->f_bsize =
4645 le32_to_cpu(response_data->BlockSize);
4646 FSData->f_blocks =
4647 le64_to_cpu(response_data->TotalBlocks);
4648 FSData->f_bfree =
4649 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004650 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 FSData->f_bavail = FSData->f_bfree;
4652 } else {
4653 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004654 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655 }
Steve French790fe572007-07-07 19:25:05 +00004656 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004658 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004659 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004661 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 }
4663 }
4664 cifs_buf_release(pSMB);
4665
4666 if (rc == -EAGAIN)
4667 goto QFSPosixRetry;
4668
4669 return rc;
4670}
4671
4672
Steve French50c2f752007-07-13 00:33:32 +00004673/* We can not use write of zero bytes trick to
4674 set file size due to need for large file support. Also note that
4675 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 routine which is only needed to work around a sharing violation bug
4677 in Samba which this routine can run into */
4678
4679int
4680CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004681 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004682 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683{
4684 struct smb_com_transaction2_spi_req *pSMB = NULL;
4685 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4686 struct file_end_of_file_info *parm_data;
4687 int name_len;
4688 int rc = 0;
4689 int bytes_returned = 0;
4690 __u16 params, byte_count, data_count, param_offset, offset;
4691
4692 cFYI(1, ("In SetEOF"));
4693SetEOFRetry:
4694 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4695 (void **) &pSMBr);
4696 if (rc)
4697 return rc;
4698
4699 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4700 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004701 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004702 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 name_len++; /* trailing null */
4704 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004705 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 name_len = strnlen(fileName, PATH_MAX);
4707 name_len++; /* trailing null */
4708 strncpy(pSMB->FileName, fileName, name_len);
4709 }
4710 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004711 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004713 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 pSMB->MaxSetupCount = 0;
4715 pSMB->Reserved = 0;
4716 pSMB->Flags = 0;
4717 pSMB->Timeout = 0;
4718 pSMB->Reserved2 = 0;
4719 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004720 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004722 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004723 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4724 pSMB->InformationLevel =
4725 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4726 else
4727 pSMB->InformationLevel =
4728 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4729 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4731 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004732 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 else
4734 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004735 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 }
4737
4738 parm_data =
4739 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4740 offset);
4741 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4742 pSMB->DataOffset = cpu_to_le16(offset);
4743 pSMB->SetupCount = 1;
4744 pSMB->Reserved3 = 0;
4745 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4746 byte_count = 3 /* pad */ + params + data_count;
4747 pSMB->DataCount = cpu_to_le16(data_count);
4748 pSMB->TotalDataCount = pSMB->DataCount;
4749 pSMB->ParameterCount = cpu_to_le16(params);
4750 pSMB->TotalParameterCount = pSMB->ParameterCount;
4751 pSMB->Reserved4 = 0;
4752 pSMB->hdr.smb_buf_length += byte_count;
4753 parm_data->FileSize = cpu_to_le64(size);
4754 pSMB->ByteCount = cpu_to_le16(byte_count);
4755 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4756 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004757 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759
4760 cifs_buf_release(pSMB);
4761
4762 if (rc == -EAGAIN)
4763 goto SetEOFRetry;
4764
4765 return rc;
4766}
4767
4768int
Steve French50c2f752007-07-13 00:33:32 +00004769CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004770 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771{
4772 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 char *data_offset;
4774 struct file_end_of_file_info *parm_data;
4775 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 __u16 params, param_offset, offset, byte_count, count;
4777
4778 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4779 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004780 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4781
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 if (rc)
4783 return rc;
4784
4785 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4786 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004787
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 params = 6;
4789 pSMB->MaxSetupCount = 0;
4790 pSMB->Reserved = 0;
4791 pSMB->Flags = 0;
4792 pSMB->Timeout = 0;
4793 pSMB->Reserved2 = 0;
4794 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4795 offset = param_offset + params;
4796
Steve French50c2f752007-07-13 00:33:32 +00004797 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798
4799 count = sizeof(struct file_end_of_file_info);
4800 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004801 /* BB find exact max SMB PDU from sess structure BB */
4802 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 pSMB->SetupCount = 1;
4804 pSMB->Reserved3 = 0;
4805 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4806 byte_count = 3 /* pad */ + params + count;
4807 pSMB->DataCount = cpu_to_le16(count);
4808 pSMB->ParameterCount = cpu_to_le16(params);
4809 pSMB->TotalDataCount = pSMB->DataCount;
4810 pSMB->TotalParameterCount = pSMB->ParameterCount;
4811 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4812 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004813 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4814 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 pSMB->DataOffset = cpu_to_le16(offset);
4816 parm_data->FileSize = cpu_to_le64(size);
4817 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004818 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4820 pSMB->InformationLevel =
4821 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4822 else
4823 pSMB->InformationLevel =
4824 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004825 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4827 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004828 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 else
4830 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004831 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 }
4833 pSMB->Reserved4 = 0;
4834 pSMB->hdr.smb_buf_length += byte_count;
4835 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004836 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 if (rc) {
4838 cFYI(1,
4839 ("Send error in SetFileInfo (SetFileSize) = %d",
4840 rc));
4841 }
4842
Steve French50c2f752007-07-13 00:33:32 +00004843 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 since file handle passed in no longer valid */
4845
4846 return rc;
4847}
4848
Steve French50c2f752007-07-13 00:33:32 +00004849/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 an open handle, rather than by pathname - this is awkward due to
4851 potential access conflicts on the open, but it is unavoidable for these
4852 old servers since the only other choice is to go from 100 nanosecond DCE
4853 time and resort to the original setpathinfo level which takes the ancient
4854 DOS time format with 2 second granularity */
4855int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004856CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4857 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858{
4859 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 char *data_offset;
4861 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 __u16 params, param_offset, offset, byte_count, count;
4863
4864 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004865 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4866
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 if (rc)
4868 return rc;
4869
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004870 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4871 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004872
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 params = 6;
4874 pSMB->MaxSetupCount = 0;
4875 pSMB->Reserved = 0;
4876 pSMB->Flags = 0;
4877 pSMB->Timeout = 0;
4878 pSMB->Reserved2 = 0;
4879 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4880 offset = param_offset + params;
4881
Steve French50c2f752007-07-13 00:33:32 +00004882 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883
Steve French26f57362007-08-30 22:09:15 +00004884 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004886 /* BB find max SMB PDU from sess */
4887 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 pSMB->SetupCount = 1;
4889 pSMB->Reserved3 = 0;
4890 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4891 byte_count = 3 /* pad */ + params + count;
4892 pSMB->DataCount = cpu_to_le16(count);
4893 pSMB->ParameterCount = cpu_to_le16(params);
4894 pSMB->TotalDataCount = pSMB->DataCount;
4895 pSMB->TotalParameterCount = pSMB->ParameterCount;
4896 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4897 pSMB->DataOffset = cpu_to_le16(offset);
4898 pSMB->Fid = fid;
4899 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4900 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4901 else
4902 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4903 pSMB->Reserved4 = 0;
4904 pSMB->hdr.smb_buf_length += byte_count;
4905 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004906 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004907 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004908 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004909 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910
Steve French50c2f752007-07-13 00:33:32 +00004911 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 since file handle passed in no longer valid */
4913
4914 return rc;
4915}
4916
Jeff Layton6d22f092008-09-23 11:48:35 -04004917int
4918CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4919 bool delete_file, __u16 fid, __u32 pid_of_opener)
4920{
4921 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4922 char *data_offset;
4923 int rc = 0;
4924 __u16 params, param_offset, offset, byte_count, count;
4925
4926 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4927 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4928
4929 if (rc)
4930 return rc;
4931
4932 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4933 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4934
4935 params = 6;
4936 pSMB->MaxSetupCount = 0;
4937 pSMB->Reserved = 0;
4938 pSMB->Flags = 0;
4939 pSMB->Timeout = 0;
4940 pSMB->Reserved2 = 0;
4941 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4942 offset = param_offset + params;
4943
4944 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4945
4946 count = 1;
4947 pSMB->MaxParameterCount = cpu_to_le16(2);
4948 /* BB find max SMB PDU from sess */
4949 pSMB->MaxDataCount = cpu_to_le16(1000);
4950 pSMB->SetupCount = 1;
4951 pSMB->Reserved3 = 0;
4952 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4953 byte_count = 3 /* pad */ + params + count;
4954 pSMB->DataCount = cpu_to_le16(count);
4955 pSMB->ParameterCount = cpu_to_le16(params);
4956 pSMB->TotalDataCount = pSMB->DataCount;
4957 pSMB->TotalParameterCount = pSMB->ParameterCount;
4958 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4959 pSMB->DataOffset = cpu_to_le16(offset);
4960 pSMB->Fid = fid;
4961 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4962 pSMB->Reserved4 = 0;
4963 pSMB->hdr.smb_buf_length += byte_count;
4964 pSMB->ByteCount = cpu_to_le16(byte_count);
4965 *data_offset = delete_file ? 1 : 0;
4966 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4967 if (rc)
4968 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4969
4970 return rc;
4971}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972
4973int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004974CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4975 const char *fileName, const FILE_BASIC_INFO *data,
4976 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977{
4978 TRANSACTION2_SPI_REQ *pSMB = NULL;
4979 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4980 int name_len;
4981 int rc = 0;
4982 int bytes_returned = 0;
4983 char *data_offset;
4984 __u16 params, param_offset, offset, byte_count, count;
4985
4986 cFYI(1, ("In SetTimes"));
4987
4988SetTimesRetry:
4989 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4990 (void **) &pSMBr);
4991 if (rc)
4992 return rc;
4993
4994 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4995 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004996 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004997 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 name_len++; /* trailing null */
4999 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005000 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 name_len = strnlen(fileName, PATH_MAX);
5002 name_len++; /* trailing null */
5003 strncpy(pSMB->FileName, fileName, name_len);
5004 }
5005
5006 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005007 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005009 /* BB find max SMB PDU from sess structure BB */
5010 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 pSMB->MaxSetupCount = 0;
5012 pSMB->Reserved = 0;
5013 pSMB->Flags = 0;
5014 pSMB->Timeout = 0;
5015 pSMB->Reserved2 = 0;
5016 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005017 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 offset = param_offset + params;
5019 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5020 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5021 pSMB->DataOffset = cpu_to_le16(offset);
5022 pSMB->SetupCount = 1;
5023 pSMB->Reserved3 = 0;
5024 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5025 byte_count = 3 /* pad */ + params + count;
5026
5027 pSMB->DataCount = cpu_to_le16(count);
5028 pSMB->ParameterCount = cpu_to_le16(params);
5029 pSMB->TotalDataCount = pSMB->DataCount;
5030 pSMB->TotalParameterCount = pSMB->ParameterCount;
5031 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5032 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5033 else
5034 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5035 pSMB->Reserved4 = 0;
5036 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005037 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 pSMB->ByteCount = cpu_to_le16(byte_count);
5039 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5040 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005041 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043
5044 cifs_buf_release(pSMB);
5045
5046 if (rc == -EAGAIN)
5047 goto SetTimesRetry;
5048
5049 return rc;
5050}
5051
5052/* Can not be used to set time stamps yet (due to old DOS time format) */
5053/* Can be used to set attributes */
5054#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5055 handling it anyway and NT4 was what we thought it would be needed for
5056 Do not delete it until we prove whether needed for Win9x though */
5057int
5058CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5059 __u16 dos_attrs, const struct nls_table *nls_codepage)
5060{
5061 SETATTR_REQ *pSMB = NULL;
5062 SETATTR_RSP *pSMBr = NULL;
5063 int rc = 0;
5064 int bytes_returned;
5065 int name_len;
5066
5067 cFYI(1, ("In SetAttrLegacy"));
5068
5069SetAttrLgcyRetry:
5070 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5071 (void **) &pSMBr);
5072 if (rc)
5073 return rc;
5074
5075 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5076 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005077 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 PATH_MAX, nls_codepage);
5079 name_len++; /* trailing null */
5080 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005081 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082 name_len = strnlen(fileName, PATH_MAX);
5083 name_len++; /* trailing null */
5084 strncpy(pSMB->fileName, fileName, name_len);
5085 }
5086 pSMB->attr = cpu_to_le16(dos_attrs);
5087 pSMB->BufferFormat = 0x04;
5088 pSMB->hdr.smb_buf_length += name_len + 1;
5089 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005092 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094
5095 cifs_buf_release(pSMB);
5096
5097 if (rc == -EAGAIN)
5098 goto SetAttrLgcyRetry;
5099
5100 return rc;
5101}
5102#endif /* temporarily unneeded SetAttr legacy function */
5103
5104int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005105CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005106 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005107 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108{
5109 TRANSACTION2_SPI_REQ *pSMB = NULL;
5110 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5111 int name_len;
5112 int rc = 0;
5113 int bytes_returned = 0;
5114 FILE_UNIX_BASIC_INFO *data_offset;
5115 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005116 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117
5118 cFYI(1, ("In SetUID/GID/Mode"));
5119setPermsRetry:
5120 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5121 (void **) &pSMBr);
5122 if (rc)
5123 return rc;
5124
5125 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5126 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005127 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005128 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 name_len++; /* trailing null */
5130 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005131 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005132 name_len = strnlen(fileName, PATH_MAX);
5133 name_len++; /* trailing null */
5134 strncpy(pSMB->FileName, fileName, name_len);
5135 }
5136
5137 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005138 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005140 /* BB find max SMB PDU from sess structure BB */
5141 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 pSMB->MaxSetupCount = 0;
5143 pSMB->Reserved = 0;
5144 pSMB->Flags = 0;
5145 pSMB->Timeout = 0;
5146 pSMB->Reserved2 = 0;
5147 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005148 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 offset = param_offset + params;
5150 data_offset =
5151 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5152 offset);
5153 memset(data_offset, 0, count);
5154 pSMB->DataOffset = cpu_to_le16(offset);
5155 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5156 pSMB->SetupCount = 1;
5157 pSMB->Reserved3 = 0;
5158 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5159 byte_count = 3 /* pad */ + params + count;
5160 pSMB->ParameterCount = cpu_to_le16(params);
5161 pSMB->DataCount = cpu_to_le16(count);
5162 pSMB->TotalParameterCount = pSMB->ParameterCount;
5163 pSMB->TotalDataCount = pSMB->DataCount;
5164 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5165 pSMB->Reserved4 = 0;
5166 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005167 /* Samba server ignores set of file size to zero due to bugs in some
5168 older clients, but we should be precise - we use SetFileSize to
5169 set file size and do not want to truncate file size to zero
5170 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005171 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005172 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5173 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5174 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5175 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5176 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5177 data_offset->Uid = cpu_to_le64(args->uid);
5178 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005180 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5181 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005183
Steve French790fe572007-07-07 19:25:05 +00005184 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005186 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005188 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005190 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005192 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005194 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005196 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5198
5199
5200 pSMB->ByteCount = cpu_to_le16(byte_count);
5201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005203 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205
Steve French0d817bc2008-05-22 02:02:03 +00005206 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 if (rc == -EAGAIN)
5208 goto setPermsRetry;
5209 return rc;
5210}
5211
Steve French50c2f752007-07-13 00:33:32 +00005212int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005213 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005214 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005215 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216{
5217 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005218 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5219 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005220 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 int bytes_returned;
5222
Steve French50c2f752007-07-13 00:33:32 +00005223 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005225 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 if (rc)
5227 return rc;
5228
5229 pSMB->TotalParameterCount = 0 ;
5230 pSMB->TotalDataCount = 0;
5231 pSMB->MaxParameterCount = cpu_to_le32(2);
5232 /* BB find exact data count max from sess structure BB */
5233 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005234/* BB VERIFY verify which is correct for above BB */
5235 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5236 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5237
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 pSMB->MaxSetupCount = 4;
5239 pSMB->Reserved = 0;
5240 pSMB->ParameterOffset = 0;
5241 pSMB->DataCount = 0;
5242 pSMB->DataOffset = 0;
5243 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5244 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5245 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005246 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5248 pSMB->Reserved2 = 0;
5249 pSMB->CompletionFilter = cpu_to_le32(filter);
5250 pSMB->Fid = netfid; /* file handle always le */
5251 pSMB->ByteCount = 0;
5252
5253 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005254 (struct smb_hdr *)pSMBr, &bytes_returned,
5255 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 if (rc) {
5257 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005258 } else {
5259 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005260 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005261 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005262 sizeof(struct dir_notify_req),
5263 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005264 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005265 dnotify_req->Pid = pSMB->hdr.Pid;
5266 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5267 dnotify_req->Mid = pSMB->hdr.Mid;
5268 dnotify_req->Tid = pSMB->hdr.Tid;
5269 dnotify_req->Uid = pSMB->hdr.Uid;
5270 dnotify_req->netfid = netfid;
5271 dnotify_req->pfile = pfile;
5272 dnotify_req->filter = filter;
5273 dnotify_req->multishot = multishot;
5274 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005275 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005276 &GlobalDnotifyReqList);
5277 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005278 } else
Steve French47c786e2005-10-11 20:03:18 -07005279 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 }
5281 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005282 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283}
5284#ifdef CONFIG_CIFS_XATTR
5285ssize_t
5286CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5287 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005288 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005289 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290{
5291 /* BB assumes one setup word */
5292 TRANSACTION2_QPI_REQ *pSMB = NULL;
5293 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5294 int rc = 0;
5295 int bytes_returned;
5296 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005297 struct fea *temp_fea;
5298 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 __u16 params, byte_count;
5300
5301 cFYI(1, ("In Query All EAs path %s", searchName));
5302QAllEAsRetry:
5303 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5304 (void **) &pSMBr);
5305 if (rc)
5306 return rc;
5307
5308 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5309 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005310 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005311 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 name_len++; /* trailing null */
5313 name_len *= 2;
5314 } else { /* BB improve the check for buffer overruns BB */
5315 name_len = strnlen(searchName, PATH_MAX);
5316 name_len++; /* trailing null */
5317 strncpy(pSMB->FileName, searchName, name_len);
5318 }
5319
Steve French50c2f752007-07-13 00:33:32 +00005320 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 pSMB->TotalDataCount = 0;
5322 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005323 /* BB find exact max SMB PDU from sess structure BB */
5324 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 pSMB->MaxSetupCount = 0;
5326 pSMB->Reserved = 0;
5327 pSMB->Flags = 0;
5328 pSMB->Timeout = 0;
5329 pSMB->Reserved2 = 0;
5330 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005331 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 pSMB->DataCount = 0;
5333 pSMB->DataOffset = 0;
5334 pSMB->SetupCount = 1;
5335 pSMB->Reserved3 = 0;
5336 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5337 byte_count = params + 1 /* pad */ ;
5338 pSMB->TotalParameterCount = cpu_to_le16(params);
5339 pSMB->ParameterCount = pSMB->TotalParameterCount;
5340 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5341 pSMB->Reserved4 = 0;
5342 pSMB->hdr.smb_buf_length += byte_count;
5343 pSMB->ByteCount = cpu_to_le16(byte_count);
5344
5345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5347 if (rc) {
5348 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5349 } else { /* decode response */
5350 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5351
5352 /* BB also check enough total bytes returned */
5353 /* BB we need to improve the validity checking
5354 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005355 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 rc = -EIO; /* bad smb */
5357 /* else if (pFindData){
5358 memcpy((char *) pFindData,
5359 (char *) &pSMBr->hdr.Protocol +
5360 data_offset, kl);
5361 }*/ else {
5362 /* check that length of list is not more than bcc */
5363 /* check that each entry does not go beyond length
5364 of list */
5365 /* check that each element of each entry does not
5366 go beyond end of list */
5367 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005368 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 rc = 0;
5370 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005371 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 ea_response_data = (struct fealist *)
5373 (((char *) &pSMBr->hdr.Protocol) +
5374 data_offset);
5375 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005376 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005377 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005379 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 } else {
5381 /* account for ea list len */
5382 name_len -= 4;
5383 temp_fea = ea_response_data->list;
5384 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005385 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386 __u16 value_len;
5387 name_len -= 4;
5388 temp_ptr += 4;
5389 rc += temp_fea->name_len;
5390 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005391 rc = rc + 5 + 1;
5392 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005393 memcpy(EAData, "user.", 5);
5394 EAData += 5;
5395 memcpy(EAData, temp_ptr,
5396 temp_fea->name_len);
5397 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 /* null terminate name */
5399 *EAData = 0;
5400 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005401 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 /* skip copy - calc size only */
5403 } else {
5404 /* stop before overrun buffer */
5405 rc = -ERANGE;
5406 break;
5407 }
5408 name_len -= temp_fea->name_len;
5409 temp_ptr += temp_fea->name_len;
5410 /* account for trailing null */
5411 name_len--;
5412 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005413 value_len =
5414 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 name_len -= value_len;
5416 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005417 /* BB check that temp_ptr is still
5418 within the SMB BB*/
5419
5420 /* no trailing null to account for
5421 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 /* go on to next EA */
5423 temp_fea = (struct fea *)temp_ptr;
5424 }
5425 }
5426 }
5427 }
Steve French0d817bc2008-05-22 02:02:03 +00005428 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 if (rc == -EAGAIN)
5430 goto QAllEAsRetry;
5431
5432 return (ssize_t)rc;
5433}
5434
Steve French50c2f752007-07-13 00:33:32 +00005435ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5436 const unsigned char *searchName, const unsigned char *ea_name,
5437 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005438 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439{
5440 TRANSACTION2_QPI_REQ *pSMB = NULL;
5441 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5442 int rc = 0;
5443 int bytes_returned;
5444 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005445 struct fea *temp_fea;
5446 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 __u16 params, byte_count;
5448
5449 cFYI(1, ("In Query EA path %s", searchName));
5450QEARetry:
5451 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5452 (void **) &pSMBr);
5453 if (rc)
5454 return rc;
5455
5456 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5457 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005458 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005459 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 name_len++; /* trailing null */
5461 name_len *= 2;
5462 } else { /* BB improve the check for buffer overruns BB */
5463 name_len = strnlen(searchName, PATH_MAX);
5464 name_len++; /* trailing null */
5465 strncpy(pSMB->FileName, searchName, name_len);
5466 }
5467
Steve French50c2f752007-07-13 00:33:32 +00005468 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 pSMB->TotalDataCount = 0;
5470 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005471 /* BB find exact max SMB PDU from sess structure BB */
5472 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 pSMB->MaxSetupCount = 0;
5474 pSMB->Reserved = 0;
5475 pSMB->Flags = 0;
5476 pSMB->Timeout = 0;
5477 pSMB->Reserved2 = 0;
5478 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005479 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 pSMB->DataCount = 0;
5481 pSMB->DataOffset = 0;
5482 pSMB->SetupCount = 1;
5483 pSMB->Reserved3 = 0;
5484 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5485 byte_count = params + 1 /* pad */ ;
5486 pSMB->TotalParameterCount = cpu_to_le16(params);
5487 pSMB->ParameterCount = pSMB->TotalParameterCount;
5488 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5489 pSMB->Reserved4 = 0;
5490 pSMB->hdr.smb_buf_length += byte_count;
5491 pSMB->ByteCount = cpu_to_le16(byte_count);
5492
5493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5495 if (rc) {
5496 cFYI(1, ("Send error in Query EA = %d", rc));
5497 } else { /* decode response */
5498 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5499
5500 /* BB also check enough total bytes returned */
5501 /* BB we need to improve the validity checking
5502 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005503 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 rc = -EIO; /* bad smb */
5505 /* else if (pFindData){
5506 memcpy((char *) pFindData,
5507 (char *) &pSMBr->hdr.Protocol +
5508 data_offset, kl);
5509 }*/ else {
5510 /* check that length of list is not more than bcc */
5511 /* check that each entry does not go beyond length
5512 of list */
5513 /* check that each element of each entry does not
5514 go beyond end of list */
5515 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005516 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 rc = -ENODATA;
5518 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005519 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 ea_response_data = (struct fealist *)
5521 (((char *) &pSMBr->hdr.Protocol) +
5522 data_offset);
5523 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005524 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005525 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005527 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 } else {
5529 /* account for ea list len */
5530 name_len -= 4;
5531 temp_fea = ea_response_data->list;
5532 temp_ptr = (char *)temp_fea;
5533 /* loop through checking if we have a matching
5534 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005535 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 __u16 value_len;
5537 name_len -= 4;
5538 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005539 value_len =
5540 le16_to_cpu(temp_fea->value_len);
5541 /* BB validate that value_len falls within SMB,
5542 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005543 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 temp_fea->name_len) == 0) {
5545 /* found a match */
5546 rc = value_len;
5547 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005548 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 memcpy(ea_value,
5550 temp_fea->name+temp_fea->name_len+1,
5551 rc);
Steve French50c2f752007-07-13 00:33:32 +00005552 /* ea values, unlike ea
5553 names, are not null
5554 terminated */
Steve French790fe572007-07-07 19:25:05 +00005555 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 /* skip copy - calc size only */
5557 } else {
Steve French50c2f752007-07-13 00:33:32 +00005558 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 rc = -ERANGE;
5560 }
5561 break;
5562 }
5563 name_len -= temp_fea->name_len;
5564 temp_ptr += temp_fea->name_len;
5565 /* account for trailing null */
5566 name_len--;
5567 temp_ptr++;
5568 name_len -= value_len;
5569 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005570 /* No trailing null to account for in
5571 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 temp_fea = (struct fea *)temp_ptr;
5573 }
Steve French50c2f752007-07-13 00:33:32 +00005574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 }
5576 }
Steve French0d817bc2008-05-22 02:02:03 +00005577 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 if (rc == -EAGAIN)
5579 goto QEARetry;
5580
5581 return (ssize_t)rc;
5582}
5583
5584int
5585CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005586 const char *ea_name, const void *ea_value,
5587 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5588 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589{
5590 struct smb_com_transaction2_spi_req *pSMB = NULL;
5591 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5592 struct fealist *parm_data;
5593 int name_len;
5594 int rc = 0;
5595 int bytes_returned = 0;
5596 __u16 params, param_offset, byte_count, offset, count;
5597
5598 cFYI(1, ("In SetEA"));
5599SetEARetry:
5600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5601 (void **) &pSMBr);
5602 if (rc)
5603 return rc;
5604
5605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5606 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005607 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005608 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 name_len++; /* trailing null */
5610 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005611 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 name_len = strnlen(fileName, PATH_MAX);
5613 name_len++; /* trailing null */
5614 strncpy(pSMB->FileName, fileName, name_len);
5615 }
5616
5617 params = 6 + name_len;
5618
5619 /* done calculating parms using name_len of file name,
5620 now use name_len to calculate length of ea name
5621 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005622 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 name_len = 0;
5624 else
Steve French50c2f752007-07-13 00:33:32 +00005625 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005627 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005629 /* BB find max SMB PDU from sess */
5630 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 pSMB->MaxSetupCount = 0;
5632 pSMB->Reserved = 0;
5633 pSMB->Flags = 0;
5634 pSMB->Timeout = 0;
5635 pSMB->Reserved2 = 0;
5636 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005637 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 offset = param_offset + params;
5639 pSMB->InformationLevel =
5640 cpu_to_le16(SMB_SET_FILE_EA);
5641
5642 parm_data =
5643 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5644 offset);
5645 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5646 pSMB->DataOffset = cpu_to_le16(offset);
5647 pSMB->SetupCount = 1;
5648 pSMB->Reserved3 = 0;
5649 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5650 byte_count = 3 /* pad */ + params + count;
5651 pSMB->DataCount = cpu_to_le16(count);
5652 parm_data->list_len = cpu_to_le32(count);
5653 parm_data->list[0].EA_flags = 0;
5654 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005655 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005657 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005658 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 parm_data->list[0].name[name_len] = 0;
5660 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5661 /* caller ensures that ea_value_len is less than 64K but
5662 we need to ensure that it fits within the smb */
5663
Steve French50c2f752007-07-13 00:33:32 +00005664 /*BB add length check to see if it would fit in
5665 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005666 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5667 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005668 memcpy(parm_data->list[0].name+name_len+1,
5669 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670
5671 pSMB->TotalDataCount = pSMB->DataCount;
5672 pSMB->ParameterCount = cpu_to_le16(params);
5673 pSMB->TotalParameterCount = pSMB->ParameterCount;
5674 pSMB->Reserved4 = 0;
5675 pSMB->hdr.smb_buf_length += byte_count;
5676 pSMB->ByteCount = cpu_to_le16(byte_count);
5677 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005679 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
5682 cifs_buf_release(pSMB);
5683
5684 if (rc == -EAGAIN)
5685 goto SetEARetry;
5686
5687 return rc;
5688}
5689
5690#endif