blob: dfb8e391d538418f0da7a77c5f7005e3c2237689 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000086static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000089 struct list_head *tmp;
90 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92/* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000095 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000096 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 }
98 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070099 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101}
102
Steve Frenchad7a2922008-02-07 23:25:02 +0000103/* Allocate and return pointer to an SMB request buffer, and set basic
104 SMB information in the SMB header. If the return code is zero, this
105 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000108 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000142 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000158 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000161 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700166 /* BB FIXME add code to check if wsize needs
167 update due to negotiated smb buffer size
168 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000169 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000171 /* tell server Unix caps we support */
172 if (tcon->ses->capabilities & CAP_UNIX)
173 reset_cifs_unix_caps(
174 0 /* no xid */,
175 tcon,
176 NULL /* we do not know sb */,
177 NULL /* no vol info */);
178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000181 /* Removed call to reopen open files here.
182 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700183 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Steve French50c2f752007-07-13 00:33:32 +0000185 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700186 know whether we can continue or not without
187 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000188 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 case SMB_COM_READ_ANDX:
190 case SMB_COM_WRITE_ANDX:
191 case SMB_COM_CLOSE:
192 case SMB_COM_FIND_CLOSE2:
193 case SMB_COM_LOCKING_ANDX: {
194 unload_nls(nls_codepage);
195 return -EAGAIN;
196 }
197 }
198 } else {
199 up(&tcon->ses->sesSem);
200 }
201 unload_nls(nls_codepage);
202
203 } else {
204 return -EIO;
205 }
206 }
Steve French790fe572007-07-07 19:25:05 +0000207 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 return rc;
209
210 *request_buf = cifs_small_buf_get();
211 if (*request_buf == NULL) {
212 /* BB should we add a retry in here if not a writepage? */
213 return -ENOMEM;
214 }
215
Steve French63135e02007-07-17 17:34:02 +0000216 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000217 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Steve French790fe572007-07-07 19:25:05 +0000219 if (tcon != NULL)
220 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000223}
224
Steve French12b3b8f2006-02-09 21:12:47 +0000225int
Steve French50c2f752007-07-13 00:33:32 +0000226small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000227 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000228{
229 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000230 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000231
Steve French5815449d2006-02-14 01:36:20 +0000232 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000233 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000234 return rc;
235
Steve French04fdabe2006-02-10 05:52:50 +0000236 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000237 buffer->Mid = GetNextMid(ses->server);
238 if (ses->capabilities & CAP_UNICODE)
239 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000240 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000241 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
242
243 /* uid, tid can stay at zero as set in header assemble */
244
Steve French50c2f752007-07-13 00:33:32 +0000245 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000246 this function is used after 1st of session setup requests */
247
248 return rc;
249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251/* If the return code is zero, this function must fill in request_buf pointer */
252static int
253smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
254 void **request_buf /* returned */ ,
255 void **response_buf /* returned */ )
256{
257 int rc = 0;
258
259 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
260 check for tcp and smb session status done differently
261 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000262 if (tcon) {
Steve Frenchbfb598202008-11-18 16:33:48 +0000263 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800264 /* only tree disconnect, open, and write,
265 (and ulogoff which does not have tcon)
266 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000267 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800268 (smb_command != SMB_COM_OPEN_ANDX) &&
269 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000270 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800271 smb_command));
272 return -ENODEV;
273 }
274 }
275
Steve French790fe572007-07-07 19:25:05 +0000276 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000277 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700279 /* Give Demultiplex thread up to 10 seconds to
280 reconnect, should be greater than cifs socket
281 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000282 while (tcon->ses->server->tcpStatus ==
283 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000285 (tcon->ses->server->tcpStatus ==
286 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000287 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700288 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000290 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000292 cFYI(1, ("gave up waiting on "
293 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700295 } /* else "hard" mount - keep retrying
296 until process is killed or server
297 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 } else /* TCP session is reestablished now */
299 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 nls_codepage = load_nls_default();
302 /* need to prevent multiple threads trying to
303 simultaneously reconnect the same SMB session */
304 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000305 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000306 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700307 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000308 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700310 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
311 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000316 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000318 /* tell server Unix caps we support */
319 if (tcon->ses->capabilities & CAP_UNIX)
320 reset_cifs_unix_caps(
321 0 /* no xid */,
322 tcon,
323 NULL /* do not know sb */,
324 NULL /* no vol info */);
325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Removed call to reopen open files here.
329 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700330 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Steve French50c2f752007-07-13 00:33:32 +0000332 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700333 know whether we can continue or not without
334 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000335 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 case SMB_COM_READ_ANDX:
337 case SMB_COM_WRITE_ANDX:
338 case SMB_COM_CLOSE:
339 case SMB_COM_FIND_CLOSE2:
340 case SMB_COM_LOCKING_ANDX: {
341 unload_nls(nls_codepage);
342 return -EAGAIN;
343 }
344 }
345 } else {
346 up(&tcon->ses->sesSem);
347 }
348 unload_nls(nls_codepage);
349
350 } else {
351 return -EIO;
352 }
353 }
Steve French790fe572007-07-07 19:25:05 +0000354 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356
357 *request_buf = cifs_buf_get();
358 if (*request_buf == NULL) {
359 /* BB should we add a retry in here if not a writepage? */
360 return -ENOMEM;
361 }
362 /* Although the original thought was we needed the response buf for */
363 /* potential retries of smb operations it turns out we can determine */
364 /* from the mid flags when the request buffer can be resent without */
365 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000366 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000367 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000370 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Steve French790fe572007-07-07 19:25:05 +0000372 if (tcon != NULL)
373 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return rc;
376}
377
Steve French50c2f752007-07-13 00:33:32 +0000378static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 int rc = -EINVAL;
381 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000382 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 /* check for plausible wct, bcc and t2 data and parm sizes */
385 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000386 if (pSMB->hdr.WordCount >= 10) {
387 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
389 /* check that bcc is at least as big as parms + data */
390 /* check that bcc is less than negotiated smb buffer */
391 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000392 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000393 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000394 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000396 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700397 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000399 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000400 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
402 return 0;
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405 }
406 }
Steve French50c2f752007-07-13 00:33:32 +0000407 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 sizeof(struct smb_t2_rsp) + 16);
409 return rc;
410}
411int
412CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
413{
414 NEGOTIATE_REQ *pSMB;
415 NEGOTIATE_RSP *pSMBr;
416 int rc = 0;
417 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000418 int i;
Steve French50c2f752007-07-13 00:33:32 +0000419 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000421 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100422 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Steve French790fe572007-07-07 19:25:05 +0000424 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 server = ses->server;
426 else {
427 rc = -EIO;
428 return rc;
429 }
430 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
431 (void **) &pSMB, (void **) &pSMBr);
432 if (rc)
433 return rc;
Steve French750d1152006-06-27 06:28:30 +0000434
435 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000436 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000437 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000438 else /* if override flags set only sign/seal OR them with global auth */
439 secFlags = extended_security | ses->overrideSecFlg;
440
Steve French762e5ab2007-06-28 18:41:42 +0000441 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000442
Steve French1982c342005-08-17 12:38:22 -0700443 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000444 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000445
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000446 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000447 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000448 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
449 cFYI(1, ("Kerberos only mechanism, enable extended security"));
450 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
451 }
Steve French50c2f752007-07-13 00:33:32 +0000452
Steve French39798772006-05-31 22:40:51 +0000453 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000454 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000455 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
456 count += strlen(protocols[i].name) + 1;
457 /* null at end of source and target buffers anyway */
458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 pSMB->hdr.smb_buf_length += count;
460 pSMB->ByteCount = cpu_to_le16(count);
461
462 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000464 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000465 goto neg_err_exit;
466
Al Viro733f99a2006-10-14 16:48:26 +0100467 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000468 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000469 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000470 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000471 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000472 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000473 could not negotiate a common dialect */
474 rc = -EOPNOTSUPP;
475 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000476#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000477 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100478 && ((dialect == LANMAN_PROT)
479 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000481 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000482
Steve French790fe572007-07-07 19:25:05 +0000483 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000484 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000485 server->secType = LANMAN;
486 else {
487 cERROR(1, ("mount failed weak security disabled"
488 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000489 rc = -EOPNOTSUPP;
490 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000491 }
Steve French254e55e2006-06-04 05:53:15 +0000492 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
493 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
494 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000495 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000496 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000497 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
498 /* even though we do not use raw we might as well set this
499 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000500 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000501 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000502 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
503 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000504 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000505 server->capabilities = CAP_MPX_MODE;
506 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000507 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000508 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000509 /* OS/2 often does not set timezone therefore
510 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000511 * Could deviate slightly from the right zone.
512 * Smallest defined timezone difference is 15 minutes
513 * (i.e. Nepal). Rounding up/down is done to match
514 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000515 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000516 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000517 struct timespec ts, utc;
518 utc = CURRENT_TIME;
519 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
520 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000521 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
522 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000523 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000524 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000525 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000526 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000527 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000528 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000529 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000530 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000531 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000532 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000533 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000534 server->timeAdj = (int)tmp;
535 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000536 }
Steve French790fe572007-07-07 19:25:05 +0000537 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000538
Steve French39798772006-05-31 22:40:51 +0000539
Steve French254e55e2006-06-04 05:53:15 +0000540 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000541 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000542
Steve French50c2f752007-07-13 00:33:32 +0000543 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000544 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000545 memcpy(server->cryptKey, rsp->EncryptionKey,
546 CIFS_CRYPTO_KEY_SIZE);
547 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
548 rc = -EIO; /* need cryptkey unless plain text */
549 goto neg_err_exit;
550 }
Steve French39798772006-05-31 22:40:51 +0000551
Steve French790fe572007-07-07 19:25:05 +0000552 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000553 /* we will not end up setting signing flags - as no signing
554 was in LANMAN and server did not return the flags on */
555 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000556#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000557 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000558 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000559 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000560 rc = -EOPNOTSUPP;
561#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000562 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000563 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000564 /* unknown wct */
565 rc = -EOPNOTSUPP;
566 goto neg_err_exit;
567 }
568 /* else wct == 17 NTLM */
569 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000570 if ((server->secMode & SECMODE_USER) == 0)
571 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000572
Steve French790fe572007-07-07 19:25:05 +0000573 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000574#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000575 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000576#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000577 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000578 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000579
Steve French790fe572007-07-07 19:25:05 +0000580 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000581 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000582 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000583 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000584 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000585 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000586 else if (secFlags & CIFSSEC_MAY_KRB5)
587 server->secType = Kerberos;
588 else if (secFlags & CIFSSEC_MAY_LANMAN)
589 server->secType = LANMAN;
590/* #ifdef CONFIG_CIFS_EXPERIMENTAL
591 else if (secFlags & CIFSSEC_MAY_PLNTXT)
592 server->secType = ??
593#endif */
594 else {
595 rc = -EOPNOTSUPP;
596 cERROR(1, ("Invalid security type"));
597 goto neg_err_exit;
598 }
599 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000600
Steve French254e55e2006-06-04 05:53:15 +0000601 /* one byte, so no need to convert this or EncryptionKeyLen from
602 little endian */
603 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
604 /* probably no need to store and check maxvcs */
605 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000607 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000608 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000609 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
610 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000611 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
612 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000613 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
614 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
615 CIFS_CRYPTO_KEY_SIZE);
616 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
617 && (pSMBr->EncryptionKeyLength == 0)) {
618 /* decode security blob */
619 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
620 rc = -EIO; /* no crypt key only if plain text pwd */
621 goto neg_err_exit;
622 }
623
624 /* BB might be helpful to save off the domain of server here */
625
Steve French50c2f752007-07-13 00:33:32 +0000626 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000627 (server->capabilities & CAP_EXTENDED_SECURITY)) {
628 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000629 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000631 goto neg_err_exit;
632 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500633 read_lock(&cifs_tcp_ses_lock);
634 if (server->srv_count > 1) {
635 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000636 if (memcmp(server->server_GUID,
637 pSMBr->u.extended_response.
638 GUID, 16) != 0) {
639 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000640 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000641 pSMBr->u.extended_response.GUID,
642 16);
643 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500644 } else {
645 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000646 memcpy(server->server_GUID,
647 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500648 }
Jeff Laytone187e442007-10-16 17:10:44 +0000649
650 if (count == 16) {
651 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000652 } else {
653 rc = decode_negTokenInit(pSMBr->u.extended_response.
654 SecurityBlob,
655 count - 16,
656 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000657 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000658 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000659 else
Steve French254e55e2006-06-04 05:53:15 +0000660 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
Steve French254e55e2006-06-04 05:53:15 +0000662 } else
663 server->capabilities &= ~CAP_EXTENDED_SECURITY;
664
Steve French6344a422006-06-12 04:18:35 +0000665#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000666signing_check:
Steve French6344a422006-06-12 04:18:35 +0000667#endif
Steve French762e5ab2007-06-28 18:41:42 +0000668 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
669 /* MUST_SIGN already includes the MAY_SIGN FLAG
670 so if this is zero it means that signing is disabled */
671 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000672 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000673 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000674 "packet signing to be enabled in "
675 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000676 rc = -EOPNOTSUPP;
677 }
Steve French50c2f752007-07-13 00:33:32 +0000678 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000679 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000680 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
681 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000682 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000683 if ((server->secMode &
684 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
685 cERROR(1,
686 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000687 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000688 } else
689 server->secMode |= SECMODE_SIGN_REQUIRED;
690 } else {
691 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000692 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000693 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000694 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
Steve French50c2f752007-07-13 00:33:32 +0000696
697neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700698 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000699
Steve French790fe572007-07-07 19:25:05 +0000700 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return rc;
702}
703
704int
705CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
706{
707 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500711
712 /* BB: do we need to check this? These should never be NULL. */
713 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
714 return -EIO;
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500717 * No need to return error on this operation if tid invalidated and
718 * closed on server already e.g. due to tcp session crashing. Also,
719 * the tcon is no longer on the list, so no need to take lock before
720 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 */
Jeff Laytonf1987b42008-11-15 11:12:47 -0500722 if (tcon->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000723 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Steve French50c2f752007-07-13 00:33:32 +0000725 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700726 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500727 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return rc;
Steve French133672e2007-11-13 22:41:37 +0000729
730 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700732 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Steve French50c2f752007-07-13 00:33:32 +0000734 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500735 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (rc == -EAGAIN)
737 rc = 0;
738
739 return rc;
740}
741
742int
743CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
744{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 LOGOFF_ANDX_REQ *pSMB;
746 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500749
750 /*
751 * BB: do we need to check validity of ses and server? They should
752 * always be valid since we have an active reference. If not, that
753 * should probably be a BUG()
754 */
755 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 return -EIO;
757
Jeff Layton14fbf502008-11-14 13:53:46 -0500758 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000759 if (ses->need_reconnect)
760 goto session_already_dead; /* no need to send SMBlogoff if uid
761 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
763 if (rc) {
764 up(&ses->sesSem);
765 return rc;
766 }
767
Steve French3b795212008-11-13 19:45:32 +0000768 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700769
Steve French3b795212008-11-13 19:45:32 +0000770 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
772 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774 pSMB->hdr.Uid = ses->Suid;
775
776 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000777 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000778session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700779 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000782 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 error */
784 if (rc == -EAGAIN)
785 rc = 0;
786 return rc;
787}
788
789int
Steve French2d785a52007-07-15 01:48:57 +0000790CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
791 __u16 type, const struct nls_table *nls_codepage, int remap)
792{
793 TRANSACTION2_SPI_REQ *pSMB = NULL;
794 TRANSACTION2_SPI_RSP *pSMBr = NULL;
795 struct unlink_psx_rq *pRqD;
796 int name_len;
797 int rc = 0;
798 int bytes_returned = 0;
799 __u16 params, param_offset, offset, byte_count;
800
801 cFYI(1, ("In POSIX delete"));
802PsxDelete:
803 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
804 (void **) &pSMBr);
805 if (rc)
806 return rc;
807
808 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
809 name_len =
810 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
811 PATH_MAX, nls_codepage, remap);
812 name_len++; /* trailing null */
813 name_len *= 2;
814 } else { /* BB add path length overrun check */
815 name_len = strnlen(fileName, PATH_MAX);
816 name_len++; /* trailing null */
817 strncpy(pSMB->FileName, fileName, name_len);
818 }
819
820 params = 6 + name_len;
821 pSMB->MaxParameterCount = cpu_to_le16(2);
822 pSMB->MaxDataCount = 0; /* BB double check this with jra */
823 pSMB->MaxSetupCount = 0;
824 pSMB->Reserved = 0;
825 pSMB->Flags = 0;
826 pSMB->Timeout = 0;
827 pSMB->Reserved2 = 0;
828 param_offset = offsetof(struct smb_com_transaction2_spi_req,
829 InformationLevel) - 4;
830 offset = param_offset + params;
831
832 /* Setup pointer to Request Data (inode type) */
833 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
834 pRqD->type = cpu_to_le16(type);
835 pSMB->ParameterOffset = cpu_to_le16(param_offset);
836 pSMB->DataOffset = cpu_to_le16(offset);
837 pSMB->SetupCount = 1;
838 pSMB->Reserved3 = 0;
839 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
840 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
841
842 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
843 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
844 pSMB->ParameterCount = cpu_to_le16(params);
845 pSMB->TotalParameterCount = pSMB->ParameterCount;
846 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
847 pSMB->Reserved4 = 0;
848 pSMB->hdr.smb_buf_length += byte_count;
849 pSMB->ByteCount = cpu_to_le16(byte_count);
850 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000852 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000853 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000854 cifs_buf_release(pSMB);
855
856 cifs_stats_inc(&tcon->num_deletes);
857
858 if (rc == -EAGAIN)
859 goto PsxDelete;
860
861 return rc;
862}
863
864int
Steve French737b7582005-04-28 22:41:06 -0700865CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
866 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
868 DELETE_FILE_REQ *pSMB = NULL;
869 DELETE_FILE_RSP *pSMBr = NULL;
870 int rc = 0;
871 int bytes_returned;
872 int name_len;
873
874DelFileRetry:
875 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
876 (void **) &pSMBr);
877 if (rc)
878 return rc;
879
880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
881 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000882 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700883 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 name_len++; /* trailing null */
885 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700886 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 name_len = strnlen(fileName, PATH_MAX);
888 name_len++; /* trailing null */
889 strncpy(pSMB->fileName, fileName, name_len);
890 }
891 pSMB->SearchAttributes =
892 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
893 pSMB->BufferFormat = 0x04;
894 pSMB->hdr.smb_buf_length += name_len + 1;
895 pSMB->ByteCount = cpu_to_le16(name_len + 1);
896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700898 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000899 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902 cifs_buf_release(pSMB);
903 if (rc == -EAGAIN)
904 goto DelFileRetry;
905
906 return rc;
907}
908
909int
Steve French50c2f752007-07-13 00:33:32 +0000910CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700911 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
913 DELETE_DIRECTORY_REQ *pSMB = NULL;
914 DELETE_DIRECTORY_RSP *pSMBr = NULL;
915 int rc = 0;
916 int bytes_returned;
917 int name_len;
918
919 cFYI(1, ("In CIFSSMBRmDir"));
920RmDirRetry:
921 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
922 (void **) &pSMBr);
923 if (rc)
924 return rc;
925
926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700927 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
928 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 name_len++; /* trailing null */
930 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700931 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 name_len = strnlen(dirName, PATH_MAX);
933 name_len++; /* trailing null */
934 strncpy(pSMB->DirName, dirName, name_len);
935 }
936
937 pSMB->BufferFormat = 0x04;
938 pSMB->hdr.smb_buf_length += name_len + 1;
939 pSMB->ByteCount = cpu_to_le16(name_len + 1);
940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700942 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000943 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 cifs_buf_release(pSMB);
947 if (rc == -EAGAIN)
948 goto RmDirRetry;
949 return rc;
950}
951
952int
953CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700954 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 int rc = 0;
957 CREATE_DIRECTORY_REQ *pSMB = NULL;
958 CREATE_DIRECTORY_RSP *pSMBr = NULL;
959 int bytes_returned;
960 int name_len;
961
962 cFYI(1, ("In CIFSSMBMkDir"));
963MkDirRetry:
964 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
965 (void **) &pSMBr);
966 if (rc)
967 return rc;
968
969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000970 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700971 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 name_len++; /* trailing null */
973 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700974 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 name_len = strnlen(name, PATH_MAX);
976 name_len++; /* trailing null */
977 strncpy(pSMB->DirName, name, name_len);
978 }
979
980 pSMB->BufferFormat = 0x04;
981 pSMB->hdr.smb_buf_length += name_len + 1;
982 pSMB->ByteCount = cpu_to_le16(name_len + 1);
983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700985 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000986 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -0700988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 cifs_buf_release(pSMB);
990 if (rc == -EAGAIN)
991 goto MkDirRetry;
992 return rc;
993}
994
Steve French2dd29d32007-04-23 22:07:35 +0000995int
996CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000997 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000998 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000999 const struct nls_table *nls_codepage, int remap)
1000{
1001 TRANSACTION2_SPI_REQ *pSMB = NULL;
1002 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1003 int name_len;
1004 int rc = 0;
1005 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001006 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 OPEN_PSX_REQ *pdata;
1008 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001009
1010 cFYI(1, ("In POSIX Create"));
1011PsxCreat:
1012 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1013 (void **) &pSMBr);
1014 if (rc)
1015 return rc;
1016
1017 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1018 name_len =
1019 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1020 PATH_MAX, nls_codepage, remap);
1021 name_len++; /* trailing null */
1022 name_len *= 2;
1023 } else { /* BB improve the check for buffer overruns BB */
1024 name_len = strnlen(name, PATH_MAX);
1025 name_len++; /* trailing null */
1026 strncpy(pSMB->FileName, name, name_len);
1027 }
1028
1029 params = 6 + name_len;
1030 count = sizeof(OPEN_PSX_REQ);
1031 pSMB->MaxParameterCount = cpu_to_le16(2);
1032 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1033 pSMB->MaxSetupCount = 0;
1034 pSMB->Reserved = 0;
1035 pSMB->Flags = 0;
1036 pSMB->Timeout = 0;
1037 pSMB->Reserved2 = 0;
1038 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001039 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001040 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001041 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001042 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001043 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001044 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001045 pdata->OpenFlags = cpu_to_le32(*pOplock);
1046 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1047 pSMB->DataOffset = cpu_to_le16(offset);
1048 pSMB->SetupCount = 1;
1049 pSMB->Reserved3 = 0;
1050 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1051 byte_count = 3 /* pad */ + params + count;
1052
1053 pSMB->DataCount = cpu_to_le16(count);
1054 pSMB->ParameterCount = cpu_to_le16(params);
1055 pSMB->TotalDataCount = pSMB->DataCount;
1056 pSMB->TotalParameterCount = pSMB->ParameterCount;
1057 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1058 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001059 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001060 pSMB->ByteCount = cpu_to_le16(byte_count);
1061 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1062 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1063 if (rc) {
1064 cFYI(1, ("Posix create returned %d", rc));
1065 goto psx_create_err;
1066 }
1067
Steve French790fe572007-07-07 19:25:05 +00001068 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001069 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1070
1071 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1072 rc = -EIO; /* bad smb */
1073 goto psx_create_err;
1074 }
1075
1076 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001077 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001078 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001079
Steve French2dd29d32007-04-23 22:07:35 +00001080 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001081 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001082 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1083 /* Let caller know file was created so we can set the mode. */
1084 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001085 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001086 *pOplock |= CIFS_CREATE_ACTION;
1087 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001088 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1089 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001090 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001091 } else {
Steve French790fe572007-07-07 19:25:05 +00001092 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001093 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001094 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001095 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001096 goto psx_create_err;
1097 }
Steve French50c2f752007-07-13 00:33:32 +00001098 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001099 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001100 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001101 }
Steve French2dd29d32007-04-23 22:07:35 +00001102
1103psx_create_err:
1104 cifs_buf_release(pSMB);
1105
1106 cifs_stats_inc(&tcon->num_mkdirs);
1107
1108 if (rc == -EAGAIN)
1109 goto PsxCreat;
1110
Steve French50c2f752007-07-13 00:33:32 +00001111 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001112}
1113
Steve Frencha9d02ad2005-08-24 23:06:05 -07001114static __u16 convert_disposition(int disposition)
1115{
1116 __u16 ofun = 0;
1117
1118 switch (disposition) {
1119 case FILE_SUPERSEDE:
1120 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1121 break;
1122 case FILE_OPEN:
1123 ofun = SMBOPEN_OAPPEND;
1124 break;
1125 case FILE_CREATE:
1126 ofun = SMBOPEN_OCREATE;
1127 break;
1128 case FILE_OPEN_IF:
1129 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1130 break;
1131 case FILE_OVERWRITE:
1132 ofun = SMBOPEN_OTRUNC;
1133 break;
1134 case FILE_OVERWRITE_IF:
1135 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1136 break;
1137 default:
Steve French790fe572007-07-07 19:25:05 +00001138 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139 ofun = SMBOPEN_OAPPEND; /* regular open */
1140 }
1141 return ofun;
1142}
1143
Jeff Layton35fc37d2008-05-14 10:22:03 -07001144static int
1145access_flags_to_smbopen_mode(const int access_flags)
1146{
1147 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1148
1149 if (masked_flags == GENERIC_READ)
1150 return SMBOPEN_READ;
1151 else if (masked_flags == GENERIC_WRITE)
1152 return SMBOPEN_WRITE;
1153
1154 /* just go for read/write */
1155 return SMBOPEN_READWRITE;
1156}
1157
Steve Frencha9d02ad2005-08-24 23:06:05 -07001158int
1159SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1160 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001161 const int access_flags, const int create_options, __u16 *netfid,
1162 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163 const struct nls_table *nls_codepage, int remap)
1164{
1165 int rc = -EACCES;
1166 OPENX_REQ *pSMB = NULL;
1167 OPENX_RSP *pSMBr = NULL;
1168 int bytes_returned;
1169 int name_len;
1170 __u16 count;
1171
1172OldOpenRetry:
1173 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1174 (void **) &pSMBr);
1175 if (rc)
1176 return rc;
1177
1178 pSMB->AndXCommand = 0xFF; /* none */
1179
1180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1181 count = 1; /* account for one byte pad to word boundary */
1182 name_len =
1183 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1184 fileName, PATH_MAX, nls_codepage, remap);
1185 name_len++; /* trailing null */
1186 name_len *= 2;
1187 } else { /* BB improve check for buffer overruns BB */
1188 count = 0; /* no pad */
1189 name_len = strnlen(fileName, PATH_MAX);
1190 name_len++; /* trailing null */
1191 strncpy(pSMB->fileName, fileName, name_len);
1192 }
1193 if (*pOplock & REQ_OPLOCK)
1194 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001195 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001196 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001197
Steve Frencha9d02ad2005-08-24 23:06:05 -07001198 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001199 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001200 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1201 /* set file as system file if special file such
1202 as fifo and server expecting SFU style and
1203 no Unix extensions */
1204
Steve French790fe572007-07-07 19:25:05 +00001205 if (create_options & CREATE_OPTION_SPECIAL)
1206 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001207 else /* BB FIXME BB */
1208 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209
Jeff Layton67750fb2008-05-09 22:28:02 +00001210 if (create_options & CREATE_OPTION_READONLY)
1211 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212
1213 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001214/* pSMB->CreateOptions = cpu_to_le32(create_options &
1215 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001217
1218 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001219 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 count += name_len;
1221 pSMB->hdr.smb_buf_length += count;
1222
1223 pSMB->ByteCount = cpu_to_le16(count);
1224 /* long_op set to 1 to allow for oplock break timeouts */
1225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001226 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227 cifs_stats_inc(&tcon->num_opens);
1228 if (rc) {
1229 cFYI(1, ("Error in Open = %d", rc));
1230 } else {
1231 /* BB verify if wct == 15 */
1232
Steve French582d21e2008-05-13 04:54:12 +00001233/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
1235 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1236 /* Let caller know file was created so we can set the mode. */
1237 /* Do we care about the CreateAction in any other cases? */
1238 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001239/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 *pOplock |= CIFS_CREATE_ACTION; */
1241 /* BB FIXME END */
1242
Steve French790fe572007-07-07 19:25:05 +00001243 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1245 pfile_info->LastAccessTime = 0; /* BB fixme */
1246 pfile_info->LastWriteTime = 0; /* BB fixme */
1247 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001248 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001249 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001251 pfile_info->AllocationSize =
1252 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1253 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001255 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 }
1257 }
1258
1259 cifs_buf_release(pSMB);
1260 if (rc == -EAGAIN)
1261 goto OldOpenRetry;
1262 return rc;
1263}
1264
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265int
1266CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1267 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001268 const int access_flags, const int create_options, __u16 *netfid,
1269 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001270 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271{
1272 int rc = -EACCES;
1273 OPEN_REQ *pSMB = NULL;
1274 OPEN_RSP *pSMBr = NULL;
1275 int bytes_returned;
1276 int name_len;
1277 __u16 count;
1278
1279openRetry:
1280 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1281 (void **) &pSMBr);
1282 if (rc)
1283 return rc;
1284
1285 pSMB->AndXCommand = 0xFF; /* none */
1286
1287 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1288 count = 1; /* account for one byte pad to word boundary */
1289 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001290 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001291 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 name_len++; /* trailing null */
1293 name_len *= 2;
1294 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001295 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 count = 0; /* no pad */
1297 name_len = strnlen(fileName, PATH_MAX);
1298 name_len++; /* trailing null */
1299 pSMB->NameLength = cpu_to_le16(name_len);
1300 strncpy(pSMB->fileName, fileName, name_len);
1301 }
1302 if (*pOplock & REQ_OPLOCK)
1303 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001304 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1307 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001308 /* set file as system file if special file such
1309 as fifo and server expecting SFU style and
1310 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001311 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001312 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1313 else
1314 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 /* XP does not handle ATTR_POSIX_SEMANTICS */
1317 /* but it helps speed up case sensitive checks for other
1318 servers such as Samba */
1319 if (tcon->ses->capabilities & CAP_UNIX)
1320 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1321
Jeff Layton67750fb2008-05-09 22:28:02 +00001322 if (create_options & CREATE_OPTION_READONLY)
1323 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1324
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1326 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001327 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001328 /* BB Expirement with various impersonation levels and verify */
1329 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 pSMB->SecurityFlags =
1331 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1332
1333 count += name_len;
1334 pSMB->hdr.smb_buf_length += count;
1335
1336 pSMB->ByteCount = cpu_to_le16(count);
1337 /* long_op set to 1 to allow for oplock break timeouts */
1338 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001339 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha45443472005-08-24 13:59:35 -07001340 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 if (rc) {
1342 cFYI(1, ("Error in Open = %d", rc));
1343 } else {
Steve French09d1db52005-04-28 22:41:08 -07001344 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1346 /* Let caller know file was created so we can set the mode. */
1347 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001348 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001349 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001350 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001351 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1352 36 /* CreationTime to Attributes */);
1353 /* the file_info buf is endian converted by caller */
1354 pfile_info->AllocationSize = pSMBr->AllocationSize;
1355 pfile_info->EndOfFile = pSMBr->EndOfFile;
1356 pfile_info->NumberOfLinks = cpu_to_le32(1);
1357 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 cifs_buf_release(pSMB);
1362 if (rc == -EAGAIN)
1363 goto openRetry;
1364 return rc;
1365}
1366
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367int
Steve French50c2f752007-07-13 00:33:32 +00001368CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1369 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1370 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
1372 int rc = -EACCES;
1373 READ_REQ *pSMB = NULL;
1374 READ_RSP *pSMBr = NULL;
1375 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001376 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001377 int resp_buf_type = 0;
1378 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Steve French790fe572007-07-07 19:25:05 +00001380 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1381 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001382 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001383 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001384 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001385 if ((lseek >> 32) > 0) {
1386 /* can not handle this big offset for old */
1387 return -EIO;
1388 }
1389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001392 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 if (rc)
1394 return rc;
1395
1396 /* tcon and ses pointer are checked in smb_init */
1397 if (tcon->ses->server == NULL)
1398 return -ECONNABORTED;
1399
Steve Frenchec637e32005-12-12 20:53:18 -08001400 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 pSMB->Fid = netfid;
1402 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001403 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001404 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 pSMB->Remaining = 0;
1407 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1408 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001409 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001410 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1411 else {
1412 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001413 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001415 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001416 }
Steve Frenchec637e32005-12-12 20:53:18 -08001417
1418 iov[0].iov_base = (char *)pSMB;
1419 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001420 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001421 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha45443472005-08-24 13:59:35 -07001422 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001423 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (rc) {
1425 cERROR(1, ("Send error in read = %d", rc));
1426 } else {
1427 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1428 data_length = data_length << 16;
1429 data_length += le16_to_cpu(pSMBr->DataLength);
1430 *nbytes = data_length;
1431
1432 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001433 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001435 cFYI(1, ("bad length %d for count %d",
1436 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 rc = -EIO;
1438 *nbytes = 0;
1439 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001440 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001441 le16_to_cpu(pSMBr->DataOffset);
1442/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001443 cERROR(1,("Faulting on read rc = %d",rc));
1444 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001445 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001446 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001447 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 }
1449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Steve French4b8f9302006-02-26 16:41:18 +00001451/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001452 if (*buf) {
1453 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001454 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001455 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001456 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001457 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001458 /* return buffer to caller to free */
1459 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001460 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001461 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001462 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001463 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001464 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001465
1466 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 since file handle passed in no longer valid */
1468 return rc;
1469}
1470
Steve Frenchec637e32005-12-12 20:53:18 -08001471
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472int
1473CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1474 const int netfid, const unsigned int count,
1475 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001476 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
1478 int rc = -EACCES;
1479 WRITE_REQ *pSMB = NULL;
1480 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001481 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 __u32 bytes_sent;
1483 __u16 byte_count;
1484
Steve French61de8002008-10-30 20:15:22 +00001485 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001486 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001487 return -ECONNABORTED;
1488
Steve French790fe572007-07-07 19:25:05 +00001489 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001490 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001491 else {
Steve French1c955182005-08-30 20:58:07 -07001492 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001493 if ((offset >> 32) > 0) {
1494 /* can not handle big offset for old srv */
1495 return -EIO;
1496 }
1497 }
Steve French1c955182005-08-30 20:58:07 -07001498
1499 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 (void **) &pSMBr);
1501 if (rc)
1502 return rc;
1503 /* tcon and ses pointer are checked in smb_init */
1504 if (tcon->ses->server == NULL)
1505 return -ECONNABORTED;
1506
1507 pSMB->AndXCommand = 0xFF; /* none */
1508 pSMB->Fid = netfid;
1509 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001510 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001511 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 pSMB->Reserved = 0xFFFFFFFF;
1514 pSMB->WriteMode = 0;
1515 pSMB->Remaining = 0;
1516
Steve French50c2f752007-07-13 00:33:32 +00001517 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 can send more if LARGE_WRITE_X capability returned by the server and if
1519 our buffer is big enough or if we convert to iovecs on socket writes
1520 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001521 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1523 } else {
1524 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1525 & ~0xFF;
1526 }
1527
1528 if (bytes_sent > count)
1529 bytes_sent = count;
1530 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001531 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001532 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001533 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001534 else if (ubuf) {
1535 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 cifs_buf_release(pSMB);
1537 return -EFAULT;
1538 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001539 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 /* No buffer */
1541 cifs_buf_release(pSMB);
1542 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001543 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001544 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001545 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001546 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001547 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1550 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001551 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001552
Steve French790fe572007-07-07 19:25:05 +00001553 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001554 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001555 else { /* old style write has byte count 4 bytes earlier
1556 so 4 bytes pad */
1557 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001558 (struct smb_com_writex_req *)pSMB;
1559 pSMBW->ByteCount = cpu_to_le16(byte_count);
1560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1563 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001564 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (rc) {
1566 cFYI(1, ("Send error in write = %d", rc));
1567 *nbytes = 0;
1568 } else {
1569 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1570 *nbytes = (*nbytes) << 16;
1571 *nbytes += le16_to_cpu(pSMBr->Count);
1572 }
1573
1574 cifs_buf_release(pSMB);
1575
Steve French50c2f752007-07-13 00:33:32 +00001576 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 since file handle passed in no longer valid */
1578
1579 return rc;
1580}
1581
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001582int
1583CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001585 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1586 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587{
1588 int rc = -EACCES;
1589 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001590 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001591 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001592 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001594 *nbytes = 0;
1595
Steve French790fe572007-07-07 19:25:05 +00001596 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001597
Steve French4c3130e2008-12-09 00:28:16 +00001598 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001599 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001600 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001601 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001602 if ((offset >> 32) > 0) {
1603 /* can not handle big offset for old srv */
1604 return -EIO;
1605 }
1606 }
Steve French8cc64c62005-10-03 13:49:43 -07001607 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (rc)
1609 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 /* tcon and ses pointer are checked in smb_init */
1611 if (tcon->ses->server == NULL)
1612 return -ECONNABORTED;
1613
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001614 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 pSMB->Fid = netfid;
1616 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001617 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001618 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 pSMB->Reserved = 0xFFFFFFFF;
1620 pSMB->WriteMode = 0;
1621 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001624 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Steve French3e844692005-10-03 13:37:24 -07001626 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1627 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001628 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001629 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001630 pSMB->hdr.smb_buf_length += count+1;
1631 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001632 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1633 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001634 pSMB->ByteCount = cpu_to_le16(count + 1);
1635 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001636 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001637 (struct smb_com_writex_req *)pSMB;
1638 pSMBW->ByteCount = cpu_to_le16(count + 5);
1639 }
Steve French3e844692005-10-03 13:37:24 -07001640 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001641 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001642 iov[0].iov_len = smb_hdr_len + 4;
1643 else /* wct == 12 pad bigger by four bytes */
1644 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001645
Steve French3e844692005-10-03 13:37:24 -07001646
Steve Frenchec637e32005-12-12 20:53:18 -08001647 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001648 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001649 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001651 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001652 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001653 /* presumably this can not happen, but best to be safe */
1654 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001655 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001656 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001657 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1658 *nbytes = (*nbytes) << 16;
1659 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Steve French4b8f9302006-02-26 16:41:18 +00001662/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001663 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001664 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001665 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001666 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Steve French50c2f752007-07-13 00:33:32 +00001668 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 since file handle passed in no longer valid */
1670
1671 return rc;
1672}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001673
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675int
1676CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1677 const __u16 smb_file_id, const __u64 len,
1678 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001679 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 int rc = 0;
1682 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001683/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 int bytes_returned;
1685 int timeout = 0;
1686 __u16 count;
1687
Steve French4b18f2a2008-04-29 00:06:05 +00001688 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001689 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 if (rc)
1692 return rc;
1693
Steve French790fe572007-07-07 19:25:05 +00001694 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001695 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001697 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001698 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1700 } else {
1701 pSMB->Timeout = 0;
1702 }
1703
1704 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1705 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1706 pSMB->LockType = lockType;
1707 pSMB->AndXCommand = 0xFF; /* none */
1708 pSMB->Fid = smb_file_id; /* netfid stays le */
1709
Steve French790fe572007-07-07 19:25:05 +00001710 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1712 /* BB where to store pid high? */
1713 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1714 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1715 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1716 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1717 count = sizeof(LOCKING_ANDX_RANGE);
1718 } else {
1719 /* oplock break */
1720 count = 0;
1721 }
1722 pSMB->hdr.smb_buf_length += count;
1723 pSMB->ByteCount = cpu_to_le16(count);
1724
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001725 if (waitFlag) {
1726 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001727 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001728 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001729 } else {
Steve French133672e2007-11-13 22:41:37 +00001730 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1731 timeout);
1732 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001733 }
Steve Frencha45443472005-08-24 13:59:35 -07001734 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001735 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Steve French50c2f752007-07-13 00:33:32 +00001738 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 since file handle passed in no longer valid */
1740 return rc;
1741}
1742
1743int
Steve French08547b02006-02-28 22:39:25 +00001744CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1745 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001746 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001747 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001748{
1749 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1750 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001751 struct cifs_posix_lock *parm_data;
1752 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001753 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001754 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001755 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001756 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001757 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001758
1759 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001760
Steve French790fe572007-07-07 19:25:05 +00001761 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001762 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001763
Steve French08547b02006-02-28 22:39:25 +00001764 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1765
1766 if (rc)
1767 return rc;
1768
1769 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1770
Steve French50c2f752007-07-13 00:33:32 +00001771 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001772 pSMB->MaxSetupCount = 0;
1773 pSMB->Reserved = 0;
1774 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001775 pSMB->Reserved2 = 0;
1776 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1777 offset = param_offset + params;
1778
Steve French08547b02006-02-28 22:39:25 +00001779 count = sizeof(struct cifs_posix_lock);
1780 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001781 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001782 pSMB->SetupCount = 1;
1783 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001784 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001785 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1786 else
1787 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1788 byte_count = 3 /* pad */ + params + count;
1789 pSMB->DataCount = cpu_to_le16(count);
1790 pSMB->ParameterCount = cpu_to_le16(params);
1791 pSMB->TotalDataCount = pSMB->DataCount;
1792 pSMB->TotalParameterCount = pSMB->ParameterCount;
1793 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001794 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001795 (((char *) &pSMB->hdr.Protocol) + offset);
1796
1797 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001798 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001799 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001800 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001801 pSMB->Timeout = cpu_to_le32(-1);
1802 } else
1803 pSMB->Timeout = 0;
1804
Steve French08547b02006-02-28 22:39:25 +00001805 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001806 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001807 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001808
1809 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001810 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001811 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1812 pSMB->Reserved4 = 0;
1813 pSMB->hdr.smb_buf_length += byte_count;
1814 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001815 if (waitFlag) {
1816 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1817 (struct smb_hdr *) pSMBr, &bytes_returned);
1818 } else {
Steve French133672e2007-11-13 22:41:37 +00001819 iov[0].iov_base = (char *)pSMB;
1820 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1821 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1822 &resp_buf_type, timeout);
1823 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1824 not try to free it twice below on exit */
1825 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001826 }
1827
Steve French08547b02006-02-28 22:39:25 +00001828 if (rc) {
1829 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001830 } else if (get_flag) {
1831 /* lock structure can be returned on get */
1832 __u16 data_offset;
1833 __u16 data_count;
1834 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001835
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001836 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1837 rc = -EIO; /* bad smb */
1838 goto plk_err_exit;
1839 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001840 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1841 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001842 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001843 rc = -EIO;
1844 goto plk_err_exit;
1845 }
1846 parm_data = (struct cifs_posix_lock *)
1847 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001848 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001849 pLockData->fl_type = F_UNLCK;
1850 }
Steve French50c2f752007-07-13 00:33:32 +00001851
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001852plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001853 if (pSMB)
1854 cifs_small_buf_release(pSMB);
1855
Steve French133672e2007-11-13 22:41:37 +00001856 if (resp_buf_type == CIFS_SMALL_BUFFER)
1857 cifs_small_buf_release(iov[0].iov_base);
1858 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1859 cifs_buf_release(iov[0].iov_base);
1860
Steve French08547b02006-02-28 22:39:25 +00001861 /* Note: On -EAGAIN error only caller can retry on handle based calls
1862 since file handle passed in no longer valid */
1863
1864 return rc;
1865}
1866
1867
1868int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1870{
1871 int rc = 0;
1872 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 cFYI(1, ("In CIFSSMBClose"));
1874
1875/* do not retry on dead session on close */
1876 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001877 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 return 0;
1879 if (rc)
1880 return rc;
1881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001883 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001885 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001886 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001888 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 /* EINTR is expected when user ctl-c to kill app */
1890 cERROR(1, ("Send error in Close = %d", rc));
1891 }
1892 }
1893
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001895 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 rc = 0;
1897
1898 return rc;
1899}
1900
1901int
Steve Frenchb298f222009-02-21 21:17:43 +00001902CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1903{
1904 int rc = 0;
1905 FLUSH_REQ *pSMB = NULL;
1906 cFYI(1, ("In CIFSSMBFlush"));
1907
1908 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1909 if (rc)
1910 return rc;
1911
1912 pSMB->FileID = (__u16) smb_file_id;
1913 pSMB->ByteCount = 0;
1914 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1915 cifs_stats_inc(&tcon->num_flushes);
1916 if (rc)
1917 cERROR(1, ("Send error in Flush = %d", rc));
1918
1919 return rc;
1920}
1921
1922int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1924 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926{
1927 int rc = 0;
1928 RENAME_REQ *pSMB = NULL;
1929 RENAME_RSP *pSMBr = NULL;
1930 int bytes_returned;
1931 int name_len, name_len2;
1932 __u16 count;
1933
1934 cFYI(1, ("In CIFSSMBRename"));
1935renameRetry:
1936 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1937 (void **) &pSMBr);
1938 if (rc)
1939 return rc;
1940
1941 pSMB->BufferFormat = 0x04;
1942 pSMB->SearchAttributes =
1943 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1944 ATTR_DIRECTORY);
1945
1946 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1947 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001948 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001949 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 name_len++; /* trailing null */
1951 name_len *= 2;
1952 pSMB->OldFileName[name_len] = 0x04; /* pad */
1953 /* protocol requires ASCII signature byte on Unicode string */
1954 pSMB->OldFileName[name_len + 1] = 0x00;
1955 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001956 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001957 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1959 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001960 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 name_len = strnlen(fromName, PATH_MAX);
1962 name_len++; /* trailing null */
1963 strncpy(pSMB->OldFileName, fromName, name_len);
1964 name_len2 = strnlen(toName, PATH_MAX);
1965 name_len2++; /* trailing null */
1966 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1967 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1968 name_len2++; /* trailing null */
1969 name_len2++; /* signature byte */
1970 }
1971
1972 count = 1 /* 1st signature byte */ + name_len + name_len2;
1973 pSMB->hdr.smb_buf_length += count;
1974 pSMB->ByteCount = cpu_to_le16(count);
1975
1976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001978 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001979 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 cifs_buf_release(pSMB);
1983
1984 if (rc == -EAGAIN)
1985 goto renameRetry;
1986
1987 return rc;
1988}
1989
Steve French50c2f752007-07-13 00:33:32 +00001990int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001991 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001992 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993{
1994 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1995 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001996 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 char *data_offset;
1998 char dummy_string[30];
1999 int rc = 0;
2000 int bytes_returned = 0;
2001 int len_of_str;
2002 __u16 params, param_offset, offset, count, byte_count;
2003
2004 cFYI(1, ("Rename to File by handle"));
2005 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2006 (void **) &pSMBr);
2007 if (rc)
2008 return rc;
2009
2010 params = 6;
2011 pSMB->MaxSetupCount = 0;
2012 pSMB->Reserved = 0;
2013 pSMB->Flags = 0;
2014 pSMB->Timeout = 0;
2015 pSMB->Reserved2 = 0;
2016 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2017 offset = param_offset + params;
2018
2019 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2020 rename_info = (struct set_file_rename *) data_offset;
2021 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002022 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 pSMB->SetupCount = 1;
2024 pSMB->Reserved3 = 0;
2025 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2026 byte_count = 3 /* pad */ + params;
2027 pSMB->ParameterCount = cpu_to_le16(params);
2028 pSMB->TotalParameterCount = pSMB->ParameterCount;
2029 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2030 pSMB->DataOffset = cpu_to_le16(offset);
2031 /* construct random name ".cifs_tmp<inodenum><mid>" */
2032 rename_info->overwrite = cpu_to_le32(1);
2033 rename_info->root_fid = 0;
2034 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002035 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002036 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2037 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002038 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002040 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002041 target_name, PATH_MAX, nls_codepage,
2042 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 }
2044 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002045 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 byte_count += count;
2047 pSMB->DataCount = cpu_to_le16(count);
2048 pSMB->TotalDataCount = pSMB->DataCount;
2049 pSMB->Fid = netfid;
2050 pSMB->InformationLevel =
2051 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2052 pSMB->Reserved4 = 0;
2053 pSMB->hdr.smb_buf_length += byte_count;
2054 pSMB->ByteCount = cpu_to_le16(byte_count);
2055 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002057 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002058 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002059 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 cifs_buf_release(pSMB);
2062
2063 /* Note: On -EAGAIN error only caller can retry on handle based calls
2064 since file handle passed in no longer valid */
2065
2066 return rc;
2067}
2068
2069int
Steve French50c2f752007-07-13 00:33:32 +00002070CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2071 const __u16 target_tid, const char *toName, const int flags,
2072 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073{
2074 int rc = 0;
2075 COPY_REQ *pSMB = NULL;
2076 COPY_RSP *pSMBr = NULL;
2077 int bytes_returned;
2078 int name_len, name_len2;
2079 __u16 count;
2080
2081 cFYI(1, ("In CIFSSMBCopy"));
2082copyRetry:
2083 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2084 (void **) &pSMBr);
2085 if (rc)
2086 return rc;
2087
2088 pSMB->BufferFormat = 0x04;
2089 pSMB->Tid2 = target_tid;
2090
2091 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2092
2093 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002094 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002095 fromName, PATH_MAX, nls_codepage,
2096 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 name_len++; /* trailing null */
2098 name_len *= 2;
2099 pSMB->OldFileName[name_len] = 0x04; /* pad */
2100 /* protocol requires ASCII signature byte on Unicode string */
2101 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002102 name_len2 =
2103 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002104 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2106 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002107 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 name_len = strnlen(fromName, PATH_MAX);
2109 name_len++; /* trailing null */
2110 strncpy(pSMB->OldFileName, fromName, name_len);
2111 name_len2 = strnlen(toName, PATH_MAX);
2112 name_len2++; /* trailing null */
2113 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2114 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2115 name_len2++; /* trailing null */
2116 name_len2++; /* signature byte */
2117 }
2118
2119 count = 1 /* 1st signature byte */ + name_len + name_len2;
2120 pSMB->hdr.smb_buf_length += count;
2121 pSMB->ByteCount = cpu_to_le16(count);
2122
2123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2124 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2125 if (rc) {
2126 cFYI(1, ("Send error in copy = %d with %d files copied",
2127 rc, le16_to_cpu(pSMBr->CopyCount)));
2128 }
Steve French0d817bc2008-05-22 02:02:03 +00002129 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
2131 if (rc == -EAGAIN)
2132 goto copyRetry;
2133
2134 return rc;
2135}
2136
2137int
2138CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2139 const char *fromName, const char *toName,
2140 const struct nls_table *nls_codepage)
2141{
2142 TRANSACTION2_SPI_REQ *pSMB = NULL;
2143 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144 char *data_offset;
2145 int name_len;
2146 int name_len_target;
2147 int rc = 0;
2148 int bytes_returned = 0;
2149 __u16 params, param_offset, offset, byte_count;
2150
2151 cFYI(1, ("In Symlink Unix style"));
2152createSymLinkRetry:
2153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154 (void **) &pSMBr);
2155 if (rc)
2156 return rc;
2157
2158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002160 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 /* find define for this maxpathcomponent */
2162 , nls_codepage);
2163 name_len++; /* trailing null */
2164 name_len *= 2;
2165
Steve French50c2f752007-07-13 00:33:32 +00002166 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 name_len = strnlen(fromName, PATH_MAX);
2168 name_len++; /* trailing null */
2169 strncpy(pSMB->FileName, fromName, name_len);
2170 }
2171 params = 6 + name_len;
2172 pSMB->MaxSetupCount = 0;
2173 pSMB->Reserved = 0;
2174 pSMB->Flags = 0;
2175 pSMB->Timeout = 0;
2176 pSMB->Reserved2 = 0;
2177 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002178 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 offset = param_offset + params;
2180
2181 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2183 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002184 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 /* find define for this maxpathcomponent */
2186 , nls_codepage);
2187 name_len_target++; /* trailing null */
2188 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002189 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 name_len_target = strnlen(toName, PATH_MAX);
2191 name_len_target++; /* trailing null */
2192 strncpy(data_offset, toName, name_len_target);
2193 }
2194
2195 pSMB->MaxParameterCount = cpu_to_le16(2);
2196 /* BB find exact max on data count below from sess */
2197 pSMB->MaxDataCount = cpu_to_le16(1000);
2198 pSMB->SetupCount = 1;
2199 pSMB->Reserved3 = 0;
2200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2201 byte_count = 3 /* pad */ + params + name_len_target;
2202 pSMB->DataCount = cpu_to_le16(name_len_target);
2203 pSMB->ParameterCount = cpu_to_le16(params);
2204 pSMB->TotalDataCount = pSMB->DataCount;
2205 pSMB->TotalParameterCount = pSMB->ParameterCount;
2206 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2207 pSMB->DataOffset = cpu_to_le16(offset);
2208 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2209 pSMB->Reserved4 = 0;
2210 pSMB->hdr.smb_buf_length += byte_count;
2211 pSMB->ByteCount = cpu_to_le16(byte_count);
2212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002214 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002215 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002216 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Steve French0d817bc2008-05-22 02:02:03 +00002218 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
2220 if (rc == -EAGAIN)
2221 goto createSymLinkRetry;
2222
2223 return rc;
2224}
2225
2226int
2227CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2228 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002229 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230{
2231 TRANSACTION2_SPI_REQ *pSMB = NULL;
2232 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2233 char *data_offset;
2234 int name_len;
2235 int name_len_target;
2236 int rc = 0;
2237 int bytes_returned = 0;
2238 __u16 params, param_offset, offset, byte_count;
2239
2240 cFYI(1, ("In Create Hard link Unix style"));
2241createHardLinkRetry:
2242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2243 (void **) &pSMBr);
2244 if (rc)
2245 return rc;
2246
2247 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002248 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002249 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 name_len++; /* trailing null */
2251 name_len *= 2;
2252
Steve French50c2f752007-07-13 00:33:32 +00002253 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 name_len = strnlen(toName, PATH_MAX);
2255 name_len++; /* trailing null */
2256 strncpy(pSMB->FileName, toName, name_len);
2257 }
2258 params = 6 + name_len;
2259 pSMB->MaxSetupCount = 0;
2260 pSMB->Reserved = 0;
2261 pSMB->Flags = 0;
2262 pSMB->Timeout = 0;
2263 pSMB->Reserved2 = 0;
2264 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002265 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 offset = param_offset + params;
2267
2268 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2269 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2270 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002271 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002272 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 name_len_target++; /* trailing null */
2274 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002275 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 name_len_target = strnlen(fromName, PATH_MAX);
2277 name_len_target++; /* trailing null */
2278 strncpy(data_offset, fromName, name_len_target);
2279 }
2280
2281 pSMB->MaxParameterCount = cpu_to_le16(2);
2282 /* BB find exact max on data count below from sess*/
2283 pSMB->MaxDataCount = cpu_to_le16(1000);
2284 pSMB->SetupCount = 1;
2285 pSMB->Reserved3 = 0;
2286 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2287 byte_count = 3 /* pad */ + params + name_len_target;
2288 pSMB->ParameterCount = cpu_to_le16(params);
2289 pSMB->TotalParameterCount = pSMB->ParameterCount;
2290 pSMB->DataCount = cpu_to_le16(name_len_target);
2291 pSMB->TotalDataCount = pSMB->DataCount;
2292 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2293 pSMB->DataOffset = cpu_to_le16(offset);
2294 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2295 pSMB->Reserved4 = 0;
2296 pSMB->hdr.smb_buf_length += byte_count;
2297 pSMB->ByteCount = cpu_to_le16(byte_count);
2298 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2299 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002300 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002301 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
2304 cifs_buf_release(pSMB);
2305 if (rc == -EAGAIN)
2306 goto createHardLinkRetry;
2307
2308 return rc;
2309}
2310
2311int
2312CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2313 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002314 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315{
2316 int rc = 0;
2317 NT_RENAME_REQ *pSMB = NULL;
2318 RENAME_RSP *pSMBr = NULL;
2319 int bytes_returned;
2320 int name_len, name_len2;
2321 __u16 count;
2322
2323 cFYI(1, ("In CIFSCreateHardLink"));
2324winCreateHardLinkRetry:
2325
2326 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2327 (void **) &pSMBr);
2328 if (rc)
2329 return rc;
2330
2331 pSMB->SearchAttributes =
2332 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2333 ATTR_DIRECTORY);
2334 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2335 pSMB->ClusterCount = 0;
2336
2337 pSMB->BufferFormat = 0x04;
2338
2339 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2340 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002341 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002342 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 name_len++; /* trailing null */
2344 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002345
2346 /* protocol specifies ASCII buffer format (0x04) for unicode */
2347 pSMB->OldFileName[name_len] = 0x04;
2348 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002350 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002351 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2353 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002354 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 name_len = strnlen(fromName, PATH_MAX);
2356 name_len++; /* trailing null */
2357 strncpy(pSMB->OldFileName, fromName, name_len);
2358 name_len2 = strnlen(toName, PATH_MAX);
2359 name_len2++; /* trailing null */
2360 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2361 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2362 name_len2++; /* trailing null */
2363 name_len2++; /* signature byte */
2364 }
2365
2366 count = 1 /* string type byte */ + name_len + name_len2;
2367 pSMB->hdr.smb_buf_length += count;
2368 pSMB->ByteCount = cpu_to_le16(count);
2369
2370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002372 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002373 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002375
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 cifs_buf_release(pSMB);
2377 if (rc == -EAGAIN)
2378 goto winCreateHardLinkRetry;
2379
2380 return rc;
2381}
2382
2383int
2384CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002385 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 const struct nls_table *nls_codepage)
2387{
2388/* SMB_QUERY_FILE_UNIX_LINK */
2389 TRANSACTION2_QPI_REQ *pSMB = NULL;
2390 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2391 int rc = 0;
2392 int bytes_returned;
2393 int name_len;
2394 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002395 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396
2397 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2398
2399querySymLinkRetry:
2400 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2401 (void **) &pSMBr);
2402 if (rc)
2403 return rc;
2404
2405 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2406 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002407 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2408 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 name_len++; /* trailing null */
2410 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002411 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 name_len = strnlen(searchName, PATH_MAX);
2413 name_len++; /* trailing null */
2414 strncpy(pSMB->FileName, searchName, name_len);
2415 }
2416
2417 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2418 pSMB->TotalDataCount = 0;
2419 pSMB->MaxParameterCount = cpu_to_le16(2);
2420 /* BB find exact max data count below from sess structure BB */
2421 pSMB->MaxDataCount = cpu_to_le16(4000);
2422 pSMB->MaxSetupCount = 0;
2423 pSMB->Reserved = 0;
2424 pSMB->Flags = 0;
2425 pSMB->Timeout = 0;
2426 pSMB->Reserved2 = 0;
2427 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002428 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 pSMB->DataCount = 0;
2430 pSMB->DataOffset = 0;
2431 pSMB->SetupCount = 1;
2432 pSMB->Reserved3 = 0;
2433 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2434 byte_count = params + 1 /* pad */ ;
2435 pSMB->TotalParameterCount = cpu_to_le16(params);
2436 pSMB->ParameterCount = pSMB->TotalParameterCount;
2437 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2438 pSMB->Reserved4 = 0;
2439 pSMB->hdr.smb_buf_length += byte_count;
2440 pSMB->ByteCount = cpu_to_le16(byte_count);
2441
2442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2444 if (rc) {
2445 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2446 } else {
2447 /* decode response */
2448
2449 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002451 if (rc || (pSMBr->ByteCount < 2))
2452 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 else {
Jeff Layton460b9692009-04-30 07:17:56 -04002454 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455
Jeff Layton460b9692009-04-30 07:17:56 -04002456 data_start = ((char *) &pSMBr->hdr.Protocol) +
2457 le16_to_cpu(pSMBr->t2.DataOffset);
2458
Steve French737b7582005-04-28 22:41:06 -07002459 /* BB FIXME investigate remapping reserved chars here */
Jeff Layton460b9692009-04-30 07:17:56 -04002460 *symlinkinfo = cifs_strndup(data_start, count,
2461 pSMBr->hdr.Flags2 &
2462 SMBFLG2_UNICODE,
2463 nls_codepage);
2464 if (!symlinkinfo)
2465 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 }
2467 }
2468 cifs_buf_release(pSMB);
2469 if (rc == -EAGAIN)
2470 goto querySymLinkRetry;
2471 return rc;
2472}
2473
Parag Warudkarc9489772007-10-23 18:09:48 +00002474#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002475/* Initialize NT TRANSACT SMB into small smb request buffer.
2476 This assumes that all NT TRANSACTS that we init here have
2477 total parm and data under about 400 bytes (to fit in small cifs
2478 buffer size), which is the case so far, it easily fits. NB:
2479 Setup words themselves and ByteCount
2480 MaxSetupCount (size of returned setup area) and
2481 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002482static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002483smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002484 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002485 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002486{
2487 int rc;
2488 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002489 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002490
2491 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2492 (void **)&pSMB);
2493 if (rc)
2494 return rc;
2495 *ret_buf = (void *)pSMB;
2496 pSMB->Reserved = 0;
2497 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2498 pSMB->TotalDataCount = 0;
2499 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2500 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2501 pSMB->ParameterCount = pSMB->TotalParameterCount;
2502 pSMB->DataCount = pSMB->TotalDataCount;
2503 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2504 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2505 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2506 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2507 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2508 pSMB->SubCommand = cpu_to_le16(sub_command);
2509 return 0;
2510}
2511
2512static int
Steve French50c2f752007-07-13 00:33:32 +00002513validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002514 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002515{
Steve French50c2f752007-07-13 00:33:32 +00002516 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002517 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002518 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002519
Steve French630f3f0c2007-10-25 21:17:17 +00002520 *pdatalen = 0;
2521 *pparmlen = 0;
2522
Steve French790fe572007-07-07 19:25:05 +00002523 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002524 return -EINVAL;
2525
2526 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2527
2528 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002529 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002530 (char *)&pSMBr->ByteCount;
2531
Steve French0a4b92c2006-01-12 15:44:21 -08002532 data_offset = le32_to_cpu(pSMBr->DataOffset);
2533 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002534 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002535 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2536
2537 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2538 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2539
2540 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002541 if (*ppparm > end_of_smb) {
2542 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002543 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002544 } else if (parm_count + *ppparm > end_of_smb) {
2545 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002546 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002547 } else if (*ppdata > end_of_smb) {
2548 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002549 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002550 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002551 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002552 *ppdata, data_count, (data_count + *ppdata),
2553 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002554 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002555 } else if (parm_count + data_count > pSMBr->ByteCount) {
2556 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
2558 }
Steve French630f3f0c2007-10-25 21:17:17 +00002559 *pdatalen = data_count;
2560 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002561 return 0;
2562}
Parag Warudkarc9489772007-10-23 18:09:48 +00002563#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002564
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565int
2566CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2567 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002568 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 const struct nls_table *nls_codepage)
2570{
2571 int rc = 0;
2572 int bytes_returned;
2573 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002574 struct smb_com_transaction_ioctl_req *pSMB;
2575 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
2577 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2578 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2579 (void **) &pSMBr);
2580 if (rc)
2581 return rc;
2582
2583 pSMB->TotalParameterCount = 0 ;
2584 pSMB->TotalDataCount = 0;
2585 pSMB->MaxParameterCount = cpu_to_le32(2);
2586 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002587 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2588 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 pSMB->MaxSetupCount = 4;
2590 pSMB->Reserved = 0;
2591 pSMB->ParameterOffset = 0;
2592 pSMB->DataCount = 0;
2593 pSMB->DataOffset = 0;
2594 pSMB->SetupCount = 4;
2595 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2596 pSMB->ParameterCount = pSMB->TotalParameterCount;
2597 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2598 pSMB->IsFsctl = 1; /* FSCTL */
2599 pSMB->IsRootFlag = 0;
2600 pSMB->Fid = fid; /* file handle always le */
2601 pSMB->ByteCount = 0;
2602
2603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2605 if (rc) {
2606 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2607 } else { /* decode response */
2608 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2609 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2610 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2611 /* BB also check enough total bytes returned */
2612 rc = -EIO; /* bad smb */
2613 else {
Steve French790fe572007-07-07 19:25:05 +00002614 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002615 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002616 pSMBr->ByteCount +
2617 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618
Steve French50c2f752007-07-13 00:33:32 +00002619 struct reparse_data *reparse_buf =
2620 (struct reparse_data *)
2621 ((char *)&pSMBr->hdr.Protocol
2622 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002623 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 rc = -EIO;
2625 goto qreparse_out;
2626 }
Steve French790fe572007-07-07 19:25:05 +00002627 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 reparse_buf->TargetNameOffset +
2629 reparse_buf->TargetNameLen) >
2630 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002631 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 rc = -EIO;
2633 goto qreparse_out;
2634 }
Steve French50c2f752007-07-13 00:33:32 +00002635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2637 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002638 (reparse_buf->LinkNamesBuf +
2639 reparse_buf->TargetNameOffset),
2640 min(buflen/2,
2641 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002643 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 reparse_buf->TargetNameOffset),
2645 name_len, nls_codepage);
2646 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002647 strncpy(symlinkinfo,
2648 reparse_buf->LinkNamesBuf +
2649 reparse_buf->TargetNameOffset,
2650 min_t(const int, buflen,
2651 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 }
2653 } else {
2654 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002655 cFYI(1, ("Invalid return data count on "
2656 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 }
2658 symlinkinfo[buflen] = 0; /* just in case so the caller
2659 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002660 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 }
2662 }
2663qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002664 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
2666 /* Note: On -EAGAIN error only caller can retry on handle based calls
2667 since file handle passed in no longer valid */
2668
2669 return rc;
2670}
2671
2672#ifdef CONFIG_CIFS_POSIX
2673
2674/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002675static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2676 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677{
2678 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002679 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2680 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2681 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2683
2684 return;
2685}
2686
2687/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002688static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2689 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690{
2691 int size = 0;
2692 int i;
2693 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002694 struct cifs_posix_ace *pACE;
2695 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2696 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
2698 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2699 return -EOPNOTSUPP;
2700
Steve French790fe572007-07-07 19:25:05 +00002701 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 count = le16_to_cpu(cifs_acl->access_entry_count);
2703 pACE = &cifs_acl->ace_array[0];
2704 size = sizeof(struct cifs_posix_acl);
2705 size += sizeof(struct cifs_posix_ace) * count;
2706 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002707 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002708 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2709 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 return -EINVAL;
2711 }
Steve French790fe572007-07-07 19:25:05 +00002712 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 count = le16_to_cpu(cifs_acl->access_entry_count);
2714 size = sizeof(struct cifs_posix_acl);
2715 size += sizeof(struct cifs_posix_ace) * count;
2716/* skip past access ACEs to get to default ACEs */
2717 pACE = &cifs_acl->ace_array[count];
2718 count = le16_to_cpu(cifs_acl->default_entry_count);
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)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 return -EINVAL;
2723 } else {
2724 /* illegal type */
2725 return -EINVAL;
2726 }
2727
2728 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002729 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002730 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002731 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 return -ERANGE;
2733 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002734 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002735 for (i = 0; i < count ; i++) {
2736 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2737 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 }
2739 }
2740 return size;
2741}
2742
Steve French50c2f752007-07-13 00:33:32 +00002743static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2744 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745{
2746 __u16 rc = 0; /* 0 = ACL converted ok */
2747
Steve Frenchff7feac2005-11-15 16:45:16 -08002748 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2749 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002751 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 /* Probably no need to le convert -1 on any arch but can not hurt */
2753 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002754 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002755 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002756 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return rc;
2758}
2759
2760/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002761static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2762 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763{
2764 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002765 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2766 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 int count;
2768 int i;
2769
Steve French790fe572007-07-07 19:25:05 +00002770 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 return 0;
2772
2773 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002774 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002775 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002776 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002777 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002778 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002779 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 return 0;
2781 }
2782 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002783 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002784 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002785 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002786 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 else {
Steve French50c2f752007-07-13 00:33:32 +00002788 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 return 0;
2790 }
Steve French50c2f752007-07-13 00:33:32 +00002791 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2793 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002794 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 /* ACE not converted */
2796 break;
2797 }
2798 }
Steve French790fe572007-07-07 19:25:05 +00002799 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2801 rc += sizeof(struct cifs_posix_acl);
2802 /* BB add check to make sure ACL does not overflow SMB */
2803 }
2804 return rc;
2805}
2806
2807int
2808CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002809 const unsigned char *searchName,
2810 char *acl_inf, const int buflen, const int acl_type,
2811 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812{
2813/* SMB_QUERY_POSIX_ACL */
2814 TRANSACTION2_QPI_REQ *pSMB = NULL;
2815 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2816 int rc = 0;
2817 int bytes_returned;
2818 int name_len;
2819 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002820
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2822
2823queryAclRetry:
2824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2825 (void **) &pSMBr);
2826 if (rc)
2827 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002828
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2830 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002831 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002832 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 name_len++; /* trailing null */
2834 name_len *= 2;
2835 pSMB->FileName[name_len] = 0;
2836 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002837 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 name_len = strnlen(searchName, PATH_MAX);
2839 name_len++; /* trailing null */
2840 strncpy(pSMB->FileName, searchName, name_len);
2841 }
2842
2843 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2844 pSMB->TotalDataCount = 0;
2845 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002846 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 pSMB->MaxDataCount = cpu_to_le16(4000);
2848 pSMB->MaxSetupCount = 0;
2849 pSMB->Reserved = 0;
2850 pSMB->Flags = 0;
2851 pSMB->Timeout = 0;
2852 pSMB->Reserved2 = 0;
2853 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002854 offsetof(struct smb_com_transaction2_qpi_req,
2855 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 pSMB->DataCount = 0;
2857 pSMB->DataOffset = 0;
2858 pSMB->SetupCount = 1;
2859 pSMB->Reserved3 = 0;
2860 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2861 byte_count = params + 1 /* pad */ ;
2862 pSMB->TotalParameterCount = cpu_to_le16(params);
2863 pSMB->ParameterCount = pSMB->TotalParameterCount;
2864 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2865 pSMB->Reserved4 = 0;
2866 pSMB->hdr.smb_buf_length += byte_count;
2867 pSMB->ByteCount = cpu_to_le16(byte_count);
2868
2869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002871 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 if (rc) {
2873 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2874 } else {
2875 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002876
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2878 if (rc || (pSMBr->ByteCount < 2))
2879 /* BB also check enough total bytes returned */
2880 rc = -EIO; /* bad smb */
2881 else {
2882 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2883 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2884 rc = cifs_copy_posix_acl(acl_inf,
2885 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002886 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 }
2888 }
2889 cifs_buf_release(pSMB);
2890 if (rc == -EAGAIN)
2891 goto queryAclRetry;
2892 return rc;
2893}
2894
2895int
2896CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002897 const unsigned char *fileName,
2898 const char *local_acl, const int buflen,
2899 const int acl_type,
2900 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901{
2902 struct smb_com_transaction2_spi_req *pSMB = NULL;
2903 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2904 char *parm_data;
2905 int name_len;
2906 int rc = 0;
2907 int bytes_returned = 0;
2908 __u16 params, byte_count, data_count, param_offset, offset;
2909
2910 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2911setAclRetry:
2912 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002913 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 if (rc)
2915 return rc;
2916 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2917 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002918 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002919 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 name_len++; /* trailing null */
2921 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002922 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 name_len = strnlen(fileName, PATH_MAX);
2924 name_len++; /* trailing null */
2925 strncpy(pSMB->FileName, fileName, name_len);
2926 }
2927 params = 6 + name_len;
2928 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002929 /* BB find max SMB size from sess */
2930 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 pSMB->MaxSetupCount = 0;
2932 pSMB->Reserved = 0;
2933 pSMB->Flags = 0;
2934 pSMB->Timeout = 0;
2935 pSMB->Reserved2 = 0;
2936 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002937 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 offset = param_offset + params;
2939 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2940 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2941
2942 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002943 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Steve French790fe572007-07-07 19:25:05 +00002945 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 rc = -EOPNOTSUPP;
2947 goto setACLerrorExit;
2948 }
2949 pSMB->DataOffset = cpu_to_le16(offset);
2950 pSMB->SetupCount = 1;
2951 pSMB->Reserved3 = 0;
2952 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2953 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2954 byte_count = 3 /* pad */ + params + data_count;
2955 pSMB->DataCount = cpu_to_le16(data_count);
2956 pSMB->TotalDataCount = pSMB->DataCount;
2957 pSMB->ParameterCount = cpu_to_le16(params);
2958 pSMB->TotalParameterCount = pSMB->ParameterCount;
2959 pSMB->Reserved4 = 0;
2960 pSMB->hdr.smb_buf_length += byte_count;
2961 pSMB->ByteCount = cpu_to_le16(byte_count);
2962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002964 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
2967setACLerrorExit:
2968 cifs_buf_release(pSMB);
2969 if (rc == -EAGAIN)
2970 goto setAclRetry;
2971 return rc;
2972}
2973
Steve Frenchf654bac2005-04-28 22:41:04 -07002974/* BB fix tabs in this function FIXME BB */
2975int
2976CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002977 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002978{
Steve French50c2f752007-07-13 00:33:32 +00002979 int rc = 0;
2980 struct smb_t2_qfi_req *pSMB = NULL;
2981 struct smb_t2_qfi_rsp *pSMBr = NULL;
2982 int bytes_returned;
2983 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002984
Steve French790fe572007-07-07 19:25:05 +00002985 cFYI(1, ("In GetExtAttr"));
2986 if (tcon == NULL)
2987 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002988
2989GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002990 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2991 (void **) &pSMBr);
2992 if (rc)
2993 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002994
Steve Frenchad7a2922008-02-07 23:25:02 +00002995 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002996 pSMB->t2.TotalDataCount = 0;
2997 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2998 /* BB find exact max data count below from sess structure BB */
2999 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3000 pSMB->t2.MaxSetupCount = 0;
3001 pSMB->t2.Reserved = 0;
3002 pSMB->t2.Flags = 0;
3003 pSMB->t2.Timeout = 0;
3004 pSMB->t2.Reserved2 = 0;
3005 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3006 Fid) - 4);
3007 pSMB->t2.DataCount = 0;
3008 pSMB->t2.DataOffset = 0;
3009 pSMB->t2.SetupCount = 1;
3010 pSMB->t2.Reserved3 = 0;
3011 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3012 byte_count = params + 1 /* pad */ ;
3013 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3014 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3015 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3016 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003017 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003018 pSMB->hdr.smb_buf_length += byte_count;
3019 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003020
Steve French790fe572007-07-07 19:25:05 +00003021 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3022 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3023 if (rc) {
3024 cFYI(1, ("error %d in GetExtAttr", rc));
3025 } else {
3026 /* decode response */
3027 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3028 if (rc || (pSMBr->ByteCount < 2))
3029 /* BB also check enough total bytes returned */
3030 /* If rc should we check for EOPNOSUPP and
3031 disable the srvino flag? or in caller? */
3032 rc = -EIO; /* bad smb */
3033 else {
3034 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3035 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3036 struct file_chattr_info *pfinfo;
3037 /* BB Do we need a cast or hash here ? */
3038 if (count != 16) {
3039 cFYI(1, ("Illegal size ret in GetExtAttr"));
3040 rc = -EIO;
3041 goto GetExtAttrOut;
3042 }
3043 pfinfo = (struct file_chattr_info *)
3044 (data_offset + (char *) &pSMBr->hdr.Protocol);
3045 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003046 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003047 }
3048 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003049GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003050 cifs_buf_release(pSMB);
3051 if (rc == -EAGAIN)
3052 goto GetExtAttrRetry;
3053 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003054}
3055
Steve Frenchf654bac2005-04-28 22:41:04 -07003056#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057
Steve French297647c2007-10-12 04:11:59 +00003058#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003059/* Get Security Descriptor (by handle) from remote server for a file or dir */
3060int
3061CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003062 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003063{
3064 int rc = 0;
3065 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003066 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003067 struct kvec iov[1];
3068
3069 cFYI(1, ("GetCifsACL"));
3070
Steve French630f3f0c2007-10-25 21:17:17 +00003071 *pbuflen = 0;
3072 *acl_inf = NULL;
3073
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003074 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003075 8 /* parm len */, tcon, (void **) &pSMB);
3076 if (rc)
3077 return rc;
3078
3079 pSMB->MaxParameterCount = cpu_to_le32(4);
3080 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3081 pSMB->MaxSetupCount = 0;
3082 pSMB->Fid = fid; /* file handle always le */
3083 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3084 CIFS_ACL_DACL);
3085 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3086 pSMB->hdr.smb_buf_length += 11;
3087 iov[0].iov_base = (char *)pSMB;
3088 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3089
Steve Frencha761ac52007-10-18 21:45:27 +00003090 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003091 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003092 cifs_stats_inc(&tcon->num_acl_get);
3093 if (rc) {
3094 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3095 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003096 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003097 __u32 parm_len;
3098 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003099 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003100 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003101
3102/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003103 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003104 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003105 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003106 goto qsec_out;
3107 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3108
Steve French630f3f0c2007-10-25 21:17:17 +00003109 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003110
3111 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3112 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003113 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003114 goto qsec_out;
3115 }
3116
3117/* BB check that data area is minimum length and as big as acl_len */
3118
Steve Frenchaf6f4612007-10-16 18:40:37 +00003119 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003120 if (acl_len != *pbuflen) {
3121 cERROR(1, ("acl length %d does not match %d",
3122 acl_len, *pbuflen));
3123 if (*pbuflen > acl_len)
3124 *pbuflen = acl_len;
3125 }
Steve French0a4b92c2006-01-12 15:44:21 -08003126
Steve French630f3f0c2007-10-25 21:17:17 +00003127 /* check if buffer is big enough for the acl
3128 header followed by the smallest SID */
3129 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3130 (*pbuflen >= 64 * 1024)) {
3131 cERROR(1, ("bad acl length %d", *pbuflen));
3132 rc = -EINVAL;
3133 *pbuflen = 0;
3134 } else {
3135 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3136 if (*acl_inf == NULL) {
3137 *pbuflen = 0;
3138 rc = -ENOMEM;
3139 }
3140 memcpy(*acl_inf, pdata, *pbuflen);
3141 }
Steve French0a4b92c2006-01-12 15:44:21 -08003142 }
3143qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003144 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003145 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003146 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003147 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003148/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003149 return rc;
3150}
Steve French97837582007-12-31 07:47:21 +00003151
3152int
3153CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3154 struct cifs_ntsd *pntsd, __u32 acllen)
3155{
3156 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3157 int rc = 0;
3158 int bytes_returned = 0;
3159 SET_SEC_DESC_REQ *pSMB = NULL;
3160 NTRANSACT_RSP *pSMBr = NULL;
3161
3162setCifsAclRetry:
3163 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3164 (void **) &pSMBr);
3165 if (rc)
3166 return (rc);
3167
3168 pSMB->MaxSetupCount = 0;
3169 pSMB->Reserved = 0;
3170
3171 param_count = 8;
3172 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3173 data_count = acllen;
3174 data_offset = param_offset + param_count;
3175 byte_count = 3 /* pad */ + param_count;
3176
3177 pSMB->DataCount = cpu_to_le32(data_count);
3178 pSMB->TotalDataCount = pSMB->DataCount;
3179 pSMB->MaxParameterCount = cpu_to_le32(4);
3180 pSMB->MaxDataCount = cpu_to_le32(16384);
3181 pSMB->ParameterCount = cpu_to_le32(param_count);
3182 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3183 pSMB->TotalParameterCount = pSMB->ParameterCount;
3184 pSMB->DataOffset = cpu_to_le32(data_offset);
3185 pSMB->SetupCount = 0;
3186 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3187 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3188
3189 pSMB->Fid = fid; /* file handle always le */
3190 pSMB->Reserved2 = 0;
3191 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3192
3193 if (pntsd && acllen) {
3194 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3195 (char *) pntsd,
3196 acllen);
3197 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3198
3199 } else
3200 pSMB->hdr.smb_buf_length += byte_count;
3201
3202 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3203 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3204
3205 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3206 if (rc)
3207 cFYI(1, ("Set CIFS ACL returned %d", rc));
3208 cifs_buf_release(pSMB);
3209
3210 if (rc == -EAGAIN)
3211 goto setCifsAclRetry;
3212
3213 return (rc);
3214}
3215
Steve French297647c2007-10-12 04:11:59 +00003216#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003217
Steve French6b8edfe2005-08-23 20:26:03 -07003218/* Legacy Query Path Information call for lookup to old servers such
3219 as Win9x/WinME */
3220int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003221 const unsigned char *searchName,
3222 FILE_ALL_INFO *pFinfo,
3223 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003224{
Steve Frenchad7a2922008-02-07 23:25:02 +00003225 QUERY_INFORMATION_REQ *pSMB;
3226 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003227 int rc = 0;
3228 int bytes_returned;
3229 int name_len;
3230
Steve French50c2f752007-07-13 00:33:32 +00003231 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003232QInfRetry:
3233 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003234 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003235 if (rc)
3236 return rc;
3237
3238 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3239 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003240 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3241 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003242 name_len++; /* trailing null */
3243 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003244 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003245 name_len = strnlen(searchName, PATH_MAX);
3246 name_len++; /* trailing null */
3247 strncpy(pSMB->FileName, searchName, name_len);
3248 }
3249 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003250 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003251 pSMB->hdr.smb_buf_length += (__u16) name_len;
3252 pSMB->ByteCount = cpu_to_le16(name_len);
3253
3254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003256 if (rc) {
3257 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003258 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003259 struct timespec ts;
3260 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003261
3262 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003263 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003264 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003265 ts.tv_nsec = 0;
3266 ts.tv_sec = time;
3267 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003268 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003269 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3270 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003271 pFinfo->AllocationSize =
3272 cpu_to_le64(le32_to_cpu(pSMBr->size));
3273 pFinfo->EndOfFile = pFinfo->AllocationSize;
3274 pFinfo->Attributes =
3275 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003276 } else
3277 rc = -EIO; /* bad buffer passed in */
3278
3279 cifs_buf_release(pSMB);
3280
3281 if (rc == -EAGAIN)
3282 goto QInfRetry;
3283
3284 return rc;
3285}
3286
3287
3288
3289
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290int
3291CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3292 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003293 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003294 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003295 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296{
3297/* level 263 SMB_QUERY_FILE_ALL_INFO */
3298 TRANSACTION2_QPI_REQ *pSMB = NULL;
3299 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3300 int rc = 0;
3301 int bytes_returned;
3302 int name_len;
3303 __u16 params, byte_count;
3304
3305/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3306QPathInfoRetry:
3307 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3308 (void **) &pSMBr);
3309 if (rc)
3310 return rc;
3311
3312 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3313 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003314 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003315 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 name_len++; /* trailing null */
3317 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003318 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 name_len = strnlen(searchName, PATH_MAX);
3320 name_len++; /* trailing null */
3321 strncpy(pSMB->FileName, searchName, name_len);
3322 }
3323
Steve French50c2f752007-07-13 00:33:32 +00003324 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 pSMB->TotalDataCount = 0;
3326 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003327 /* BB find exact max SMB PDU from sess structure BB */
3328 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 pSMB->MaxSetupCount = 0;
3330 pSMB->Reserved = 0;
3331 pSMB->Flags = 0;
3332 pSMB->Timeout = 0;
3333 pSMB->Reserved2 = 0;
3334 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003335 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 pSMB->DataCount = 0;
3337 pSMB->DataOffset = 0;
3338 pSMB->SetupCount = 1;
3339 pSMB->Reserved3 = 0;
3340 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3341 byte_count = params + 1 /* pad */ ;
3342 pSMB->TotalParameterCount = cpu_to_le16(params);
3343 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003344 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003345 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3346 else
3347 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348 pSMB->Reserved4 = 0;
3349 pSMB->hdr.smb_buf_length += byte_count;
3350 pSMB->ByteCount = cpu_to_le16(byte_count);
3351
3352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3354 if (rc) {
3355 cFYI(1, ("Send error in QPathInfo = %d", rc));
3356 } else { /* decode response */
3357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3358
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003359 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3360 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003361 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003363 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003364 rc = -EIO; /* 24 or 26 expected but we do not read
3365 last field */
3366 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003367 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003369
3370 /* On legacy responses we do not read the last field,
3371 EAsize, fortunately since it varies by subdialect and
3372 also note it differs on Set vs. Get, ie two bytes or 4
3373 bytes depending but we don't care here */
3374 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003375 size = sizeof(FILE_INFO_STANDARD);
3376 else
3377 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 memcpy((char *) pFindData,
3379 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003380 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 } else
3382 rc = -ENOMEM;
3383 }
3384 cifs_buf_release(pSMB);
3385 if (rc == -EAGAIN)
3386 goto QPathInfoRetry;
3387
3388 return rc;
3389}
3390
3391int
3392CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3393 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003394 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003395 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396{
3397/* SMB_QUERY_FILE_UNIX_BASIC */
3398 TRANSACTION2_QPI_REQ *pSMB = NULL;
3399 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3400 int rc = 0;
3401 int bytes_returned = 0;
3402 int name_len;
3403 __u16 params, byte_count;
3404
3405 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3406UnixQPathInfoRetry:
3407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3408 (void **) &pSMBr);
3409 if (rc)
3410 return rc;
3411
3412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3413 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003414 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003415 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 name_len++; /* trailing null */
3417 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003418 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 name_len = strnlen(searchName, PATH_MAX);
3420 name_len++; /* trailing null */
3421 strncpy(pSMB->FileName, searchName, name_len);
3422 }
3423
Steve French50c2f752007-07-13 00:33:32 +00003424 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 pSMB->TotalDataCount = 0;
3426 pSMB->MaxParameterCount = cpu_to_le16(2);
3427 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003428 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 pSMB->MaxSetupCount = 0;
3430 pSMB->Reserved = 0;
3431 pSMB->Flags = 0;
3432 pSMB->Timeout = 0;
3433 pSMB->Reserved2 = 0;
3434 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003435 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 pSMB->DataCount = 0;
3437 pSMB->DataOffset = 0;
3438 pSMB->SetupCount = 1;
3439 pSMB->Reserved3 = 0;
3440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3441 byte_count = params + 1 /* pad */ ;
3442 pSMB->TotalParameterCount = cpu_to_le16(params);
3443 pSMB->ParameterCount = pSMB->TotalParameterCount;
3444 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3445 pSMB->Reserved4 = 0;
3446 pSMB->hdr.smb_buf_length += byte_count;
3447 pSMB->ByteCount = cpu_to_le16(byte_count);
3448
3449 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3451 if (rc) {
3452 cFYI(1, ("Send error in QPathInfo = %d", rc));
3453 } else { /* decode response */
3454 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3455
3456 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003457 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3458 "Unix Extensions can be disabled on mount "
3459 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 rc = -EIO; /* bad smb */
3461 } else {
3462 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3463 memcpy((char *) pFindData,
3464 (char *) &pSMBr->hdr.Protocol +
3465 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003466 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 }
3468 }
3469 cifs_buf_release(pSMB);
3470 if (rc == -EAGAIN)
3471 goto UnixQPathInfoRetry;
3472
3473 return rc;
3474}
3475
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476/* xid, tcon, searchName and codepage are input parms, rest are returned */
3477int
3478CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003479 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003481 __u16 *pnetfid,
3482 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483{
3484/* level 257 SMB_ */
3485 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3486 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003487 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 int rc = 0;
3489 int bytes_returned = 0;
3490 int name_len;
3491 __u16 params, byte_count;
3492
Steve French50c2f752007-07-13 00:33:32 +00003493 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494
3495findFirstRetry:
3496 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3497 (void **) &pSMBr);
3498 if (rc)
3499 return rc;
3500
3501 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3502 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003503 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003504 PATH_MAX, nls_codepage, remap);
3505 /* We can not add the asterik earlier in case
3506 it got remapped to 0xF03A as if it were part of the
3507 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003509 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003510 pSMB->FileName[name_len+1] = 0;
3511 pSMB->FileName[name_len+2] = '*';
3512 pSMB->FileName[name_len+3] = 0;
3513 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3515 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003516 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 } else { /* BB add check for overrun of SMB buf BB */
3518 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003520 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 free buffer exit; BB */
3522 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003523 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003524 pSMB->FileName[name_len+1] = '*';
3525 pSMB->FileName[name_len+2] = 0;
3526 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 }
3528
3529 params = 12 + name_len /* includes null */ ;
3530 pSMB->TotalDataCount = 0; /* no EAs */
3531 pSMB->MaxParameterCount = cpu_to_le16(10);
3532 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3533 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3534 pSMB->MaxSetupCount = 0;
3535 pSMB->Reserved = 0;
3536 pSMB->Flags = 0;
3537 pSMB->Timeout = 0;
3538 pSMB->Reserved2 = 0;
3539 byte_count = params + 1 /* pad */ ;
3540 pSMB->TotalParameterCount = cpu_to_le16(params);
3541 pSMB->ParameterCount = pSMB->TotalParameterCount;
3542 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003543 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3544 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 pSMB->DataCount = 0;
3546 pSMB->DataOffset = 0;
3547 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3548 pSMB->Reserved3 = 0;
3549 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3550 pSMB->SearchAttributes =
3551 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3552 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003553 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3554 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555 CIFS_SEARCH_RETURN_RESUME);
3556 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3557
3558 /* BB what should we set StorageType to? Does it matter? BB */
3559 pSMB->SearchStorageType = 0;
3560 pSMB->hdr.smb_buf_length += byte_count;
3561 pSMB->ByteCount = cpu_to_le16(byte_count);
3562
3563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003565 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
Steve French88274812006-03-09 22:21:45 +00003567 if (rc) {/* BB add logic to retry regular search if Unix search
3568 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 /* BB Add code to handle unsupported level rc */
3570 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003571
Steve French88274812006-03-09 22:21:45 +00003572 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
3574 /* BB eventually could optimize out free and realloc of buf */
3575 /* for this case */
3576 if (rc == -EAGAIN)
3577 goto findFirstRetry;
3578 } else { /* decode response */
3579 /* BB remember to free buffer if error BB */
3580 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003581 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003582 unsigned int lnoff;
3583
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003585 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 else
Steve French4b18f2a2008-04-29 00:06:05 +00003587 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588
3589 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003590 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003591 psrch_inf->srch_entries_start =
3592 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3595 le16_to_cpu(pSMBr->t2.ParameterOffset));
3596
Steve French790fe572007-07-07 19:25:05 +00003597 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003598 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 else
Steve French4b18f2a2008-04-29 00:06:05 +00003600 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601
Steve French50c2f752007-07-13 00:33:32 +00003602 psrch_inf->entries_in_buffer =
3603 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003604 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003606 lnoff = le16_to_cpu(parms->LastNameOffset);
3607 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3608 lnoff) {
3609 cERROR(1, ("ignoring corrupt resume name"));
3610 psrch_inf->last_entry = NULL;
3611 return rc;
3612 }
3613
Steve French0752f152008-10-07 20:03:33 +00003614 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003615 lnoff;
3616
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 *pnetfid = parms->SearchHandle;
3618 } else {
3619 cifs_buf_release(pSMB);
3620 }
3621 }
3622
3623 return rc;
3624}
3625
3626int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003627 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628{
3629 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3630 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003631 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 char *response_data;
3633 int rc = 0;
3634 int bytes_returned, name_len;
3635 __u16 params, byte_count;
3636
3637 cFYI(1, ("In FindNext"));
3638
Steve French4b18f2a2008-04-29 00:06:05 +00003639 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 return -ENOENT;
3641
3642 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3643 (void **) &pSMBr);
3644 if (rc)
3645 return rc;
3646
Steve French50c2f752007-07-13 00:33:32 +00003647 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 byte_count = 0;
3649 pSMB->TotalDataCount = 0; /* no EAs */
3650 pSMB->MaxParameterCount = cpu_to_le16(8);
3651 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003652 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3653 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 pSMB->MaxSetupCount = 0;
3655 pSMB->Reserved = 0;
3656 pSMB->Flags = 0;
3657 pSMB->Timeout = 0;
3658 pSMB->Reserved2 = 0;
3659 pSMB->ParameterOffset = cpu_to_le16(
3660 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3661 pSMB->DataCount = 0;
3662 pSMB->DataOffset = 0;
3663 pSMB->SetupCount = 1;
3664 pSMB->Reserved3 = 0;
3665 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3666 pSMB->SearchHandle = searchHandle; /* always kept as le */
3667 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003668 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3670 pSMB->ResumeKey = psrch_inf->resume_key;
3671 pSMB->SearchFlags =
3672 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3673
3674 name_len = psrch_inf->resume_name_len;
3675 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003676 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3678 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003679 /* 14 byte parm len above enough for 2 byte null terminator */
3680 pSMB->ResumeFileName[name_len] = 0;
3681 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 } else {
3683 rc = -EINVAL;
3684 goto FNext2_err_exit;
3685 }
3686 byte_count = params + 1 /* pad */ ;
3687 pSMB->TotalParameterCount = cpu_to_le16(params);
3688 pSMB->ParameterCount = pSMB->TotalParameterCount;
3689 pSMB->hdr.smb_buf_length += byte_count;
3690 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003691
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3693 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003694 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 if (rc) {
3696 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003697 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003698 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003699 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 } else
3701 cFYI(1, ("FindNext returned = %d", rc));
3702 } else { /* decode response */
3703 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003704
Steve French790fe572007-07-07 19:25:05 +00003705 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003706 unsigned int lnoff;
3707
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 /* BB fixme add lock for file (srch_info) struct here */
3709 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003710 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 else
Steve French4b18f2a2008-04-29 00:06:05 +00003712 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 response_data = (char *) &pSMBr->hdr.Protocol +
3714 le16_to_cpu(pSMBr->t2.ParameterOffset);
3715 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3716 response_data = (char *)&pSMBr->hdr.Protocol +
3717 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003718 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003719 cifs_small_buf_release(
3720 psrch_inf->ntwrk_buf_start);
3721 else
3722 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 psrch_inf->srch_entries_start = response_data;
3724 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003725 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003726 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003727 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 else
Steve French4b18f2a2008-04-29 00:06:05 +00003729 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003730 psrch_inf->entries_in_buffer =
3731 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 psrch_inf->index_of_last_entry +=
3733 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003734 lnoff = le16_to_cpu(parms->LastNameOffset);
3735 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3736 lnoff) {
3737 cERROR(1, ("ignoring corrupt resume name"));
3738 psrch_inf->last_entry = NULL;
3739 return rc;
3740 } else
3741 psrch_inf->last_entry =
3742 psrch_inf->srch_entries_start + lnoff;
3743
Steve French50c2f752007-07-13 00:33:32 +00003744/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3745 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
3747 /* BB fixme add unlock here */
3748 }
3749
3750 }
3751
3752 /* BB On error, should we leave previous search buf (and count and
3753 last entry fields) intact or free the previous one? */
3754
3755 /* Note: On -EAGAIN error only caller can retry on handle based calls
3756 since file handle passed in no longer valid */
3757FNext2_err_exit:
3758 if (rc != 0)
3759 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 return rc;
3761}
3762
3763int
Steve French50c2f752007-07-13 00:33:32 +00003764CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3765 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766{
3767 int rc = 0;
3768 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769
3770 cFYI(1, ("In CIFSSMBFindClose"));
3771 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3772
3773 /* no sense returning error if session restarted
3774 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003775 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 return 0;
3777 if (rc)
3778 return rc;
3779
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 pSMB->FileID = searchHandle;
3781 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003782 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003783 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003785
Steve Frencha45443472005-08-24 13:59:35 -07003786 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787
3788 /* Since session is dead, search handle closed on server already */
3789 if (rc == -EAGAIN)
3790 rc = 0;
3791
3792 return rc;
3793}
3794
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795int
3796CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003797 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003798 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003799 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800{
3801 int rc = 0;
3802 TRANSACTION2_QPI_REQ *pSMB = NULL;
3803 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3804 int name_len, bytes_returned;
3805 __u16 params, byte_count;
3806
Steve French50c2f752007-07-13 00:33:32 +00003807 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003808 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003809 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810
3811GetInodeNumberRetry:
3812 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003813 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814 if (rc)
3815 return rc;
3816
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3818 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003819 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003820 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 name_len++; /* trailing null */
3822 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003823 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 name_len = strnlen(searchName, PATH_MAX);
3825 name_len++; /* trailing null */
3826 strncpy(pSMB->FileName, searchName, name_len);
3827 }
3828
3829 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3830 pSMB->TotalDataCount = 0;
3831 pSMB->MaxParameterCount = cpu_to_le16(2);
3832 /* BB find exact max data count below from sess structure BB */
3833 pSMB->MaxDataCount = cpu_to_le16(4000);
3834 pSMB->MaxSetupCount = 0;
3835 pSMB->Reserved = 0;
3836 pSMB->Flags = 0;
3837 pSMB->Timeout = 0;
3838 pSMB->Reserved2 = 0;
3839 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003840 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 pSMB->DataCount = 0;
3842 pSMB->DataOffset = 0;
3843 pSMB->SetupCount = 1;
3844 pSMB->Reserved3 = 0;
3845 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3846 byte_count = params + 1 /* pad */ ;
3847 pSMB->TotalParameterCount = cpu_to_le16(params);
3848 pSMB->ParameterCount = pSMB->TotalParameterCount;
3849 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3850 pSMB->Reserved4 = 0;
3851 pSMB->hdr.smb_buf_length += byte_count;
3852 pSMB->ByteCount = cpu_to_le16(byte_count);
3853
3854 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3855 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3856 if (rc) {
3857 cFYI(1, ("error %d in QueryInternalInfo", rc));
3858 } else {
3859 /* decode response */
3860 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3861 if (rc || (pSMBr->ByteCount < 2))
3862 /* BB also check enough total bytes returned */
3863 /* If rc should we check for EOPNOSUPP and
3864 disable the srvino flag? or in caller? */
3865 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003866 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3868 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003869 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003871 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3873 rc = -EIO;
3874 goto GetInodeNumOut;
3875 }
3876 pfinfo = (struct file_internal_info *)
3877 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003878 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 }
3880 }
3881GetInodeNumOut:
3882 cifs_buf_release(pSMB);
3883 if (rc == -EAGAIN)
3884 goto GetInodeNumberRetry;
3885 return rc;
3886}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
Igor Mammedovfec45852008-05-16 13:06:30 +04003888/* parses DFS refferal V3 structure
3889 * caller is responsible for freeing target_nodes
3890 * returns:
3891 * on success - 0
3892 * on failure - errno
3893 */
3894static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003895parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003896 unsigned int *num_of_nodes,
3897 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003898 const struct nls_table *nls_codepage, int remap,
3899 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003900{
3901 int i, rc = 0;
3902 char *data_end;
3903 bool is_unicode;
3904 struct dfs_referral_level_3 *ref;
3905
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003906 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3907 is_unicode = true;
3908 else
3909 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003910 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3911
3912 if (*num_of_nodes < 1) {
3913 cERROR(1, ("num_referrals: must be at least > 0,"
3914 "but we get num_referrals = %d\n", *num_of_nodes));
3915 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003916 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003917 }
3918
3919 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003920 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003921 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003922 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003923 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003924 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003925 }
3926
3927 /* get the upper boundary of the resp buffer */
3928 data_end = (char *)(&(pSMBr->PathConsumed)) +
3929 le16_to_cpu(pSMBr->t2.DataCount);
3930
3931 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3932 *num_of_nodes,
3933 le16_to_cpu(pSMBr->DFSFlags)));
3934
3935 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3936 *num_of_nodes, GFP_KERNEL);
3937 if (*target_nodes == NULL) {
3938 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3939 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003940 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003941 }
3942
3943 /* collect neccessary data from referrals */
3944 for (i = 0; i < *num_of_nodes; i++) {
3945 char *temp;
3946 int max_len;
3947 struct dfs_info3_param *node = (*target_nodes)+i;
3948
3949 node->flags = le16_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003950 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003951 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3952 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003953 cifsConvertToUCS((__le16 *) tmp, searchName,
3954 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003955 node->path_consumed = cifs_ucs2_bytes(tmp,
3956 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04003957 nls_codepage);
3958 kfree(tmp);
3959 } else
3960 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3961
Igor Mammedovfec45852008-05-16 13:06:30 +04003962 node->server_type = le16_to_cpu(ref->ServerType);
3963 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3964
3965 /* copy DfsPath */
3966 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3967 max_len = data_end - temp;
Jeff Layton066ce682009-04-30 07:16:14 -04003968 node->path_name = cifs_strndup(temp, max_len, is_unicode,
3969 nls_codepage);
3970 if (IS_ERR(node->path_name)) {
3971 rc = PTR_ERR(node->path_name);
3972 node->path_name = NULL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003973 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003974 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003975
3976 /* copy link target UNC */
3977 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3978 max_len = data_end - temp;
Jeff Layton066ce682009-04-30 07:16:14 -04003979 node->node_name = cifs_strndup(temp, max_len, is_unicode,
3980 nls_codepage);
3981 if (IS_ERR(node->node_name)) {
3982 rc = PTR_ERR(node->node_name);
3983 node->node_name = NULL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003984 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003985 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003986 }
3987
Steve Frencha1fe78f2008-05-16 18:48:38 +00003988parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04003989 if (rc) {
3990 free_dfs_info_array(*target_nodes, *num_of_nodes);
3991 *target_nodes = NULL;
3992 *num_of_nodes = 0;
3993 }
3994 return rc;
3995}
3996
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997int
3998CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3999 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004000 struct dfs_info3_param **target_nodes,
4001 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004002 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003{
4004/* TRANS2_GET_DFS_REFERRAL */
4005 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4006 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 int rc = 0;
4008 int bytes_returned;
4009 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004011 *num_of_nodes = 0;
4012 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013
4014 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4015 if (ses == NULL)
4016 return -ENODEV;
4017getDFSRetry:
4018 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4019 (void **) &pSMBr);
4020 if (rc)
4021 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004022
4023 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004024 but should never be null here anyway */
4025 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 pSMB->hdr.Tid = ses->ipc_tid;
4027 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004028 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004030 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032
4033 if (ses->capabilities & CAP_UNICODE) {
4034 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4035 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004036 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004037 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 name_len++; /* trailing null */
4039 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004040 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 name_len = strnlen(searchName, PATH_MAX);
4042 name_len++; /* trailing null */
4043 strncpy(pSMB->RequestFileName, searchName, name_len);
4044 }
4045
Steve French790fe572007-07-07 19:25:05 +00004046 if (ses->server) {
4047 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004048 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4049 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4050 }
4051
Steve French50c2f752007-07-13 00:33:32 +00004052 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004053
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 params = 2 /* level */ + name_len /*includes null */ ;
4055 pSMB->TotalDataCount = 0;
4056 pSMB->DataCount = 0;
4057 pSMB->DataOffset = 0;
4058 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004059 /* BB find exact max SMB PDU from sess structure BB */
4060 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 pSMB->MaxSetupCount = 0;
4062 pSMB->Reserved = 0;
4063 pSMB->Flags = 0;
4064 pSMB->Timeout = 0;
4065 pSMB->Reserved2 = 0;
4066 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004067 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 pSMB->SetupCount = 1;
4069 pSMB->Reserved3 = 0;
4070 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4071 byte_count = params + 3 /* pad */ ;
4072 pSMB->ParameterCount = cpu_to_le16(params);
4073 pSMB->TotalParameterCount = pSMB->ParameterCount;
4074 pSMB->MaxReferralLevel = cpu_to_le16(3);
4075 pSMB->hdr.smb_buf_length += byte_count;
4076 pSMB->ByteCount = cpu_to_le16(byte_count);
4077
4078 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4079 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4080 if (rc) {
4081 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004082 goto GetDFSRefExit;
4083 }
4084 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004086 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004087 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004088 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004089 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004091
4092 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4093 pSMBr->ByteCount,
4094 le16_to_cpu(pSMBr->t2.DataOffset)));
4095
4096 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004097 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004098 target_nodes, nls_codepage, remap,
4099 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004100
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004102 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103
4104 if (rc == -EAGAIN)
4105 goto getDFSRetry;
4106
4107 return rc;
4108}
4109
Steve French20962432005-09-21 22:05:57 -07004110/* Query File System Info such as free space to old servers such as Win 9x */
4111int
4112SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4113{
4114/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4115 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4116 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4117 FILE_SYSTEM_ALLOC_INFO *response_data;
4118 int rc = 0;
4119 int bytes_returned = 0;
4120 __u16 params, byte_count;
4121
4122 cFYI(1, ("OldQFSInfo"));
4123oldQFSInfoRetry:
4124 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4125 (void **) &pSMBr);
4126 if (rc)
4127 return rc;
Steve French20962432005-09-21 22:05:57 -07004128
4129 params = 2; /* level */
4130 pSMB->TotalDataCount = 0;
4131 pSMB->MaxParameterCount = cpu_to_le16(2);
4132 pSMB->MaxDataCount = cpu_to_le16(1000);
4133 pSMB->MaxSetupCount = 0;
4134 pSMB->Reserved = 0;
4135 pSMB->Flags = 0;
4136 pSMB->Timeout = 0;
4137 pSMB->Reserved2 = 0;
4138 byte_count = params + 1 /* pad */ ;
4139 pSMB->TotalParameterCount = cpu_to_le16(params);
4140 pSMB->ParameterCount = pSMB->TotalParameterCount;
4141 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4142 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4143 pSMB->DataCount = 0;
4144 pSMB->DataOffset = 0;
4145 pSMB->SetupCount = 1;
4146 pSMB->Reserved3 = 0;
4147 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4148 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4149 pSMB->hdr.smb_buf_length += byte_count;
4150 pSMB->ByteCount = cpu_to_le16(byte_count);
4151
4152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4153 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4154 if (rc) {
4155 cFYI(1, ("Send error in QFSInfo = %d", rc));
4156 } else { /* decode response */
4157 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4158
4159 if (rc || (pSMBr->ByteCount < 18))
4160 rc = -EIO; /* bad smb */
4161 else {
4162 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004163 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004164 pSMBr->ByteCount, data_offset));
4165
Steve French50c2f752007-07-13 00:33:32 +00004166 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004167 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4168 FSData->f_bsize =
4169 le16_to_cpu(response_data->BytesPerSector) *
4170 le32_to_cpu(response_data->
4171 SectorsPerAllocationUnit);
4172 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004173 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004174 FSData->f_bfree = FSData->f_bavail =
4175 le32_to_cpu(response_data->FreeAllocationUnits);
4176 cFYI(1,
4177 ("Blocks: %lld Free: %lld Block size %ld",
4178 (unsigned long long)FSData->f_blocks,
4179 (unsigned long long)FSData->f_bfree,
4180 FSData->f_bsize));
4181 }
4182 }
4183 cifs_buf_release(pSMB);
4184
4185 if (rc == -EAGAIN)
4186 goto oldQFSInfoRetry;
4187
4188 return rc;
4189}
4190
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191int
Steve French737b7582005-04-28 22:41:06 -07004192CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193{
4194/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4195 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4196 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4197 FILE_SYSTEM_INFO *response_data;
4198 int rc = 0;
4199 int bytes_returned = 0;
4200 __u16 params, byte_count;
4201
4202 cFYI(1, ("In QFSInfo"));
4203QFSInfoRetry:
4204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4205 (void **) &pSMBr);
4206 if (rc)
4207 return rc;
4208
4209 params = 2; /* level */
4210 pSMB->TotalDataCount = 0;
4211 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004212 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 pSMB->MaxSetupCount = 0;
4214 pSMB->Reserved = 0;
4215 pSMB->Flags = 0;
4216 pSMB->Timeout = 0;
4217 pSMB->Reserved2 = 0;
4218 byte_count = params + 1 /* pad */ ;
4219 pSMB->TotalParameterCount = cpu_to_le16(params);
4220 pSMB->ParameterCount = pSMB->TotalParameterCount;
4221 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004222 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 pSMB->DataCount = 0;
4224 pSMB->DataOffset = 0;
4225 pSMB->SetupCount = 1;
4226 pSMB->Reserved3 = 0;
4227 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4228 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4229 pSMB->hdr.smb_buf_length += byte_count;
4230 pSMB->ByteCount = cpu_to_le16(byte_count);
4231
4232 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4233 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4234 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004235 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004237 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238
Steve French20962432005-09-21 22:05:57 -07004239 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 rc = -EIO; /* bad smb */
4241 else {
4242 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
4244 response_data =
4245 (FILE_SYSTEM_INFO
4246 *) (((char *) &pSMBr->hdr.Protocol) +
4247 data_offset);
4248 FSData->f_bsize =
4249 le32_to_cpu(response_data->BytesPerSector) *
4250 le32_to_cpu(response_data->
4251 SectorsPerAllocationUnit);
4252 FSData->f_blocks =
4253 le64_to_cpu(response_data->TotalAllocationUnits);
4254 FSData->f_bfree = FSData->f_bavail =
4255 le64_to_cpu(response_data->FreeAllocationUnits);
4256 cFYI(1,
4257 ("Blocks: %lld Free: %lld Block size %ld",
4258 (unsigned long long)FSData->f_blocks,
4259 (unsigned long long)FSData->f_bfree,
4260 FSData->f_bsize));
4261 }
4262 }
4263 cifs_buf_release(pSMB);
4264
4265 if (rc == -EAGAIN)
4266 goto QFSInfoRetry;
4267
4268 return rc;
4269}
4270
4271int
Steve French737b7582005-04-28 22:41:06 -07004272CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273{
4274/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4275 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4276 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4277 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4278 int rc = 0;
4279 int bytes_returned = 0;
4280 __u16 params, byte_count;
4281
4282 cFYI(1, ("In QFSAttributeInfo"));
4283QFSAttributeRetry:
4284 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4285 (void **) &pSMBr);
4286 if (rc)
4287 return rc;
4288
4289 params = 2; /* level */
4290 pSMB->TotalDataCount = 0;
4291 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004292 /* BB find exact max SMB PDU from sess structure BB */
4293 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 pSMB->MaxSetupCount = 0;
4295 pSMB->Reserved = 0;
4296 pSMB->Flags = 0;
4297 pSMB->Timeout = 0;
4298 pSMB->Reserved2 = 0;
4299 byte_count = params + 1 /* pad */ ;
4300 pSMB->TotalParameterCount = cpu_to_le16(params);
4301 pSMB->ParameterCount = pSMB->TotalParameterCount;
4302 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004303 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 pSMB->DataCount = 0;
4305 pSMB->DataOffset = 0;
4306 pSMB->SetupCount = 1;
4307 pSMB->Reserved3 = 0;
4308 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4309 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4310 pSMB->hdr.smb_buf_length += byte_count;
4311 pSMB->ByteCount = cpu_to_le16(byte_count);
4312
4313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4314 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4315 if (rc) {
4316 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4317 } else { /* decode response */
4318 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4319
Steve French50c2f752007-07-13 00:33:32 +00004320 if (rc || (pSMBr->ByteCount < 13)) {
4321 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 rc = -EIO; /* bad smb */
4323 } else {
4324 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4325 response_data =
4326 (FILE_SYSTEM_ATTRIBUTE_INFO
4327 *) (((char *) &pSMBr->hdr.Protocol) +
4328 data_offset);
4329 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004330 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004331 }
4332 }
4333 cifs_buf_release(pSMB);
4334
4335 if (rc == -EAGAIN)
4336 goto QFSAttributeRetry;
4337
4338 return rc;
4339}
4340
4341int
Steve French737b7582005-04-28 22:41:06 -07004342CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343{
4344/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4345 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4346 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4347 FILE_SYSTEM_DEVICE_INFO *response_data;
4348 int rc = 0;
4349 int bytes_returned = 0;
4350 __u16 params, byte_count;
4351
4352 cFYI(1, ("In QFSDeviceInfo"));
4353QFSDeviceRetry:
4354 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4355 (void **) &pSMBr);
4356 if (rc)
4357 return rc;
4358
4359 params = 2; /* level */
4360 pSMB->TotalDataCount = 0;
4361 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004362 /* BB find exact max SMB PDU from sess structure BB */
4363 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 pSMB->MaxSetupCount = 0;
4365 pSMB->Reserved = 0;
4366 pSMB->Flags = 0;
4367 pSMB->Timeout = 0;
4368 pSMB->Reserved2 = 0;
4369 byte_count = params + 1 /* pad */ ;
4370 pSMB->TotalParameterCount = cpu_to_le16(params);
4371 pSMB->ParameterCount = pSMB->TotalParameterCount;
4372 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004373 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
4375 pSMB->DataCount = 0;
4376 pSMB->DataOffset = 0;
4377 pSMB->SetupCount = 1;
4378 pSMB->Reserved3 = 0;
4379 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4380 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4381 pSMB->hdr.smb_buf_length += byte_count;
4382 pSMB->ByteCount = cpu_to_le16(byte_count);
4383
4384 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4385 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4386 if (rc) {
4387 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4388 } else { /* decode response */
4389 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4390
Steve French630f3f0c2007-10-25 21:17:17 +00004391 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 rc = -EIO; /* bad smb */
4393 else {
4394 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4395 response_data =
Steve French737b7582005-04-28 22:41:06 -07004396 (FILE_SYSTEM_DEVICE_INFO *)
4397 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 data_offset);
4399 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004400 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 }
4402 }
4403 cifs_buf_release(pSMB);
4404
4405 if (rc == -EAGAIN)
4406 goto QFSDeviceRetry;
4407
4408 return rc;
4409}
4410
4411int
Steve French737b7582005-04-28 22:41:06 -07004412CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413{
4414/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4415 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4416 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4417 FILE_SYSTEM_UNIX_INFO *response_data;
4418 int rc = 0;
4419 int bytes_returned = 0;
4420 __u16 params, byte_count;
4421
4422 cFYI(1, ("In QFSUnixInfo"));
4423QFSUnixRetry:
4424 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4425 (void **) &pSMBr);
4426 if (rc)
4427 return rc;
4428
4429 params = 2; /* level */
4430 pSMB->TotalDataCount = 0;
4431 pSMB->DataCount = 0;
4432 pSMB->DataOffset = 0;
4433 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004434 /* BB find exact max SMB PDU from sess structure BB */
4435 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 pSMB->MaxSetupCount = 0;
4437 pSMB->Reserved = 0;
4438 pSMB->Flags = 0;
4439 pSMB->Timeout = 0;
4440 pSMB->Reserved2 = 0;
4441 byte_count = params + 1 /* pad */ ;
4442 pSMB->ParameterCount = cpu_to_le16(params);
4443 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004444 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4445 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 pSMB->SetupCount = 1;
4447 pSMB->Reserved3 = 0;
4448 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4449 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4450 pSMB->hdr.smb_buf_length += byte_count;
4451 pSMB->ByteCount = cpu_to_le16(byte_count);
4452
4453 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4454 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4455 if (rc) {
4456 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4457 } else { /* decode response */
4458 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4459
4460 if (rc || (pSMBr->ByteCount < 13)) {
4461 rc = -EIO; /* bad smb */
4462 } else {
4463 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4464 response_data =
4465 (FILE_SYSTEM_UNIX_INFO
4466 *) (((char *) &pSMBr->hdr.Protocol) +
4467 data_offset);
4468 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004469 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 }
4471 }
4472 cifs_buf_release(pSMB);
4473
4474 if (rc == -EAGAIN)
4475 goto QFSUnixRetry;
4476
4477
4478 return rc;
4479}
4480
Jeremy Allisonac670552005-06-22 17:26:35 -07004481int
Steve French45abc6e2005-06-23 13:42:03 -05004482CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004483{
4484/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4485 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4486 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4487 int rc = 0;
4488 int bytes_returned = 0;
4489 __u16 params, param_offset, offset, byte_count;
4490
4491 cFYI(1, ("In SETFSUnixInfo"));
4492SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004493 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004494 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4495 (void **) &pSMBr);
4496 if (rc)
4497 return rc;
4498
4499 params = 4; /* 2 bytes zero followed by info level. */
4500 pSMB->MaxSetupCount = 0;
4501 pSMB->Reserved = 0;
4502 pSMB->Flags = 0;
4503 pSMB->Timeout = 0;
4504 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004505 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4506 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004507 offset = param_offset + params;
4508
4509 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004510 /* BB find exact max SMB PDU from sess structure BB */
4511 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004512 pSMB->SetupCount = 1;
4513 pSMB->Reserved3 = 0;
4514 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4515 byte_count = 1 /* pad */ + params + 12;
4516
4517 pSMB->DataCount = cpu_to_le16(12);
4518 pSMB->ParameterCount = cpu_to_le16(params);
4519 pSMB->TotalDataCount = pSMB->DataCount;
4520 pSMB->TotalParameterCount = pSMB->ParameterCount;
4521 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4522 pSMB->DataOffset = cpu_to_le16(offset);
4523
4524 /* Params. */
4525 pSMB->FileNum = 0;
4526 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4527
4528 /* Data. */
4529 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4530 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4531 pSMB->ClientUnixCap = cpu_to_le64(cap);
4532
4533 pSMB->hdr.smb_buf_length += byte_count;
4534 pSMB->ByteCount = cpu_to_le16(byte_count);
4535
4536 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4537 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4538 if (rc) {
4539 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4540 } else { /* decode response */
4541 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004542 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004543 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004544 }
4545 cifs_buf_release(pSMB);
4546
4547 if (rc == -EAGAIN)
4548 goto SETFSUnixRetry;
4549
4550 return rc;
4551}
4552
4553
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554
4555int
4556CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004557 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558{
4559/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4560 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4561 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4562 FILE_SYSTEM_POSIX_INFO *response_data;
4563 int rc = 0;
4564 int bytes_returned = 0;
4565 __u16 params, byte_count;
4566
4567 cFYI(1, ("In QFSPosixInfo"));
4568QFSPosixRetry:
4569 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4570 (void **) &pSMBr);
4571 if (rc)
4572 return rc;
4573
4574 params = 2; /* level */
4575 pSMB->TotalDataCount = 0;
4576 pSMB->DataCount = 0;
4577 pSMB->DataOffset = 0;
4578 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004579 /* BB find exact max SMB PDU from sess structure BB */
4580 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581 pSMB->MaxSetupCount = 0;
4582 pSMB->Reserved = 0;
4583 pSMB->Flags = 0;
4584 pSMB->Timeout = 0;
4585 pSMB->Reserved2 = 0;
4586 byte_count = params + 1 /* pad */ ;
4587 pSMB->ParameterCount = cpu_to_le16(params);
4588 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004589 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4590 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 pSMB->SetupCount = 1;
4592 pSMB->Reserved3 = 0;
4593 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4594 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4595 pSMB->hdr.smb_buf_length += byte_count;
4596 pSMB->ByteCount = cpu_to_le16(byte_count);
4597
4598 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4599 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4600 if (rc) {
4601 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4602 } else { /* decode response */
4603 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4604
4605 if (rc || (pSMBr->ByteCount < 13)) {
4606 rc = -EIO; /* bad smb */
4607 } else {
4608 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4609 response_data =
4610 (FILE_SYSTEM_POSIX_INFO
4611 *) (((char *) &pSMBr->hdr.Protocol) +
4612 data_offset);
4613 FSData->f_bsize =
4614 le32_to_cpu(response_data->BlockSize);
4615 FSData->f_blocks =
4616 le64_to_cpu(response_data->TotalBlocks);
4617 FSData->f_bfree =
4618 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004619 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 FSData->f_bavail = FSData->f_bfree;
4621 } else {
4622 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004623 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 }
Steve French790fe572007-07-07 19:25:05 +00004625 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004627 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004628 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004630 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 }
4632 }
4633 cifs_buf_release(pSMB);
4634
4635 if (rc == -EAGAIN)
4636 goto QFSPosixRetry;
4637
4638 return rc;
4639}
4640
4641
Steve French50c2f752007-07-13 00:33:32 +00004642/* We can not use write of zero bytes trick to
4643 set file size due to need for large file support. Also note that
4644 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 routine which is only needed to work around a sharing violation bug
4646 in Samba which this routine can run into */
4647
4648int
4649CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004650 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004651 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652{
4653 struct smb_com_transaction2_spi_req *pSMB = NULL;
4654 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4655 struct file_end_of_file_info *parm_data;
4656 int name_len;
4657 int rc = 0;
4658 int bytes_returned = 0;
4659 __u16 params, byte_count, data_count, param_offset, offset;
4660
4661 cFYI(1, ("In SetEOF"));
4662SetEOFRetry:
4663 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4664 (void **) &pSMBr);
4665 if (rc)
4666 return rc;
4667
4668 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4669 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004670 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004671 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 name_len++; /* trailing null */
4673 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004674 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 name_len = strnlen(fileName, PATH_MAX);
4676 name_len++; /* trailing null */
4677 strncpy(pSMB->FileName, fileName, name_len);
4678 }
4679 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004680 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004682 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 pSMB->MaxSetupCount = 0;
4684 pSMB->Reserved = 0;
4685 pSMB->Flags = 0;
4686 pSMB->Timeout = 0;
4687 pSMB->Reserved2 = 0;
4688 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004689 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004691 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004692 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4693 pSMB->InformationLevel =
4694 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4695 else
4696 pSMB->InformationLevel =
4697 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4698 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4700 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004701 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 else
4703 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004704 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 }
4706
4707 parm_data =
4708 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4709 offset);
4710 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4711 pSMB->DataOffset = cpu_to_le16(offset);
4712 pSMB->SetupCount = 1;
4713 pSMB->Reserved3 = 0;
4714 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4715 byte_count = 3 /* pad */ + params + data_count;
4716 pSMB->DataCount = cpu_to_le16(data_count);
4717 pSMB->TotalDataCount = pSMB->DataCount;
4718 pSMB->ParameterCount = cpu_to_le16(params);
4719 pSMB->TotalParameterCount = pSMB->ParameterCount;
4720 pSMB->Reserved4 = 0;
4721 pSMB->hdr.smb_buf_length += byte_count;
4722 parm_data->FileSize = cpu_to_le64(size);
4723 pSMB->ByteCount = cpu_to_le16(byte_count);
4724 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4725 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004726 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728
4729 cifs_buf_release(pSMB);
4730
4731 if (rc == -EAGAIN)
4732 goto SetEOFRetry;
4733
4734 return rc;
4735}
4736
4737int
Steve French50c2f752007-07-13 00:33:32 +00004738CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004739 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740{
4741 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 char *data_offset;
4743 struct file_end_of_file_info *parm_data;
4744 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 __u16 params, param_offset, offset, byte_count, count;
4746
4747 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4748 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004749 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4750
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 if (rc)
4752 return rc;
4753
4754 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4755 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004756
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 params = 6;
4758 pSMB->MaxSetupCount = 0;
4759 pSMB->Reserved = 0;
4760 pSMB->Flags = 0;
4761 pSMB->Timeout = 0;
4762 pSMB->Reserved2 = 0;
4763 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4764 offset = param_offset + params;
4765
Steve French50c2f752007-07-13 00:33:32 +00004766 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767
4768 count = sizeof(struct file_end_of_file_info);
4769 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004770 /* BB find exact max SMB PDU from sess structure BB */
4771 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 pSMB->SetupCount = 1;
4773 pSMB->Reserved3 = 0;
4774 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4775 byte_count = 3 /* pad */ + params + count;
4776 pSMB->DataCount = cpu_to_le16(count);
4777 pSMB->ParameterCount = cpu_to_le16(params);
4778 pSMB->TotalDataCount = pSMB->DataCount;
4779 pSMB->TotalParameterCount = pSMB->ParameterCount;
4780 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4781 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004782 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4783 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 pSMB->DataOffset = cpu_to_le16(offset);
4785 parm_data->FileSize = cpu_to_le64(size);
4786 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004787 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4789 pSMB->InformationLevel =
4790 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4791 else
4792 pSMB->InformationLevel =
4793 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004794 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4796 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004797 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 else
4799 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004800 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 }
4802 pSMB->Reserved4 = 0;
4803 pSMB->hdr.smb_buf_length += byte_count;
4804 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004805 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 if (rc) {
4807 cFYI(1,
4808 ("Send error in SetFileInfo (SetFileSize) = %d",
4809 rc));
4810 }
4811
Steve French50c2f752007-07-13 00:33:32 +00004812 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 since file handle passed in no longer valid */
4814
4815 return rc;
4816}
4817
Steve French50c2f752007-07-13 00:33:32 +00004818/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 an open handle, rather than by pathname - this is awkward due to
4820 potential access conflicts on the open, but it is unavoidable for these
4821 old servers since the only other choice is to go from 100 nanosecond DCE
4822 time and resort to the original setpathinfo level which takes the ancient
4823 DOS time format with 2 second granularity */
4824int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004825CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4826 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827{
4828 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 char *data_offset;
4830 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 __u16 params, param_offset, offset, byte_count, count;
4832
4833 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004834 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4835
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 if (rc)
4837 return rc;
4838
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004839 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4840 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004841
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 params = 6;
4843 pSMB->MaxSetupCount = 0;
4844 pSMB->Reserved = 0;
4845 pSMB->Flags = 0;
4846 pSMB->Timeout = 0;
4847 pSMB->Reserved2 = 0;
4848 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4849 offset = param_offset + params;
4850
Steve French50c2f752007-07-13 00:33:32 +00004851 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852
Steve French26f57362007-08-30 22:09:15 +00004853 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004855 /* BB find max SMB PDU from sess */
4856 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 pSMB->SetupCount = 1;
4858 pSMB->Reserved3 = 0;
4859 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4860 byte_count = 3 /* pad */ + params + count;
4861 pSMB->DataCount = cpu_to_le16(count);
4862 pSMB->ParameterCount = cpu_to_le16(params);
4863 pSMB->TotalDataCount = pSMB->DataCount;
4864 pSMB->TotalParameterCount = pSMB->ParameterCount;
4865 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4866 pSMB->DataOffset = cpu_to_le16(offset);
4867 pSMB->Fid = fid;
4868 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4869 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4870 else
4871 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4872 pSMB->Reserved4 = 0;
4873 pSMB->hdr.smb_buf_length += byte_count;
4874 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004875 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004876 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004877 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004878 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879
Steve French50c2f752007-07-13 00:33:32 +00004880 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 since file handle passed in no longer valid */
4882
4883 return rc;
4884}
4885
Jeff Layton6d22f092008-09-23 11:48:35 -04004886int
4887CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4888 bool delete_file, __u16 fid, __u32 pid_of_opener)
4889{
4890 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4891 char *data_offset;
4892 int rc = 0;
4893 __u16 params, param_offset, offset, byte_count, count;
4894
4895 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4896 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4897
4898 if (rc)
4899 return rc;
4900
4901 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4902 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4903
4904 params = 6;
4905 pSMB->MaxSetupCount = 0;
4906 pSMB->Reserved = 0;
4907 pSMB->Flags = 0;
4908 pSMB->Timeout = 0;
4909 pSMB->Reserved2 = 0;
4910 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4911 offset = param_offset + params;
4912
4913 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4914
4915 count = 1;
4916 pSMB->MaxParameterCount = cpu_to_le16(2);
4917 /* BB find max SMB PDU from sess */
4918 pSMB->MaxDataCount = cpu_to_le16(1000);
4919 pSMB->SetupCount = 1;
4920 pSMB->Reserved3 = 0;
4921 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4922 byte_count = 3 /* pad */ + params + count;
4923 pSMB->DataCount = cpu_to_le16(count);
4924 pSMB->ParameterCount = cpu_to_le16(params);
4925 pSMB->TotalDataCount = pSMB->DataCount;
4926 pSMB->TotalParameterCount = pSMB->ParameterCount;
4927 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4928 pSMB->DataOffset = cpu_to_le16(offset);
4929 pSMB->Fid = fid;
4930 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4931 pSMB->Reserved4 = 0;
4932 pSMB->hdr.smb_buf_length += byte_count;
4933 pSMB->ByteCount = cpu_to_le16(byte_count);
4934 *data_offset = delete_file ? 1 : 0;
4935 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4936 if (rc)
4937 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4938
4939 return rc;
4940}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941
4942int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004943CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4944 const char *fileName, const FILE_BASIC_INFO *data,
4945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946{
4947 TRANSACTION2_SPI_REQ *pSMB = NULL;
4948 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4949 int name_len;
4950 int rc = 0;
4951 int bytes_returned = 0;
4952 char *data_offset;
4953 __u16 params, param_offset, offset, byte_count, count;
4954
4955 cFYI(1, ("In SetTimes"));
4956
4957SetTimesRetry:
4958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4959 (void **) &pSMBr);
4960 if (rc)
4961 return rc;
4962
4963 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4964 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004965 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004966 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 name_len++; /* trailing null */
4968 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004969 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970 name_len = strnlen(fileName, PATH_MAX);
4971 name_len++; /* trailing null */
4972 strncpy(pSMB->FileName, fileName, name_len);
4973 }
4974
4975 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004976 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004978 /* BB find max SMB PDU from sess structure BB */
4979 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 pSMB->MaxSetupCount = 0;
4981 pSMB->Reserved = 0;
4982 pSMB->Flags = 0;
4983 pSMB->Timeout = 0;
4984 pSMB->Reserved2 = 0;
4985 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004986 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 offset = param_offset + params;
4988 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4989 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4990 pSMB->DataOffset = cpu_to_le16(offset);
4991 pSMB->SetupCount = 1;
4992 pSMB->Reserved3 = 0;
4993 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4994 byte_count = 3 /* pad */ + params + count;
4995
4996 pSMB->DataCount = cpu_to_le16(count);
4997 pSMB->ParameterCount = cpu_to_le16(params);
4998 pSMB->TotalDataCount = pSMB->DataCount;
4999 pSMB->TotalParameterCount = pSMB->ParameterCount;
5000 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5001 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5002 else
5003 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5004 pSMB->Reserved4 = 0;
5005 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005006 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 pSMB->ByteCount = cpu_to_le16(byte_count);
5008 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5009 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005010 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012
5013 cifs_buf_release(pSMB);
5014
5015 if (rc == -EAGAIN)
5016 goto SetTimesRetry;
5017
5018 return rc;
5019}
5020
5021/* Can not be used to set time stamps yet (due to old DOS time format) */
5022/* Can be used to set attributes */
5023#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5024 handling it anyway and NT4 was what we thought it would be needed for
5025 Do not delete it until we prove whether needed for Win9x though */
5026int
5027CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5028 __u16 dos_attrs, const struct nls_table *nls_codepage)
5029{
5030 SETATTR_REQ *pSMB = NULL;
5031 SETATTR_RSP *pSMBr = NULL;
5032 int rc = 0;
5033 int bytes_returned;
5034 int name_len;
5035
5036 cFYI(1, ("In SetAttrLegacy"));
5037
5038SetAttrLgcyRetry:
5039 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5040 (void **) &pSMBr);
5041 if (rc)
5042 return rc;
5043
5044 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5045 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005046 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 PATH_MAX, nls_codepage);
5048 name_len++; /* trailing null */
5049 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005050 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 name_len = strnlen(fileName, PATH_MAX);
5052 name_len++; /* trailing null */
5053 strncpy(pSMB->fileName, fileName, name_len);
5054 }
5055 pSMB->attr = cpu_to_le16(dos_attrs);
5056 pSMB->BufferFormat = 0x04;
5057 pSMB->hdr.smb_buf_length += name_len + 1;
5058 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5059 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005061 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063
5064 cifs_buf_release(pSMB);
5065
5066 if (rc == -EAGAIN)
5067 goto SetAttrLgcyRetry;
5068
5069 return rc;
5070}
5071#endif /* temporarily unneeded SetAttr legacy function */
5072
5073int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005074CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005075 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005076 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077{
5078 TRANSACTION2_SPI_REQ *pSMB = NULL;
5079 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5080 int name_len;
5081 int rc = 0;
5082 int bytes_returned = 0;
5083 FILE_UNIX_BASIC_INFO *data_offset;
5084 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005085 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005086
5087 cFYI(1, ("In SetUID/GID/Mode"));
5088setPermsRetry:
5089 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5090 (void **) &pSMBr);
5091 if (rc)
5092 return rc;
5093
5094 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5095 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005096 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005097 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 name_len++; /* trailing null */
5099 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005100 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 name_len = strnlen(fileName, PATH_MAX);
5102 name_len++; /* trailing null */
5103 strncpy(pSMB->FileName, fileName, name_len);
5104 }
5105
5106 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005107 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005109 /* BB find max SMB PDU from sess structure BB */
5110 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 pSMB->MaxSetupCount = 0;
5112 pSMB->Reserved = 0;
5113 pSMB->Flags = 0;
5114 pSMB->Timeout = 0;
5115 pSMB->Reserved2 = 0;
5116 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005117 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118 offset = param_offset + params;
5119 data_offset =
5120 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5121 offset);
5122 memset(data_offset, 0, count);
5123 pSMB->DataOffset = cpu_to_le16(offset);
5124 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5125 pSMB->SetupCount = 1;
5126 pSMB->Reserved3 = 0;
5127 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5128 byte_count = 3 /* pad */ + params + count;
5129 pSMB->ParameterCount = cpu_to_le16(params);
5130 pSMB->DataCount = cpu_to_le16(count);
5131 pSMB->TotalParameterCount = pSMB->ParameterCount;
5132 pSMB->TotalDataCount = pSMB->DataCount;
5133 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5134 pSMB->Reserved4 = 0;
5135 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005136 /* Samba server ignores set of file size to zero due to bugs in some
5137 older clients, but we should be precise - we use SetFileSize to
5138 set file size and do not want to truncate file size to zero
5139 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005140 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005141 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5142 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5143 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5144 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5145 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5146 data_offset->Uid = cpu_to_le64(args->uid);
5147 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005149 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5150 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005152
Steve French790fe572007-07-07 19:25:05 +00005153 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005155 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005157 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005159 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005161 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005163 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005165 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5167
5168
5169 pSMB->ByteCount = cpu_to_le16(byte_count);
5170 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5171 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005172 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174
Steve French0d817bc2008-05-22 02:02:03 +00005175 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 if (rc == -EAGAIN)
5177 goto setPermsRetry;
5178 return rc;
5179}
5180
Steve French50c2f752007-07-13 00:33:32 +00005181int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005182 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005183 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005184 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185{
5186 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005187 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5188 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005189 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 int bytes_returned;
5191
Steve French50c2f752007-07-13 00:33:32 +00005192 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005194 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 if (rc)
5196 return rc;
5197
5198 pSMB->TotalParameterCount = 0 ;
5199 pSMB->TotalDataCount = 0;
5200 pSMB->MaxParameterCount = cpu_to_le32(2);
5201 /* BB find exact data count max from sess structure BB */
5202 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005203/* BB VERIFY verify which is correct for above BB */
5204 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5205 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5206
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pSMB->MaxSetupCount = 4;
5208 pSMB->Reserved = 0;
5209 pSMB->ParameterOffset = 0;
5210 pSMB->DataCount = 0;
5211 pSMB->DataOffset = 0;
5212 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5213 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5214 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005215 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5217 pSMB->Reserved2 = 0;
5218 pSMB->CompletionFilter = cpu_to_le32(filter);
5219 pSMB->Fid = netfid; /* file handle always le */
5220 pSMB->ByteCount = 0;
5221
5222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005223 (struct smb_hdr *)pSMBr, &bytes_returned,
5224 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 if (rc) {
5226 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005227 } else {
5228 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005229 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005230 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005231 sizeof(struct dir_notify_req),
5232 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005233 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005234 dnotify_req->Pid = pSMB->hdr.Pid;
5235 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5236 dnotify_req->Mid = pSMB->hdr.Mid;
5237 dnotify_req->Tid = pSMB->hdr.Tid;
5238 dnotify_req->Uid = pSMB->hdr.Uid;
5239 dnotify_req->netfid = netfid;
5240 dnotify_req->pfile = pfile;
5241 dnotify_req->filter = filter;
5242 dnotify_req->multishot = multishot;
5243 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005244 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005245 &GlobalDnotifyReqList);
5246 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005247 } else
Steve French47c786e2005-10-11 20:03:18 -07005248 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 }
5250 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005251 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252}
5253#ifdef CONFIG_CIFS_XATTR
5254ssize_t
5255CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5256 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005257 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005258 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259{
5260 /* BB assumes one setup word */
5261 TRANSACTION2_QPI_REQ *pSMB = NULL;
5262 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5263 int rc = 0;
5264 int bytes_returned;
5265 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005266 struct fea *temp_fea;
5267 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 __u16 params, byte_count;
5269
5270 cFYI(1, ("In Query All EAs path %s", searchName));
5271QAllEAsRetry:
5272 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5273 (void **) &pSMBr);
5274 if (rc)
5275 return rc;
5276
5277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5278 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005279 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005280 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 name_len++; /* trailing null */
5282 name_len *= 2;
5283 } else { /* BB improve the check for buffer overruns BB */
5284 name_len = strnlen(searchName, PATH_MAX);
5285 name_len++; /* trailing null */
5286 strncpy(pSMB->FileName, searchName, name_len);
5287 }
5288
Steve French50c2f752007-07-13 00:33:32 +00005289 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 pSMB->TotalDataCount = 0;
5291 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005292 /* BB find exact max SMB PDU from sess structure BB */
5293 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 pSMB->MaxSetupCount = 0;
5295 pSMB->Reserved = 0;
5296 pSMB->Flags = 0;
5297 pSMB->Timeout = 0;
5298 pSMB->Reserved2 = 0;
5299 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005300 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 pSMB->DataCount = 0;
5302 pSMB->DataOffset = 0;
5303 pSMB->SetupCount = 1;
5304 pSMB->Reserved3 = 0;
5305 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5306 byte_count = params + 1 /* pad */ ;
5307 pSMB->TotalParameterCount = cpu_to_le16(params);
5308 pSMB->ParameterCount = pSMB->TotalParameterCount;
5309 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5310 pSMB->Reserved4 = 0;
5311 pSMB->hdr.smb_buf_length += byte_count;
5312 pSMB->ByteCount = cpu_to_le16(byte_count);
5313
5314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5315 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5316 if (rc) {
5317 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5318 } else { /* decode response */
5319 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5320
5321 /* BB also check enough total bytes returned */
5322 /* BB we need to improve the validity checking
5323 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005324 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 rc = -EIO; /* bad smb */
5326 /* else if (pFindData){
5327 memcpy((char *) pFindData,
5328 (char *) &pSMBr->hdr.Protocol +
5329 data_offset, kl);
5330 }*/ else {
5331 /* check that length of list is not more than bcc */
5332 /* check that each entry does not go beyond length
5333 of list */
5334 /* check that each element of each entry does not
5335 go beyond end of list */
5336 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005337 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338 rc = 0;
5339 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005340 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 ea_response_data = (struct fealist *)
5342 (((char *) &pSMBr->hdr.Protocol) +
5343 data_offset);
5344 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005345 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005346 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005347 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005348 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 } else {
5350 /* account for ea list len */
5351 name_len -= 4;
5352 temp_fea = ea_response_data->list;
5353 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005354 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 __u16 value_len;
5356 name_len -= 4;
5357 temp_ptr += 4;
5358 rc += temp_fea->name_len;
5359 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005360 rc = rc + 5 + 1;
5361 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005362 memcpy(EAData, "user.", 5);
5363 EAData += 5;
5364 memcpy(EAData, temp_ptr,
5365 temp_fea->name_len);
5366 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 /* null terminate name */
5368 *EAData = 0;
5369 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005370 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 /* skip copy - calc size only */
5372 } else {
5373 /* stop before overrun buffer */
5374 rc = -ERANGE;
5375 break;
5376 }
5377 name_len -= temp_fea->name_len;
5378 temp_ptr += temp_fea->name_len;
5379 /* account for trailing null */
5380 name_len--;
5381 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005382 value_len =
5383 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 name_len -= value_len;
5385 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005386 /* BB check that temp_ptr is still
5387 within the SMB BB*/
5388
5389 /* no trailing null to account for
5390 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 /* go on to next EA */
5392 temp_fea = (struct fea *)temp_ptr;
5393 }
5394 }
5395 }
5396 }
Steve French0d817bc2008-05-22 02:02:03 +00005397 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 if (rc == -EAGAIN)
5399 goto QAllEAsRetry;
5400
5401 return (ssize_t)rc;
5402}
5403
Steve French50c2f752007-07-13 00:33:32 +00005404ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5405 const unsigned char *searchName, const unsigned char *ea_name,
5406 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005407 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408{
5409 TRANSACTION2_QPI_REQ *pSMB = NULL;
5410 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5411 int rc = 0;
5412 int bytes_returned;
5413 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005414 struct fea *temp_fea;
5415 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 __u16 params, byte_count;
5417
5418 cFYI(1, ("In Query EA path %s", searchName));
5419QEARetry:
5420 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5421 (void **) &pSMBr);
5422 if (rc)
5423 return rc;
5424
5425 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5426 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005427 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005428 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 name_len++; /* trailing null */
5430 name_len *= 2;
5431 } else { /* BB improve the check for buffer overruns BB */
5432 name_len = strnlen(searchName, PATH_MAX);
5433 name_len++; /* trailing null */
5434 strncpy(pSMB->FileName, searchName, name_len);
5435 }
5436
Steve French50c2f752007-07-13 00:33:32 +00005437 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 pSMB->TotalDataCount = 0;
5439 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005440 /* BB find exact max SMB PDU from sess structure BB */
5441 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 pSMB->MaxSetupCount = 0;
5443 pSMB->Reserved = 0;
5444 pSMB->Flags = 0;
5445 pSMB->Timeout = 0;
5446 pSMB->Reserved2 = 0;
5447 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005448 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 pSMB->DataCount = 0;
5450 pSMB->DataOffset = 0;
5451 pSMB->SetupCount = 1;
5452 pSMB->Reserved3 = 0;
5453 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5454 byte_count = params + 1 /* pad */ ;
5455 pSMB->TotalParameterCount = cpu_to_le16(params);
5456 pSMB->ParameterCount = pSMB->TotalParameterCount;
5457 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5458 pSMB->Reserved4 = 0;
5459 pSMB->hdr.smb_buf_length += byte_count;
5460 pSMB->ByteCount = cpu_to_le16(byte_count);
5461
5462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5464 if (rc) {
5465 cFYI(1, ("Send error in Query EA = %d", rc));
5466 } else { /* decode response */
5467 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5468
5469 /* BB also check enough total bytes returned */
5470 /* BB we need to improve the validity checking
5471 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005472 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 rc = -EIO; /* bad smb */
5474 /* else if (pFindData){
5475 memcpy((char *) pFindData,
5476 (char *) &pSMBr->hdr.Protocol +
5477 data_offset, kl);
5478 }*/ else {
5479 /* check that length of list is not more than bcc */
5480 /* check that each entry does not go beyond length
5481 of list */
5482 /* check that each element of each entry does not
5483 go beyond end of list */
5484 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005485 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 rc = -ENODATA;
5487 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005488 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 ea_response_data = (struct fealist *)
5490 (((char *) &pSMBr->hdr.Protocol) +
5491 data_offset);
5492 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005493 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005494 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005496 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 } else {
5498 /* account for ea list len */
5499 name_len -= 4;
5500 temp_fea = ea_response_data->list;
5501 temp_ptr = (char *)temp_fea;
5502 /* loop through checking if we have a matching
5503 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005504 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 __u16 value_len;
5506 name_len -= 4;
5507 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005508 value_len =
5509 le16_to_cpu(temp_fea->value_len);
5510 /* BB validate that value_len falls within SMB,
5511 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005512 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 temp_fea->name_len) == 0) {
5514 /* found a match */
5515 rc = value_len;
5516 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005517 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 memcpy(ea_value,
5519 temp_fea->name+temp_fea->name_len+1,
5520 rc);
Steve French50c2f752007-07-13 00:33:32 +00005521 /* ea values, unlike ea
5522 names, are not null
5523 terminated */
Steve French790fe572007-07-07 19:25:05 +00005524 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 /* skip copy - calc size only */
5526 } else {
Steve French50c2f752007-07-13 00:33:32 +00005527 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 rc = -ERANGE;
5529 }
5530 break;
5531 }
5532 name_len -= temp_fea->name_len;
5533 temp_ptr += temp_fea->name_len;
5534 /* account for trailing null */
5535 name_len--;
5536 temp_ptr++;
5537 name_len -= value_len;
5538 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005539 /* No trailing null to account for in
5540 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541 temp_fea = (struct fea *)temp_ptr;
5542 }
Steve French50c2f752007-07-13 00:33:32 +00005543 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 }
5545 }
Steve French0d817bc2008-05-22 02:02:03 +00005546 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005547 if (rc == -EAGAIN)
5548 goto QEARetry;
5549
5550 return (ssize_t)rc;
5551}
5552
5553int
5554CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005555 const char *ea_name, const void *ea_value,
5556 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5557 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005558{
5559 struct smb_com_transaction2_spi_req *pSMB = NULL;
5560 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5561 struct fealist *parm_data;
5562 int name_len;
5563 int rc = 0;
5564 int bytes_returned = 0;
5565 __u16 params, param_offset, byte_count, offset, count;
5566
5567 cFYI(1, ("In SetEA"));
5568SetEARetry:
5569 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5570 (void **) &pSMBr);
5571 if (rc)
5572 return rc;
5573
5574 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5575 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005576 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005577 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 name_len++; /* trailing null */
5579 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005580 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 name_len = strnlen(fileName, PATH_MAX);
5582 name_len++; /* trailing null */
5583 strncpy(pSMB->FileName, fileName, name_len);
5584 }
5585
5586 params = 6 + name_len;
5587
5588 /* done calculating parms using name_len of file name,
5589 now use name_len to calculate length of ea name
5590 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005591 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 name_len = 0;
5593 else
Steve French50c2f752007-07-13 00:33:32 +00005594 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005596 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005598 /* BB find max SMB PDU from sess */
5599 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 pSMB->MaxSetupCount = 0;
5601 pSMB->Reserved = 0;
5602 pSMB->Flags = 0;
5603 pSMB->Timeout = 0;
5604 pSMB->Reserved2 = 0;
5605 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005606 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005607 offset = param_offset + params;
5608 pSMB->InformationLevel =
5609 cpu_to_le16(SMB_SET_FILE_EA);
5610
5611 parm_data =
5612 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5613 offset);
5614 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5615 pSMB->DataOffset = cpu_to_le16(offset);
5616 pSMB->SetupCount = 1;
5617 pSMB->Reserved3 = 0;
5618 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5619 byte_count = 3 /* pad */ + params + count;
5620 pSMB->DataCount = cpu_to_le16(count);
5621 parm_data->list_len = cpu_to_le32(count);
5622 parm_data->list[0].EA_flags = 0;
5623 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005624 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005626 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005627 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 parm_data->list[0].name[name_len] = 0;
5629 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5630 /* caller ensures that ea_value_len is less than 64K but
5631 we need to ensure that it fits within the smb */
5632
Steve French50c2f752007-07-13 00:33:32 +00005633 /*BB add length check to see if it would fit in
5634 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005635 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5636 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005637 memcpy(parm_data->list[0].name+name_len+1,
5638 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639
5640 pSMB->TotalDataCount = pSMB->DataCount;
5641 pSMB->ParameterCount = cpu_to_le16(params);
5642 pSMB->TotalParameterCount = pSMB->ParameterCount;
5643 pSMB->Reserved4 = 0;
5644 pSMB->hdr.smb_buf_length += byte_count;
5645 pSMB->ByteCount = cpu_to_le16(byte_count);
5646 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5647 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005648 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650
5651 cifs_buf_release(pSMB);
5652
5653 if (rc == -EAGAIN)
5654 goto SetEARetry;
5655
5656 return rc;
5657}
5658
5659#endif