blob: d06260251c304692dc2789c14059170245ad2957 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchd185cda2009-04-30 17:45:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2009
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 Frencha4544342005-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 Frenchbfb59822008-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 Frencha4544342005-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 Frenchac683922009-05-06 04:16:04 +0000452#ifdef CONFIG_CIFS_EXPERIMENTAL
453 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
454 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
455 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
456 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
457 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
458 }
459#endif
Steve French50c2f752007-07-13 00:33:32 +0000460
Steve French39798772006-05-31 22:40:51 +0000461 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000462 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000463 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
464 count += strlen(protocols[i].name) + 1;
465 /* null at end of source and target buffers anyway */
466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 pSMB->hdr.smb_buf_length += count;
468 pSMB->ByteCount = cpu_to_le16(count);
469
470 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000472 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000473 goto neg_err_exit;
474
Al Viro733f99a2006-10-14 16:48:26 +0100475 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000476 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000477 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000478 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000479 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000480 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000481 could not negotiate a common dialect */
482 rc = -EOPNOTSUPP;
483 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000484#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000485 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100486 && ((dialect == LANMAN_PROT)
487 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000488 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000489 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000490
Steve French790fe572007-07-07 19:25:05 +0000491 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000492 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000493 server->secType = LANMAN;
494 else {
495 cERROR(1, ("mount failed weak security disabled"
496 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000497 rc = -EOPNOTSUPP;
498 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000499 }
Steve French254e55e2006-06-04 05:53:15 +0000500 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
501 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
502 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000503 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000504 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000505 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
506 /* even though we do not use raw we might as well set this
507 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000508 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000509 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000510 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
511 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000512 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000513 server->capabilities = CAP_MPX_MODE;
514 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000515 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000516 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000517 /* OS/2 often does not set timezone therefore
518 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000519 * Could deviate slightly from the right zone.
520 * Smallest defined timezone difference is 15 minutes
521 * (i.e. Nepal). Rounding up/down is done to match
522 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000523 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000524 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000525 struct timespec ts, utc;
526 utc = CURRENT_TIME;
527 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
528 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000529 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
530 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000531 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000532 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000533 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000534 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000535 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000536 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000537 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000538 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000539 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000540 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000541 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000542 server->timeAdj = (int)tmp;
543 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000544 }
Steve French790fe572007-07-07 19:25:05 +0000545 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000546
Steve French39798772006-05-31 22:40:51 +0000547
Steve French254e55e2006-06-04 05:53:15 +0000548 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000549 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000550
Steve French50c2f752007-07-13 00:33:32 +0000551 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000552 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000553 memcpy(server->cryptKey, rsp->EncryptionKey,
554 CIFS_CRYPTO_KEY_SIZE);
555 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
556 rc = -EIO; /* need cryptkey unless plain text */
557 goto neg_err_exit;
558 }
Steve French39798772006-05-31 22:40:51 +0000559
Steve French790fe572007-07-07 19:25:05 +0000560 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000561 /* we will not end up setting signing flags - as no signing
562 was in LANMAN and server did not return the flags on */
563 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000564#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000565 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000566 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000567 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000568 rc = -EOPNOTSUPP;
569#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000570 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000571 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000572 /* unknown wct */
573 rc = -EOPNOTSUPP;
574 goto neg_err_exit;
575 }
576 /* else wct == 17 NTLM */
577 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000578 if ((server->secMode & SECMODE_USER) == 0)
579 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000580
Steve French790fe572007-07-07 19:25:05 +0000581 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000582#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000583 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000584#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000585 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000586 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000587
Steve French790fe572007-07-07 19:25:05 +0000588 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000589 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000590 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000591 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000592 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000593 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000594 else if (secFlags & CIFSSEC_MAY_KRB5)
595 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000596 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
597 server->secType = NTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000598 else if (secFlags & CIFSSEC_MAY_LANMAN)
599 server->secType = LANMAN;
600/* #ifdef CONFIG_CIFS_EXPERIMENTAL
601 else if (secFlags & CIFSSEC_MAY_PLNTXT)
602 server->secType = ??
603#endif */
604 else {
605 rc = -EOPNOTSUPP;
606 cERROR(1, ("Invalid security type"));
607 goto neg_err_exit;
608 }
609 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000610
Steve French254e55e2006-06-04 05:53:15 +0000611 /* one byte, so no need to convert this or EncryptionKeyLen from
612 little endian */
613 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
614 /* probably no need to store and check maxvcs */
615 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000617 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000618 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000619 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
620 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000621 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
622 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000623 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
624 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
625 CIFS_CRYPTO_KEY_SIZE);
626 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
627 && (pSMBr->EncryptionKeyLength == 0)) {
628 /* decode security blob */
629 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
630 rc = -EIO; /* no crypt key only if plain text pwd */
631 goto neg_err_exit;
632 }
633
634 /* BB might be helpful to save off the domain of server here */
635
Steve French50c2f752007-07-13 00:33:32 +0000636 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000637 (server->capabilities & CAP_EXTENDED_SECURITY)) {
638 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000639 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000641 goto neg_err_exit;
642 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500643 read_lock(&cifs_tcp_ses_lock);
644 if (server->srv_count > 1) {
645 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000646 if (memcmp(server->server_GUID,
647 pSMBr->u.extended_response.
648 GUID, 16) != 0) {
649 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000650 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000651 pSMBr->u.extended_response.GUID,
652 16);
653 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500654 } else {
655 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000656 memcpy(server->server_GUID,
657 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500658 }
Jeff Laytone187e442007-10-16 17:10:44 +0000659
660 if (count == 16) {
661 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000662 } else {
663 rc = decode_negTokenInit(pSMBr->u.extended_response.
664 SecurityBlob,
665 count - 16,
666 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000667 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000668 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000669 else
Steve French254e55e2006-06-04 05:53:15 +0000670 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
Steve French254e55e2006-06-04 05:53:15 +0000672 } else
673 server->capabilities &= ~CAP_EXTENDED_SECURITY;
674
Steve French6344a422006-06-12 04:18:35 +0000675#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000676signing_check:
Steve French6344a422006-06-12 04:18:35 +0000677#endif
Steve French762e5ab2007-06-28 18:41:42 +0000678 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
679 /* MUST_SIGN already includes the MAY_SIGN FLAG
680 so if this is zero it means that signing is disabled */
681 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000682 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000683 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000684 "packet signing to be enabled in "
685 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000686 rc = -EOPNOTSUPP;
687 }
Steve French50c2f752007-07-13 00:33:32 +0000688 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000689 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000690 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
691 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000692 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000693 if ((server->secMode &
694 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
695 cERROR(1,
696 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000697 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000698 } else
699 server->secMode |= SECMODE_SIGN_REQUIRED;
700 } else {
701 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000702 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000703 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000704 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 }
Steve French50c2f752007-07-13 00:33:32 +0000706
707neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700708 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000709
Steve French790fe572007-07-07 19:25:05 +0000710 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return rc;
712}
713
714int
715CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
716{
717 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500721
722 /* BB: do we need to check this? These should never be NULL. */
723 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
724 return -EIO;
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500727 * No need to return error on this operation if tid invalidated and
728 * closed on server already e.g. due to tcp session crashing. Also,
729 * the tcon is no longer on the list, so no need to take lock before
730 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 */
Jeff Laytonf1987b42008-11-15 11:12:47 -0500732 if (tcon->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000733 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Steve French50c2f752007-07-13 00:33:32 +0000735 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700736 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500737 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return rc;
Steve French133672e2007-11-13 22:41:37 +0000739
740 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700742 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Steve French50c2f752007-07-13 00:33:32 +0000744 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500745 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (rc == -EAGAIN)
747 rc = 0;
748
749 return rc;
750}
751
752int
753CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
754{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 LOGOFF_ANDX_REQ *pSMB;
756 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500759
760 /*
761 * BB: do we need to check validity of ses and server? They should
762 * always be valid since we have an active reference. If not, that
763 * should probably be a BUG()
764 */
765 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return -EIO;
767
Jeff Layton14fbf502008-11-14 13:53:46 -0500768 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000769 if (ses->need_reconnect)
770 goto session_already_dead; /* no need to send SMBlogoff if uid
771 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
773 if (rc) {
774 up(&ses->sesSem);
775 return rc;
776 }
777
Steve French3b795212008-11-13 19:45:32 +0000778 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700779
Steve French3b795212008-11-13 19:45:32 +0000780 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
782 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 pSMB->hdr.Uid = ses->Suid;
785
786 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000787 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000788session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700789 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000792 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 error */
794 if (rc == -EAGAIN)
795 rc = 0;
796 return rc;
797}
798
799int
Steve French2d785a52007-07-15 01:48:57 +0000800CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
801 __u16 type, const struct nls_table *nls_codepage, int remap)
802{
803 TRANSACTION2_SPI_REQ *pSMB = NULL;
804 TRANSACTION2_SPI_RSP *pSMBr = NULL;
805 struct unlink_psx_rq *pRqD;
806 int name_len;
807 int rc = 0;
808 int bytes_returned = 0;
809 __u16 params, param_offset, offset, byte_count;
810
811 cFYI(1, ("In POSIX delete"));
812PsxDelete:
813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
814 (void **) &pSMBr);
815 if (rc)
816 return rc;
817
818 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
819 name_len =
820 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
821 PATH_MAX, nls_codepage, remap);
822 name_len++; /* trailing null */
823 name_len *= 2;
824 } else { /* BB add path length overrun check */
825 name_len = strnlen(fileName, PATH_MAX);
826 name_len++; /* trailing null */
827 strncpy(pSMB->FileName, fileName, name_len);
828 }
829
830 params = 6 + name_len;
831 pSMB->MaxParameterCount = cpu_to_le16(2);
832 pSMB->MaxDataCount = 0; /* BB double check this with jra */
833 pSMB->MaxSetupCount = 0;
834 pSMB->Reserved = 0;
835 pSMB->Flags = 0;
836 pSMB->Timeout = 0;
837 pSMB->Reserved2 = 0;
838 param_offset = offsetof(struct smb_com_transaction2_spi_req,
839 InformationLevel) - 4;
840 offset = param_offset + params;
841
842 /* Setup pointer to Request Data (inode type) */
843 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
844 pRqD->type = cpu_to_le16(type);
845 pSMB->ParameterOffset = cpu_to_le16(param_offset);
846 pSMB->DataOffset = cpu_to_le16(offset);
847 pSMB->SetupCount = 1;
848 pSMB->Reserved3 = 0;
849 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
850 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
851
852 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
853 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
854 pSMB->ParameterCount = cpu_to_le16(params);
855 pSMB->TotalParameterCount = pSMB->ParameterCount;
856 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
857 pSMB->Reserved4 = 0;
858 pSMB->hdr.smb_buf_length += byte_count;
859 pSMB->ByteCount = cpu_to_le16(byte_count);
860 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
861 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000862 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000863 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000864 cifs_buf_release(pSMB);
865
866 cifs_stats_inc(&tcon->num_deletes);
867
868 if (rc == -EAGAIN)
869 goto PsxDelete;
870
871 return rc;
872}
873
874int
Steve French737b7582005-04-28 22:41:06 -0700875CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
876 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 DELETE_FILE_REQ *pSMB = NULL;
879 DELETE_FILE_RSP *pSMBr = NULL;
880 int rc = 0;
881 int bytes_returned;
882 int name_len;
883
884DelFileRetry:
885 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
886 (void **) &pSMBr);
887 if (rc)
888 return rc;
889
890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
891 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000892 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700893 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 name_len++; /* trailing null */
895 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700896 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 name_len = strnlen(fileName, PATH_MAX);
898 name_len++; /* trailing null */
899 strncpy(pSMB->fileName, fileName, name_len);
900 }
901 pSMB->SearchAttributes =
902 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
903 pSMB->BufferFormat = 0x04;
904 pSMB->hdr.smb_buf_length += name_len + 1;
905 pSMB->ByteCount = cpu_to_le16(name_len + 1);
906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700908 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000909 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 cifs_buf_release(pSMB);
913 if (rc == -EAGAIN)
914 goto DelFileRetry;
915
916 return rc;
917}
918
919int
Steve French50c2f752007-07-13 00:33:32 +0000920CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700921 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
923 DELETE_DIRECTORY_REQ *pSMB = NULL;
924 DELETE_DIRECTORY_RSP *pSMBr = NULL;
925 int rc = 0;
926 int bytes_returned;
927 int name_len;
928
929 cFYI(1, ("In CIFSSMBRmDir"));
930RmDirRetry:
931 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
932 (void **) &pSMBr);
933 if (rc)
934 return rc;
935
936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700937 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
938 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 name_len++; /* trailing null */
940 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700941 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 name_len = strnlen(dirName, PATH_MAX);
943 name_len++; /* trailing null */
944 strncpy(pSMB->DirName, dirName, name_len);
945 }
946
947 pSMB->BufferFormat = 0x04;
948 pSMB->hdr.smb_buf_length += name_len + 1;
949 pSMB->ByteCount = cpu_to_le16(name_len + 1);
950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700952 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000953 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 cifs_buf_release(pSMB);
957 if (rc == -EAGAIN)
958 goto RmDirRetry;
959 return rc;
960}
961
962int
963CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700964 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
966 int rc = 0;
967 CREATE_DIRECTORY_REQ *pSMB = NULL;
968 CREATE_DIRECTORY_RSP *pSMBr = NULL;
969 int bytes_returned;
970 int name_len;
971
972 cFYI(1, ("In CIFSSMBMkDir"));
973MkDirRetry:
974 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
975 (void **) &pSMBr);
976 if (rc)
977 return rc;
978
979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000980 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700981 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 name_len++; /* trailing null */
983 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700984 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 name_len = strnlen(name, PATH_MAX);
986 name_len++; /* trailing null */
987 strncpy(pSMB->DirName, name, name_len);
988 }
989
990 pSMB->BufferFormat = 0x04;
991 pSMB->hdr.smb_buf_length += name_len + 1;
992 pSMB->ByteCount = cpu_to_le16(name_len + 1);
993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700995 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000996 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -0700998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 cifs_buf_release(pSMB);
1000 if (rc == -EAGAIN)
1001 goto MkDirRetry;
1002 return rc;
1003}
1004
Steve French2dd29d32007-04-23 22:07:35 +00001005int
1006CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001008 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001009 const struct nls_table *nls_codepage, int remap)
1010{
1011 TRANSACTION2_SPI_REQ *pSMB = NULL;
1012 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1013 int name_len;
1014 int rc = 0;
1015 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001016 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001017 OPEN_PSX_REQ *pdata;
1018 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001019
1020 cFYI(1, ("In POSIX Create"));
1021PsxCreat:
1022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1023 (void **) &pSMBr);
1024 if (rc)
1025 return rc;
1026
1027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1028 name_len =
1029 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1030 PATH_MAX, nls_codepage, remap);
1031 name_len++; /* trailing null */
1032 name_len *= 2;
1033 } else { /* BB improve the check for buffer overruns BB */
1034 name_len = strnlen(name, PATH_MAX);
1035 name_len++; /* trailing null */
1036 strncpy(pSMB->FileName, name, name_len);
1037 }
1038
1039 params = 6 + name_len;
1040 count = sizeof(OPEN_PSX_REQ);
1041 pSMB->MaxParameterCount = cpu_to_le16(2);
1042 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1043 pSMB->MaxSetupCount = 0;
1044 pSMB->Reserved = 0;
1045 pSMB->Flags = 0;
1046 pSMB->Timeout = 0;
1047 pSMB->Reserved2 = 0;
1048 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001049 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001050 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001051 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001052 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001053 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001054 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001055 pdata->OpenFlags = cpu_to_le32(*pOplock);
1056 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1057 pSMB->DataOffset = cpu_to_le16(offset);
1058 pSMB->SetupCount = 1;
1059 pSMB->Reserved3 = 0;
1060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1061 byte_count = 3 /* pad */ + params + count;
1062
1063 pSMB->DataCount = cpu_to_le16(count);
1064 pSMB->ParameterCount = cpu_to_le16(params);
1065 pSMB->TotalDataCount = pSMB->DataCount;
1066 pSMB->TotalParameterCount = pSMB->ParameterCount;
1067 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1068 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001069 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001070 pSMB->ByteCount = cpu_to_le16(byte_count);
1071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1073 if (rc) {
1074 cFYI(1, ("Posix create returned %d", rc));
1075 goto psx_create_err;
1076 }
1077
Steve French790fe572007-07-07 19:25:05 +00001078 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001079 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1080
1081 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1082 rc = -EIO; /* bad smb */
1083 goto psx_create_err;
1084 }
1085
1086 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001087 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001088 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001089
Steve French2dd29d32007-04-23 22:07:35 +00001090 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001091 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001092 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1093 /* Let caller know file was created so we can set the mode. */
1094 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001095 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001096 *pOplock |= CIFS_CREATE_ACTION;
1097 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001098 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1099 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001100 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001101 } else {
Steve French790fe572007-07-07 19:25:05 +00001102 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001103 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001104 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001105 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001106 goto psx_create_err;
1107 }
Steve French50c2f752007-07-13 00:33:32 +00001108 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001109 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001110 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001111 }
Steve French2dd29d32007-04-23 22:07:35 +00001112
1113psx_create_err:
1114 cifs_buf_release(pSMB);
1115
1116 cifs_stats_inc(&tcon->num_mkdirs);
1117
1118 if (rc == -EAGAIN)
1119 goto PsxCreat;
1120
Steve French50c2f752007-07-13 00:33:32 +00001121 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001122}
1123
Steve Frencha9d02ad2005-08-24 23:06:05 -07001124static __u16 convert_disposition(int disposition)
1125{
1126 __u16 ofun = 0;
1127
1128 switch (disposition) {
1129 case FILE_SUPERSEDE:
1130 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1131 break;
1132 case FILE_OPEN:
1133 ofun = SMBOPEN_OAPPEND;
1134 break;
1135 case FILE_CREATE:
1136 ofun = SMBOPEN_OCREATE;
1137 break;
1138 case FILE_OPEN_IF:
1139 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_OVERWRITE:
1142 ofun = SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OVERWRITE_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 default:
Steve French790fe572007-07-07 19:25:05 +00001148 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001149 ofun = SMBOPEN_OAPPEND; /* regular open */
1150 }
1151 return ofun;
1152}
1153
Jeff Layton35fc37d2008-05-14 10:22:03 -07001154static int
1155access_flags_to_smbopen_mode(const int access_flags)
1156{
1157 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1158
1159 if (masked_flags == GENERIC_READ)
1160 return SMBOPEN_READ;
1161 else if (masked_flags == GENERIC_WRITE)
1162 return SMBOPEN_WRITE;
1163
1164 /* just go for read/write */
1165 return SMBOPEN_READWRITE;
1166}
1167
Steve Frencha9d02ad2005-08-24 23:06:05 -07001168int
1169SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1170 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001171 const int access_flags, const int create_options, __u16 *netfid,
1172 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 const struct nls_table *nls_codepage, int remap)
1174{
1175 int rc = -EACCES;
1176 OPENX_REQ *pSMB = NULL;
1177 OPENX_RSP *pSMBr = NULL;
1178 int bytes_returned;
1179 int name_len;
1180 __u16 count;
1181
1182OldOpenRetry:
1183 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1184 (void **) &pSMBr);
1185 if (rc)
1186 return rc;
1187
1188 pSMB->AndXCommand = 0xFF; /* none */
1189
1190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1191 count = 1; /* account for one byte pad to word boundary */
1192 name_len =
1193 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1194 fileName, PATH_MAX, nls_codepage, remap);
1195 name_len++; /* trailing null */
1196 name_len *= 2;
1197 } else { /* BB improve check for buffer overruns BB */
1198 count = 0; /* no pad */
1199 name_len = strnlen(fileName, PATH_MAX);
1200 name_len++; /* trailing null */
1201 strncpy(pSMB->fileName, fileName, name_len);
1202 }
1203 if (*pOplock & REQ_OPLOCK)
1204 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001205 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001207
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001209 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1211 /* set file as system file if special file such
1212 as fifo and server expecting SFU style and
1213 no Unix extensions */
1214
Steve French790fe572007-07-07 19:25:05 +00001215 if (create_options & CREATE_OPTION_SPECIAL)
1216 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001217 else /* BB FIXME BB */
1218 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219
Jeff Layton67750fb2008-05-09 22:28:02 +00001220 if (create_options & CREATE_OPTION_READONLY)
1221 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222
1223 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001224/* pSMB->CreateOptions = cpu_to_le32(create_options &
1225 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001227
1228 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001229 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 count += name_len;
1231 pSMB->hdr.smb_buf_length += count;
1232
1233 pSMB->ByteCount = cpu_to_le16(count);
1234 /* long_op set to 1 to allow for oplock break timeouts */
1235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001236 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 cifs_stats_inc(&tcon->num_opens);
1238 if (rc) {
1239 cFYI(1, ("Error in Open = %d", rc));
1240 } else {
1241 /* BB verify if wct == 15 */
1242
Steve French582d21e2008-05-13 04:54:12 +00001243/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244
1245 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1246 /* Let caller know file was created so we can set the mode. */
1247 /* Do we care about the CreateAction in any other cases? */
1248 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001249/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 *pOplock |= CIFS_CREATE_ACTION; */
1251 /* BB FIXME END */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255 pfile_info->LastAccessTime = 0; /* BB fixme */
1256 pfile_info->LastWriteTime = 0; /* BB fixme */
1257 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001258 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001259 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001261 pfile_info->AllocationSize =
1262 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001265 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 }
1267 }
1268
1269 cifs_buf_release(pSMB);
1270 if (rc == -EAGAIN)
1271 goto OldOpenRetry;
1272 return rc;
1273}
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275int
1276CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1277 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001278 const int access_flags, const int create_options, __u16 *netfid,
1279 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001280 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281{
1282 int rc = -EACCES;
1283 OPEN_REQ *pSMB = NULL;
1284 OPEN_RSP *pSMBr = NULL;
1285 int bytes_returned;
1286 int name_len;
1287 __u16 count;
1288
1289openRetry:
1290 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1291 (void **) &pSMBr);
1292 if (rc)
1293 return rc;
1294
1295 pSMB->AndXCommand = 0xFF; /* none */
1296
1297 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1298 count = 1; /* account for one byte pad to word boundary */
1299 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001300 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001301 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 name_len++; /* trailing null */
1303 name_len *= 2;
1304 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001305 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 count = 0; /* no pad */
1307 name_len = strnlen(fileName, PATH_MAX);
1308 name_len++; /* trailing null */
1309 pSMB->NameLength = cpu_to_le16(name_len);
1310 strncpy(pSMB->fileName, fileName, name_len);
1311 }
1312 if (*pOplock & REQ_OPLOCK)
1313 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001314 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1317 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001318 /* set file as system file if special file such
1319 as fifo and server expecting SFU style and
1320 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001321 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001322 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1323 else
1324 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 /* XP does not handle ATTR_POSIX_SEMANTICS */
1327 /* but it helps speed up case sensitive checks for other
1328 servers such as Samba */
1329 if (tcon->ses->capabilities & CAP_UNIX)
1330 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1331
Jeff Layton67750fb2008-05-09 22:28:02 +00001332 if (create_options & CREATE_OPTION_READONLY)
1333 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1336 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001337 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001338 /* BB Expirement with various impersonation levels and verify */
1339 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->SecurityFlags =
1341 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1342
1343 count += name_len;
1344 pSMB->hdr.smb_buf_length += count;
1345
1346 pSMB->ByteCount = cpu_to_le16(count);
1347 /* long_op set to 1 to allow for oplock break timeouts */
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001349 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001350 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if (rc) {
1352 cFYI(1, ("Error in Open = %d", rc));
1353 } else {
Steve French09d1db52005-04-28 22:41:08 -07001354 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1356 /* Let caller know file was created so we can set the mode. */
1357 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001358 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001359 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001360 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001361 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1362 36 /* CreationTime to Attributes */);
1363 /* the file_info buf is endian converted by caller */
1364 pfile_info->AllocationSize = pSMBr->AllocationSize;
1365 pfile_info->EndOfFile = pSMBr->EndOfFile;
1366 pfile_info->NumberOfLinks = cpu_to_le32(1);
1367 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 cifs_buf_release(pSMB);
1372 if (rc == -EAGAIN)
1373 goto openRetry;
1374 return rc;
1375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377int
Steve French50c2f752007-07-13 00:33:32 +00001378CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1379 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1380 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
1382 int rc = -EACCES;
1383 READ_REQ *pSMB = NULL;
1384 READ_RSP *pSMBr = NULL;
1385 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001386 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001387 int resp_buf_type = 0;
1388 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Steve French790fe572007-07-07 19:25:05 +00001390 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1391 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001392 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001393 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001394 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001395 if ((lseek >> 32) > 0) {
1396 /* can not handle this big offset for old */
1397 return -EIO;
1398 }
1399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001402 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if (rc)
1404 return rc;
1405
1406 /* tcon and ses pointer are checked in smb_init */
1407 if (tcon->ses->server == NULL)
1408 return -ECONNABORTED;
1409
Steve Frenchec637e32005-12-12 20:53:18 -08001410 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 pSMB->Fid = netfid;
1412 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001413 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 pSMB->Remaining = 0;
1417 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1418 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001419 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001420 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1421 else {
1422 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001423 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001424 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001425 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001426 }
Steve Frenchec637e32005-12-12 20:53:18 -08001427
1428 iov[0].iov_base = (char *)pSMB;
1429 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001430 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001431 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001432 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001433 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 if (rc) {
1435 cERROR(1, ("Send error in read = %d", rc));
1436 } else {
1437 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1438 data_length = data_length << 16;
1439 data_length += le16_to_cpu(pSMBr->DataLength);
1440 *nbytes = data_length;
1441
1442 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001443 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001445 cFYI(1, ("bad length %d for count %d",
1446 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 rc = -EIO;
1448 *nbytes = 0;
1449 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001450 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001451 le16_to_cpu(pSMBr->DataOffset);
1452/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001453 cERROR(1,("Faulting on read rc = %d",rc));
1454 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001455 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001456 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001457 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 }
1459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
Steve French4b8f9302006-02-26 16:41:18 +00001461/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001462 if (*buf) {
1463 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001464 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001465 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001466 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001467 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001468 /* return buffer to caller to free */
1469 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001470 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001471 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001472 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001473 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001474 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001475
1476 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 since file handle passed in no longer valid */
1478 return rc;
1479}
1480
Steve Frenchec637e32005-12-12 20:53:18 -08001481
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482int
1483CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1484 const int netfid, const unsigned int count,
1485 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001486 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
1488 int rc = -EACCES;
1489 WRITE_REQ *pSMB = NULL;
1490 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001491 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 __u32 bytes_sent;
1493 __u16 byte_count;
1494
Steve French61de8002008-10-30 20:15:22 +00001495 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001496 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001497 return -ECONNABORTED;
1498
Steve French790fe572007-07-07 19:25:05 +00001499 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001500 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001501 else {
Steve French1c955182005-08-30 20:58:07 -07001502 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001503 if ((offset >> 32) > 0) {
1504 /* can not handle big offset for old srv */
1505 return -EIO;
1506 }
1507 }
Steve French1c955182005-08-30 20:58:07 -07001508
1509 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 (void **) &pSMBr);
1511 if (rc)
1512 return rc;
1513 /* tcon and ses pointer are checked in smb_init */
1514 if (tcon->ses->server == NULL)
1515 return -ECONNABORTED;
1516
1517 pSMB->AndXCommand = 0xFF; /* none */
1518 pSMB->Fid = netfid;
1519 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001520 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001521 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 pSMB->Reserved = 0xFFFFFFFF;
1524 pSMB->WriteMode = 0;
1525 pSMB->Remaining = 0;
1526
Steve French50c2f752007-07-13 00:33:32 +00001527 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 can send more if LARGE_WRITE_X capability returned by the server and if
1529 our buffer is big enough or if we convert to iovecs on socket writes
1530 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001531 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1533 } else {
1534 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1535 & ~0xFF;
1536 }
1537
1538 if (bytes_sent > count)
1539 bytes_sent = count;
1540 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001541 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001542 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001543 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001544 else if (ubuf) {
1545 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 cifs_buf_release(pSMB);
1547 return -EFAULT;
1548 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001549 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 /* No buffer */
1551 cifs_buf_release(pSMB);
1552 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001553 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001554 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001555 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001556 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001557 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001558
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1560 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001561 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001562
Steve French790fe572007-07-07 19:25:05 +00001563 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001564 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001565 else { /* old style write has byte count 4 bytes earlier
1566 so 4 bytes pad */
1567 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001568 (struct smb_com_writex_req *)pSMB;
1569 pSMBW->ByteCount = cpu_to_le16(byte_count);
1570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571
1572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1573 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001574 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 if (rc) {
1576 cFYI(1, ("Send error in write = %d", rc));
1577 *nbytes = 0;
1578 } else {
1579 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1580 *nbytes = (*nbytes) << 16;
1581 *nbytes += le16_to_cpu(pSMBr->Count);
1582 }
1583
1584 cifs_buf_release(pSMB);
1585
Steve French50c2f752007-07-13 00:33:32 +00001586 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 since file handle passed in no longer valid */
1588
1589 return rc;
1590}
1591
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001592int
1593CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001595 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1596 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597{
1598 int rc = -EACCES;
1599 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001600 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001601 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001602 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001604 *nbytes = 0;
1605
Steve French790fe572007-07-07 19:25:05 +00001606 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001607
Steve French4c3130e2008-12-09 00:28:16 +00001608 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001609 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001610 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001611 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001612 if ((offset >> 32) > 0) {
1613 /* can not handle big offset for old srv */
1614 return -EIO;
1615 }
1616 }
Steve French8cc64c62005-10-03 13:49:43 -07001617 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if (rc)
1619 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620 /* tcon and ses pointer are checked in smb_init */
1621 if (tcon->ses->server == NULL)
1622 return -ECONNABORTED;
1623
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001624 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 pSMB->Fid = netfid;
1626 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001627 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001628 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 pSMB->Reserved = 0xFFFFFFFF;
1630 pSMB->WriteMode = 0;
1631 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001632
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001634 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Steve French3e844692005-10-03 13:37:24 -07001636 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1637 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001638 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001639 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001640 pSMB->hdr.smb_buf_length += count+1;
1641 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001642 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1643 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001644 pSMB->ByteCount = cpu_to_le16(count + 1);
1645 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001646 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001647 (struct smb_com_writex_req *)pSMB;
1648 pSMBW->ByteCount = cpu_to_le16(count + 5);
1649 }
Steve French3e844692005-10-03 13:37:24 -07001650 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001651 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001652 iov[0].iov_len = smb_hdr_len + 4;
1653 else /* wct == 12 pad bigger by four bytes */
1654 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001655
Steve French3e844692005-10-03 13:37:24 -07001656
Steve Frenchec637e32005-12-12 20:53:18 -08001657 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001658 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001659 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001661 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001662 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001663 /* presumably this can not happen, but best to be safe */
1664 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001665 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001666 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001667 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1668 *nbytes = (*nbytes) << 16;
1669 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Steve French4b8f9302006-02-26 16:41:18 +00001672/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001673 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001674 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001675 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001676 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Steve French50c2f752007-07-13 00:33:32 +00001678 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 since file handle passed in no longer valid */
1680
1681 return rc;
1682}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001683
1684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685int
1686CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1687 const __u16 smb_file_id, const __u64 len,
1688 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001689 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690{
1691 int rc = 0;
1692 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001693/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 int bytes_returned;
1695 int timeout = 0;
1696 __u16 count;
1697
Steve French4b18f2a2008-04-29 00:06:05 +00001698 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001699 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1700
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (rc)
1702 return rc;
1703
Steve French790fe572007-07-07 19:25:05 +00001704 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001705 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001707 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001708 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1710 } else {
1711 pSMB->Timeout = 0;
1712 }
1713
1714 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1715 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1716 pSMB->LockType = lockType;
1717 pSMB->AndXCommand = 0xFF; /* none */
1718 pSMB->Fid = smb_file_id; /* netfid stays le */
1719
Steve French790fe572007-07-07 19:25:05 +00001720 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1722 /* BB where to store pid high? */
1723 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1724 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1725 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1726 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1727 count = sizeof(LOCKING_ANDX_RANGE);
1728 } else {
1729 /* oplock break */
1730 count = 0;
1731 }
1732 pSMB->hdr.smb_buf_length += count;
1733 pSMB->ByteCount = cpu_to_le16(count);
1734
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001735 if (waitFlag) {
1736 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001737 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001738 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001739 } else {
Steve French133672e2007-11-13 22:41:37 +00001740 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1741 timeout);
1742 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001743 }
Steve Frencha4544342005-08-24 13:59:35 -07001744 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001745 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747
Steve French50c2f752007-07-13 00:33:32 +00001748 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 since file handle passed in no longer valid */
1750 return rc;
1751}
1752
1753int
Steve French08547b02006-02-28 22:39:25 +00001754CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1755 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001756 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001757 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001758{
1759 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1760 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001761 struct cifs_posix_lock *parm_data;
1762 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001763 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001764 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001765 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001766 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001767 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001768
1769 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001770
Steve French790fe572007-07-07 19:25:05 +00001771 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001772 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001773
Steve French08547b02006-02-28 22:39:25 +00001774 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1775
1776 if (rc)
1777 return rc;
1778
1779 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1780
Steve French50c2f752007-07-13 00:33:32 +00001781 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001782 pSMB->MaxSetupCount = 0;
1783 pSMB->Reserved = 0;
1784 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001785 pSMB->Reserved2 = 0;
1786 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1787 offset = param_offset + params;
1788
Steve French08547b02006-02-28 22:39:25 +00001789 count = sizeof(struct cifs_posix_lock);
1790 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001791 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001792 pSMB->SetupCount = 1;
1793 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001794 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001795 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1796 else
1797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1798 byte_count = 3 /* pad */ + params + count;
1799 pSMB->DataCount = cpu_to_le16(count);
1800 pSMB->ParameterCount = cpu_to_le16(params);
1801 pSMB->TotalDataCount = pSMB->DataCount;
1802 pSMB->TotalParameterCount = pSMB->ParameterCount;
1803 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001804 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001805 (((char *) &pSMB->hdr.Protocol) + offset);
1806
1807 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001808 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001809 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001810 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001811 pSMB->Timeout = cpu_to_le32(-1);
1812 } else
1813 pSMB->Timeout = 0;
1814
Steve French08547b02006-02-28 22:39:25 +00001815 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001816 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001817 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001818
1819 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001820 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001821 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1822 pSMB->Reserved4 = 0;
1823 pSMB->hdr.smb_buf_length += byte_count;
1824 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001825 if (waitFlag) {
1826 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1827 (struct smb_hdr *) pSMBr, &bytes_returned);
1828 } else {
Steve French133672e2007-11-13 22:41:37 +00001829 iov[0].iov_base = (char *)pSMB;
1830 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1831 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1832 &resp_buf_type, timeout);
1833 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1834 not try to free it twice below on exit */
1835 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001836 }
1837
Steve French08547b02006-02-28 22:39:25 +00001838 if (rc) {
1839 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001840 } else if (get_flag) {
1841 /* lock structure can be returned on get */
1842 __u16 data_offset;
1843 __u16 data_count;
1844 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001845
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001846 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1847 rc = -EIO; /* bad smb */
1848 goto plk_err_exit;
1849 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001850 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1851 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001852 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001853 rc = -EIO;
1854 goto plk_err_exit;
1855 }
1856 parm_data = (struct cifs_posix_lock *)
1857 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001858 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001859 pLockData->fl_type = F_UNLCK;
1860 }
Steve French50c2f752007-07-13 00:33:32 +00001861
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001862plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001863 if (pSMB)
1864 cifs_small_buf_release(pSMB);
1865
Steve French133672e2007-11-13 22:41:37 +00001866 if (resp_buf_type == CIFS_SMALL_BUFFER)
1867 cifs_small_buf_release(iov[0].iov_base);
1868 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1869 cifs_buf_release(iov[0].iov_base);
1870
Steve French08547b02006-02-28 22:39:25 +00001871 /* Note: On -EAGAIN error only caller can retry on handle based calls
1872 since file handle passed in no longer valid */
1873
1874 return rc;
1875}
1876
1877
1878int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1880{
1881 int rc = 0;
1882 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 cFYI(1, ("In CIFSSMBClose"));
1884
1885/* do not retry on dead session on close */
1886 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001887 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 return 0;
1889 if (rc)
1890 return rc;
1891
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001893 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001895 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001896 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001898 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 /* EINTR is expected when user ctl-c to kill app */
1900 cERROR(1, ("Send error in Close = %d", rc));
1901 }
1902 }
1903
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001905 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 rc = 0;
1907
1908 return rc;
1909}
1910
1911int
Steve Frenchb298f222009-02-21 21:17:43 +00001912CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1913{
1914 int rc = 0;
1915 FLUSH_REQ *pSMB = NULL;
1916 cFYI(1, ("In CIFSSMBFlush"));
1917
1918 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1919 if (rc)
1920 return rc;
1921
1922 pSMB->FileID = (__u16) smb_file_id;
1923 pSMB->ByteCount = 0;
1924 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1925 cifs_stats_inc(&tcon->num_flushes);
1926 if (rc)
1927 cERROR(1, ("Send error in Flush = %d", rc));
1928
1929 return rc;
1930}
1931
1932int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1934 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001935 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
1937 int rc = 0;
1938 RENAME_REQ *pSMB = NULL;
1939 RENAME_RSP *pSMBr = NULL;
1940 int bytes_returned;
1941 int name_len, name_len2;
1942 __u16 count;
1943
1944 cFYI(1, ("In CIFSSMBRename"));
1945renameRetry:
1946 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1947 (void **) &pSMBr);
1948 if (rc)
1949 return rc;
1950
1951 pSMB->BufferFormat = 0x04;
1952 pSMB->SearchAttributes =
1953 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1954 ATTR_DIRECTORY);
1955
1956 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1957 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001958 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001959 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 name_len++; /* trailing null */
1961 name_len *= 2;
1962 pSMB->OldFileName[name_len] = 0x04; /* pad */
1963 /* protocol requires ASCII signature byte on Unicode string */
1964 pSMB->OldFileName[name_len + 1] = 0x00;
1965 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001966 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001967 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1969 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001970 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 name_len = strnlen(fromName, PATH_MAX);
1972 name_len++; /* trailing null */
1973 strncpy(pSMB->OldFileName, fromName, name_len);
1974 name_len2 = strnlen(toName, PATH_MAX);
1975 name_len2++; /* trailing null */
1976 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1977 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1978 name_len2++; /* trailing null */
1979 name_len2++; /* signature byte */
1980 }
1981
1982 count = 1 /* 1st signature byte */ + name_len + name_len2;
1983 pSMB->hdr.smb_buf_length += count;
1984 pSMB->ByteCount = cpu_to_le16(count);
1985
1986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001988 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001989 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 cifs_buf_release(pSMB);
1993
1994 if (rc == -EAGAIN)
1995 goto renameRetry;
1996
1997 return rc;
1998}
1999
Steve French50c2f752007-07-13 00:33:32 +00002000int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002001 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002002 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003{
2004 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2005 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002006 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 char *data_offset;
2008 char dummy_string[30];
2009 int rc = 0;
2010 int bytes_returned = 0;
2011 int len_of_str;
2012 __u16 params, param_offset, offset, count, byte_count;
2013
2014 cFYI(1, ("Rename to File by handle"));
2015 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2016 (void **) &pSMBr);
2017 if (rc)
2018 return rc;
2019
2020 params = 6;
2021 pSMB->MaxSetupCount = 0;
2022 pSMB->Reserved = 0;
2023 pSMB->Flags = 0;
2024 pSMB->Timeout = 0;
2025 pSMB->Reserved2 = 0;
2026 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2027 offset = param_offset + params;
2028
2029 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2030 rename_info = (struct set_file_rename *) data_offset;
2031 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002032 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 pSMB->SetupCount = 1;
2034 pSMB->Reserved3 = 0;
2035 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2036 byte_count = 3 /* pad */ + params;
2037 pSMB->ParameterCount = cpu_to_le16(params);
2038 pSMB->TotalParameterCount = pSMB->ParameterCount;
2039 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2040 pSMB->DataOffset = cpu_to_le16(offset);
2041 /* construct random name ".cifs_tmp<inodenum><mid>" */
2042 rename_info->overwrite = cpu_to_le32(1);
2043 rename_info->root_fid = 0;
2044 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002045 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002046 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2047 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002048 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002050 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002051 target_name, PATH_MAX, nls_codepage,
2052 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 }
2054 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002055 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 byte_count += count;
2057 pSMB->DataCount = cpu_to_le16(count);
2058 pSMB->TotalDataCount = pSMB->DataCount;
2059 pSMB->Fid = netfid;
2060 pSMB->InformationLevel =
2061 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2062 pSMB->Reserved4 = 0;
2063 pSMB->hdr.smb_buf_length += byte_count;
2064 pSMB->ByteCount = cpu_to_le16(byte_count);
2065 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002067 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002068 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002069 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002070
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 cifs_buf_release(pSMB);
2072
2073 /* Note: On -EAGAIN error only caller can retry on handle based calls
2074 since file handle passed in no longer valid */
2075
2076 return rc;
2077}
2078
2079int
Steve French50c2f752007-07-13 00:33:32 +00002080CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2081 const __u16 target_tid, const char *toName, const int flags,
2082 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083{
2084 int rc = 0;
2085 COPY_REQ *pSMB = NULL;
2086 COPY_RSP *pSMBr = NULL;
2087 int bytes_returned;
2088 int name_len, name_len2;
2089 __u16 count;
2090
2091 cFYI(1, ("In CIFSSMBCopy"));
2092copyRetry:
2093 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2094 (void **) &pSMBr);
2095 if (rc)
2096 return rc;
2097
2098 pSMB->BufferFormat = 0x04;
2099 pSMB->Tid2 = target_tid;
2100
2101 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2102
2103 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002104 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002105 fromName, PATH_MAX, nls_codepage,
2106 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 name_len++; /* trailing null */
2108 name_len *= 2;
2109 pSMB->OldFileName[name_len] = 0x04; /* pad */
2110 /* protocol requires ASCII signature byte on Unicode string */
2111 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002112 name_len2 =
2113 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002114 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2116 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002117 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 name_len = strnlen(fromName, PATH_MAX);
2119 name_len++; /* trailing null */
2120 strncpy(pSMB->OldFileName, fromName, name_len);
2121 name_len2 = strnlen(toName, PATH_MAX);
2122 name_len2++; /* trailing null */
2123 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2124 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2125 name_len2++; /* trailing null */
2126 name_len2++; /* signature byte */
2127 }
2128
2129 count = 1 /* 1st signature byte */ + name_len + name_len2;
2130 pSMB->hdr.smb_buf_length += count;
2131 pSMB->ByteCount = cpu_to_le16(count);
2132
2133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2135 if (rc) {
2136 cFYI(1, ("Send error in copy = %d with %d files copied",
2137 rc, le16_to_cpu(pSMBr->CopyCount)));
2138 }
Steve French0d817bc2008-05-22 02:02:03 +00002139 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
2141 if (rc == -EAGAIN)
2142 goto copyRetry;
2143
2144 return rc;
2145}
2146
2147int
2148CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2149 const char *fromName, const char *toName,
2150 const struct nls_table *nls_codepage)
2151{
2152 TRANSACTION2_SPI_REQ *pSMB = NULL;
2153 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2154 char *data_offset;
2155 int name_len;
2156 int name_len_target;
2157 int rc = 0;
2158 int bytes_returned = 0;
2159 __u16 params, param_offset, offset, byte_count;
2160
2161 cFYI(1, ("In Symlink Unix style"));
2162createSymLinkRetry:
2163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2164 (void **) &pSMBr);
2165 if (rc)
2166 return rc;
2167
2168 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2169 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002170 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 /* find define for this maxpathcomponent */
2172 , nls_codepage);
2173 name_len++; /* trailing null */
2174 name_len *= 2;
2175
Steve French50c2f752007-07-13 00:33:32 +00002176 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 name_len = strnlen(fromName, PATH_MAX);
2178 name_len++; /* trailing null */
2179 strncpy(pSMB->FileName, fromName, name_len);
2180 }
2181 params = 6 + name_len;
2182 pSMB->MaxSetupCount = 0;
2183 pSMB->Reserved = 0;
2184 pSMB->Flags = 0;
2185 pSMB->Timeout = 0;
2186 pSMB->Reserved2 = 0;
2187 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002188 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 offset = param_offset + params;
2190
2191 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2192 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2193 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002194 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 /* find define for this maxpathcomponent */
2196 , nls_codepage);
2197 name_len_target++; /* trailing null */
2198 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002199 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 name_len_target = strnlen(toName, PATH_MAX);
2201 name_len_target++; /* trailing null */
2202 strncpy(data_offset, toName, name_len_target);
2203 }
2204
2205 pSMB->MaxParameterCount = cpu_to_le16(2);
2206 /* BB find exact max on data count below from sess */
2207 pSMB->MaxDataCount = cpu_to_le16(1000);
2208 pSMB->SetupCount = 1;
2209 pSMB->Reserved3 = 0;
2210 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2211 byte_count = 3 /* pad */ + params + name_len_target;
2212 pSMB->DataCount = cpu_to_le16(name_len_target);
2213 pSMB->ParameterCount = cpu_to_le16(params);
2214 pSMB->TotalDataCount = pSMB->DataCount;
2215 pSMB->TotalParameterCount = pSMB->ParameterCount;
2216 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2217 pSMB->DataOffset = cpu_to_le16(offset);
2218 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2219 pSMB->Reserved4 = 0;
2220 pSMB->hdr.smb_buf_length += byte_count;
2221 pSMB->ByteCount = cpu_to_le16(byte_count);
2222 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2223 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002224 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002225 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002226 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
Steve French0d817bc2008-05-22 02:02:03 +00002228 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229
2230 if (rc == -EAGAIN)
2231 goto createSymLinkRetry;
2232
2233 return rc;
2234}
2235
2236int
2237CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2238 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002239 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240{
2241 TRANSACTION2_SPI_REQ *pSMB = NULL;
2242 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2243 char *data_offset;
2244 int name_len;
2245 int name_len_target;
2246 int rc = 0;
2247 int bytes_returned = 0;
2248 __u16 params, param_offset, offset, byte_count;
2249
2250 cFYI(1, ("In Create Hard link Unix style"));
2251createHardLinkRetry:
2252 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2253 (void **) &pSMBr);
2254 if (rc)
2255 return rc;
2256
2257 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002258 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002259 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 name_len++; /* trailing null */
2261 name_len *= 2;
2262
Steve French50c2f752007-07-13 00:33:32 +00002263 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 name_len = strnlen(toName, PATH_MAX);
2265 name_len++; /* trailing null */
2266 strncpy(pSMB->FileName, toName, name_len);
2267 }
2268 params = 6 + name_len;
2269 pSMB->MaxSetupCount = 0;
2270 pSMB->Reserved = 0;
2271 pSMB->Flags = 0;
2272 pSMB->Timeout = 0;
2273 pSMB->Reserved2 = 0;
2274 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002275 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 offset = param_offset + params;
2277
2278 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2279 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2280 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002281 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002282 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 name_len_target++; /* trailing null */
2284 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002285 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 name_len_target = strnlen(fromName, PATH_MAX);
2287 name_len_target++; /* trailing null */
2288 strncpy(data_offset, fromName, name_len_target);
2289 }
2290
2291 pSMB->MaxParameterCount = cpu_to_le16(2);
2292 /* BB find exact max on data count below from sess*/
2293 pSMB->MaxDataCount = cpu_to_le16(1000);
2294 pSMB->SetupCount = 1;
2295 pSMB->Reserved3 = 0;
2296 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2297 byte_count = 3 /* pad */ + params + name_len_target;
2298 pSMB->ParameterCount = cpu_to_le16(params);
2299 pSMB->TotalParameterCount = pSMB->ParameterCount;
2300 pSMB->DataCount = cpu_to_le16(name_len_target);
2301 pSMB->TotalDataCount = pSMB->DataCount;
2302 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2303 pSMB->DataOffset = cpu_to_le16(offset);
2304 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2305 pSMB->Reserved4 = 0;
2306 pSMB->hdr.smb_buf_length += byte_count;
2307 pSMB->ByteCount = cpu_to_le16(byte_count);
2308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002310 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002311 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
2314 cifs_buf_release(pSMB);
2315 if (rc == -EAGAIN)
2316 goto createHardLinkRetry;
2317
2318 return rc;
2319}
2320
2321int
2322CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2323 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002324 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325{
2326 int rc = 0;
2327 NT_RENAME_REQ *pSMB = NULL;
2328 RENAME_RSP *pSMBr = NULL;
2329 int bytes_returned;
2330 int name_len, name_len2;
2331 __u16 count;
2332
2333 cFYI(1, ("In CIFSCreateHardLink"));
2334winCreateHardLinkRetry:
2335
2336 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2337 (void **) &pSMBr);
2338 if (rc)
2339 return rc;
2340
2341 pSMB->SearchAttributes =
2342 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2343 ATTR_DIRECTORY);
2344 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2345 pSMB->ClusterCount = 0;
2346
2347 pSMB->BufferFormat = 0x04;
2348
2349 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2350 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002351 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002352 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 name_len++; /* trailing null */
2354 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002355
2356 /* protocol specifies ASCII buffer format (0x04) for unicode */
2357 pSMB->OldFileName[name_len] = 0x04;
2358 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002360 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002361 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2363 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002364 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 name_len = strnlen(fromName, PATH_MAX);
2366 name_len++; /* trailing null */
2367 strncpy(pSMB->OldFileName, fromName, name_len);
2368 name_len2 = strnlen(toName, PATH_MAX);
2369 name_len2++; /* trailing null */
2370 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2371 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2372 name_len2++; /* trailing null */
2373 name_len2++; /* signature byte */
2374 }
2375
2376 count = 1 /* string type byte */ + name_len + name_len2;
2377 pSMB->hdr.smb_buf_length += count;
2378 pSMB->ByteCount = cpu_to_le16(count);
2379
2380 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2381 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002382 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002383 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002385
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 cifs_buf_release(pSMB);
2387 if (rc == -EAGAIN)
2388 goto winCreateHardLinkRetry;
2389
2390 return rc;
2391}
2392
2393int
2394CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002395 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 const struct nls_table *nls_codepage)
2397{
2398/* SMB_QUERY_FILE_UNIX_LINK */
2399 TRANSACTION2_QPI_REQ *pSMB = NULL;
2400 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2401 int rc = 0;
2402 int bytes_returned;
2403 int name_len;
2404 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002405 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406
2407 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2408
2409querySymLinkRetry:
2410 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2411 (void **) &pSMBr);
2412 if (rc)
2413 return rc;
2414
2415 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2416 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002417 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2418 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 name_len++; /* trailing null */
2420 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002421 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 name_len = strnlen(searchName, PATH_MAX);
2423 name_len++; /* trailing null */
2424 strncpy(pSMB->FileName, searchName, name_len);
2425 }
2426
2427 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2428 pSMB->TotalDataCount = 0;
2429 pSMB->MaxParameterCount = cpu_to_le16(2);
2430 /* BB find exact max data count below from sess structure BB */
2431 pSMB->MaxDataCount = cpu_to_le16(4000);
2432 pSMB->MaxSetupCount = 0;
2433 pSMB->Reserved = 0;
2434 pSMB->Flags = 0;
2435 pSMB->Timeout = 0;
2436 pSMB->Reserved2 = 0;
2437 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002438 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 pSMB->DataCount = 0;
2440 pSMB->DataOffset = 0;
2441 pSMB->SetupCount = 1;
2442 pSMB->Reserved3 = 0;
2443 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2444 byte_count = params + 1 /* pad */ ;
2445 pSMB->TotalParameterCount = cpu_to_le16(params);
2446 pSMB->ParameterCount = pSMB->TotalParameterCount;
2447 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2448 pSMB->Reserved4 = 0;
2449 pSMB->hdr.smb_buf_length += byte_count;
2450 pSMB->ByteCount = cpu_to_le16(byte_count);
2451
2452 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2453 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2454 if (rc) {
2455 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2456 } else {
2457 /* decode response */
2458
2459 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002461 if (rc || (pSMBr->ByteCount < 2))
2462 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002464 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002465 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
Jeff Layton460b9692009-04-30 07:17:56 -04002467 data_start = ((char *) &pSMBr->hdr.Protocol) +
2468 le16_to_cpu(pSMBr->t2.DataOffset);
2469
Steve French0e0d2cf2009-05-01 05:27:32 +00002470 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2471 is_unicode = true;
2472 else
2473 is_unicode = false;
2474
Steve French737b7582005-04-28 22:41:06 -07002475 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002476 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002477 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002478 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002479 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 }
2481 }
2482 cifs_buf_release(pSMB);
2483 if (rc == -EAGAIN)
2484 goto querySymLinkRetry;
2485 return rc;
2486}
2487
Parag Warudkarc9489772007-10-23 18:09:48 +00002488#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002489/* Initialize NT TRANSACT SMB into small smb request buffer.
2490 This assumes that all NT TRANSACTS that we init here have
2491 total parm and data under about 400 bytes (to fit in small cifs
2492 buffer size), which is the case so far, it easily fits. NB:
2493 Setup words themselves and ByteCount
2494 MaxSetupCount (size of returned setup area) and
2495 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002496static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002497smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002498 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002499 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002500{
2501 int rc;
2502 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002503 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002504
2505 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2506 (void **)&pSMB);
2507 if (rc)
2508 return rc;
2509 *ret_buf = (void *)pSMB;
2510 pSMB->Reserved = 0;
2511 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2512 pSMB->TotalDataCount = 0;
2513 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2514 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2515 pSMB->ParameterCount = pSMB->TotalParameterCount;
2516 pSMB->DataCount = pSMB->TotalDataCount;
2517 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2518 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2519 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2520 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2521 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2522 pSMB->SubCommand = cpu_to_le16(sub_command);
2523 return 0;
2524}
2525
2526static int
Steve French50c2f752007-07-13 00:33:32 +00002527validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002528 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002529{
Steve French50c2f752007-07-13 00:33:32 +00002530 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002531 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002532 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002533
Steve French630f3f02007-10-25 21:17:17 +00002534 *pdatalen = 0;
2535 *pparmlen = 0;
2536
Steve French790fe572007-07-07 19:25:05 +00002537 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002538 return -EINVAL;
2539
2540 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2541
2542 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002543 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002544 (char *)&pSMBr->ByteCount;
2545
Steve French0a4b92c2006-01-12 15:44:21 -08002546 data_offset = le32_to_cpu(pSMBr->DataOffset);
2547 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002548 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002549 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2550
2551 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2552 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2553
2554 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002555 if (*ppparm > end_of_smb) {
2556 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002558 } else if (parm_count + *ppparm > end_of_smb) {
2559 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002560 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002561 } else if (*ppdata > end_of_smb) {
2562 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002563 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002564 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002565 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002566 *ppdata, data_count, (data_count + *ppdata),
2567 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002568 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002569 } else if (parm_count + data_count > pSMBr->ByteCount) {
2570 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002571 return -EINVAL;
2572 }
Steve French630f3f02007-10-25 21:17:17 +00002573 *pdatalen = data_count;
2574 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002575 return 0;
2576}
2577
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578int
2579CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2580 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002581 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 const struct nls_table *nls_codepage)
2583{
2584 int rc = 0;
2585 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002586 struct smb_com_transaction_ioctl_req *pSMB;
2587 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
2589 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2590 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2591 (void **) &pSMBr);
2592 if (rc)
2593 return rc;
2594
2595 pSMB->TotalParameterCount = 0 ;
2596 pSMB->TotalDataCount = 0;
2597 pSMB->MaxParameterCount = cpu_to_le32(2);
2598 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002599 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2600 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 pSMB->MaxSetupCount = 4;
2602 pSMB->Reserved = 0;
2603 pSMB->ParameterOffset = 0;
2604 pSMB->DataCount = 0;
2605 pSMB->DataOffset = 0;
2606 pSMB->SetupCount = 4;
2607 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2608 pSMB->ParameterCount = pSMB->TotalParameterCount;
2609 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2610 pSMB->IsFsctl = 1; /* FSCTL */
2611 pSMB->IsRootFlag = 0;
2612 pSMB->Fid = fid; /* file handle always le */
2613 pSMB->ByteCount = 0;
2614
2615 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2616 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2617 if (rc) {
2618 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2619 } else { /* decode response */
2620 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2621 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002622 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 /* BB also check enough total bytes returned */
2624 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002625 goto qreparse_out;
2626 }
2627 if (data_count && (data_count < 2048)) {
2628 char *end_of_smb = 2 /* sizeof byte count */ +
2629 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
Steve Frenchafe48c32009-05-02 05:25:46 +00002631 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002632 (struct reparse_data *)
2633 ((char *)&pSMBr->hdr.Protocol
2634 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002635 if ((char *)reparse_buf >= end_of_smb) {
2636 rc = -EIO;
2637 goto qreparse_out;
2638 }
2639 if ((reparse_buf->LinkNamesBuf +
2640 reparse_buf->TargetNameOffset +
2641 reparse_buf->TargetNameLen) > end_of_smb) {
2642 cFYI(1, ("reparse buf beyond SMB"));
2643 rc = -EIO;
2644 goto qreparse_out;
2645 }
Steve French50c2f752007-07-13 00:33:32 +00002646
Steve Frenchafe48c32009-05-02 05:25:46 +00002647 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2648 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002649 (reparse_buf->LinkNamesBuf +
2650 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002651 buflen,
2652 reparse_buf->TargetNameLen,
2653 nls_codepage, 0);
2654 } else { /* ASCII names */
2655 strncpy(symlinkinfo,
2656 reparse_buf->LinkNamesBuf +
2657 reparse_buf->TargetNameOffset,
2658 min_t(const int, buflen,
2659 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002661 } else {
2662 rc = -EIO;
2663 cFYI(1, ("Invalid return data count on "
2664 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002666 symlinkinfo[buflen] = 0; /* just in case so the caller
2667 does not go off the end of the buffer */
2668 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 }
Steve French989c7e52009-05-02 05:32:20 +00002670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002672 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
2674 /* Note: On -EAGAIN error only caller can retry on handle based calls
2675 since file handle passed in no longer valid */
2676
2677 return rc;
2678}
Steve Frenchafe48c32009-05-02 05:25:46 +00002679#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680
2681#ifdef CONFIG_CIFS_POSIX
2682
2683/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002684static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2685 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686{
2687 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002688 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2689 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2690 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2692
2693 return;
2694}
2695
2696/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002697static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2698 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699{
2700 int size = 0;
2701 int i;
2702 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002703 struct cifs_posix_ace *pACE;
2704 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2705 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
2707 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2708 return -EOPNOTSUPP;
2709
Steve French790fe572007-07-07 19:25:05 +00002710 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 count = le16_to_cpu(cifs_acl->access_entry_count);
2712 pACE = &cifs_acl->ace_array[0];
2713 size = sizeof(struct cifs_posix_acl);
2714 size += sizeof(struct cifs_posix_ace) * count;
2715 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002716 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002717 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2718 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 return -EINVAL;
2720 }
Steve French790fe572007-07-07 19:25:05 +00002721 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 count = le16_to_cpu(cifs_acl->access_entry_count);
2723 size = sizeof(struct cifs_posix_acl);
2724 size += sizeof(struct cifs_posix_ace) * count;
2725/* skip past access ACEs to get to default ACEs */
2726 pACE = &cifs_acl->ace_array[count];
2727 count = le16_to_cpu(cifs_acl->default_entry_count);
2728 size += sizeof(struct cifs_posix_ace) * count;
2729 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002730 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 return -EINVAL;
2732 } else {
2733 /* illegal type */
2734 return -EINVAL;
2735 }
2736
2737 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002738 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002739 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002740 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 return -ERANGE;
2742 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002743 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002744 for (i = 0; i < count ; i++) {
2745 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2746 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 }
2748 }
2749 return size;
2750}
2751
Steve French50c2f752007-07-13 00:33:32 +00002752static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2753 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754{
2755 __u16 rc = 0; /* 0 = ACL converted ok */
2756
Steve Frenchff7feac2005-11-15 16:45:16 -08002757 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2758 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002760 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 /* Probably no need to le convert -1 on any arch but can not hurt */
2762 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002763 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002764 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002765 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 return rc;
2767}
2768
2769/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002770static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2771 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772{
2773 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002774 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2775 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 int count;
2777 int i;
2778
Steve French790fe572007-07-07 19:25:05 +00002779 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 return 0;
2781
2782 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002783 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002784 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002785 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002786 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002787 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002788 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789 return 0;
2790 }
2791 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002792 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002793 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002794 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002795 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 else {
Steve French50c2f752007-07-13 00:33:32 +00002797 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 return 0;
2799 }
Steve French50c2f752007-07-13 00:33:32 +00002800 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2802 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002803 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 /* ACE not converted */
2805 break;
2806 }
2807 }
Steve French790fe572007-07-07 19:25:05 +00002808 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2810 rc += sizeof(struct cifs_posix_acl);
2811 /* BB add check to make sure ACL does not overflow SMB */
2812 }
2813 return rc;
2814}
2815
2816int
2817CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002818 const unsigned char *searchName,
2819 char *acl_inf, const int buflen, const int acl_type,
2820 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821{
2822/* SMB_QUERY_POSIX_ACL */
2823 TRANSACTION2_QPI_REQ *pSMB = NULL;
2824 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2825 int rc = 0;
2826 int bytes_returned;
2827 int name_len;
2828 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002829
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2831
2832queryAclRetry:
2833 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2834 (void **) &pSMBr);
2835 if (rc)
2836 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002837
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2839 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002840 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002841 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 name_len++; /* trailing null */
2843 name_len *= 2;
2844 pSMB->FileName[name_len] = 0;
2845 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002846 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 name_len = strnlen(searchName, PATH_MAX);
2848 name_len++; /* trailing null */
2849 strncpy(pSMB->FileName, searchName, name_len);
2850 }
2851
2852 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2853 pSMB->TotalDataCount = 0;
2854 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002855 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 pSMB->MaxDataCount = cpu_to_le16(4000);
2857 pSMB->MaxSetupCount = 0;
2858 pSMB->Reserved = 0;
2859 pSMB->Flags = 0;
2860 pSMB->Timeout = 0;
2861 pSMB->Reserved2 = 0;
2862 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002863 offsetof(struct smb_com_transaction2_qpi_req,
2864 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 pSMB->DataCount = 0;
2866 pSMB->DataOffset = 0;
2867 pSMB->SetupCount = 1;
2868 pSMB->Reserved3 = 0;
2869 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2870 byte_count = params + 1 /* pad */ ;
2871 pSMB->TotalParameterCount = cpu_to_le16(params);
2872 pSMB->ParameterCount = pSMB->TotalParameterCount;
2873 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2874 pSMB->Reserved4 = 0;
2875 pSMB->hdr.smb_buf_length += byte_count;
2876 pSMB->ByteCount = cpu_to_le16(byte_count);
2877
2878 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2879 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002880 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 if (rc) {
2882 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2883 } else {
2884 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002885
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2887 if (rc || (pSMBr->ByteCount < 2))
2888 /* BB also check enough total bytes returned */
2889 rc = -EIO; /* bad smb */
2890 else {
2891 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2892 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2893 rc = cifs_copy_posix_acl(acl_inf,
2894 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002895 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 }
2897 }
2898 cifs_buf_release(pSMB);
2899 if (rc == -EAGAIN)
2900 goto queryAclRetry;
2901 return rc;
2902}
2903
2904int
2905CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002906 const unsigned char *fileName,
2907 const char *local_acl, const int buflen,
2908 const int acl_type,
2909 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910{
2911 struct smb_com_transaction2_spi_req *pSMB = NULL;
2912 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2913 char *parm_data;
2914 int name_len;
2915 int rc = 0;
2916 int bytes_returned = 0;
2917 __u16 params, byte_count, data_count, param_offset, offset;
2918
2919 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2920setAclRetry:
2921 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002922 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 if (rc)
2924 return rc;
2925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2926 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002927 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002928 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 name_len++; /* trailing null */
2930 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002931 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 name_len = strnlen(fileName, PATH_MAX);
2933 name_len++; /* trailing null */
2934 strncpy(pSMB->FileName, fileName, name_len);
2935 }
2936 params = 6 + name_len;
2937 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002938 /* BB find max SMB size from sess */
2939 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 pSMB->MaxSetupCount = 0;
2941 pSMB->Reserved = 0;
2942 pSMB->Flags = 0;
2943 pSMB->Timeout = 0;
2944 pSMB->Reserved2 = 0;
2945 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002946 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 offset = param_offset + params;
2948 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2949 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2950
2951 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002952 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
Steve French790fe572007-07-07 19:25:05 +00002954 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 rc = -EOPNOTSUPP;
2956 goto setACLerrorExit;
2957 }
2958 pSMB->DataOffset = cpu_to_le16(offset);
2959 pSMB->SetupCount = 1;
2960 pSMB->Reserved3 = 0;
2961 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2962 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2963 byte_count = 3 /* pad */ + params + data_count;
2964 pSMB->DataCount = cpu_to_le16(data_count);
2965 pSMB->TotalDataCount = pSMB->DataCount;
2966 pSMB->ParameterCount = cpu_to_le16(params);
2967 pSMB->TotalParameterCount = pSMB->ParameterCount;
2968 pSMB->Reserved4 = 0;
2969 pSMB->hdr.smb_buf_length += byte_count;
2970 pSMB->ByteCount = cpu_to_le16(byte_count);
2971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002973 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
2976setACLerrorExit:
2977 cifs_buf_release(pSMB);
2978 if (rc == -EAGAIN)
2979 goto setAclRetry;
2980 return rc;
2981}
2982
Steve Frenchf654bac2005-04-28 22:41:04 -07002983/* BB fix tabs in this function FIXME BB */
2984int
2985CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002986 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002987{
Steve French50c2f752007-07-13 00:33:32 +00002988 int rc = 0;
2989 struct smb_t2_qfi_req *pSMB = NULL;
2990 struct smb_t2_qfi_rsp *pSMBr = NULL;
2991 int bytes_returned;
2992 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002993
Steve French790fe572007-07-07 19:25:05 +00002994 cFYI(1, ("In GetExtAttr"));
2995 if (tcon == NULL)
2996 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002997
2998GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002999 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3000 (void **) &pSMBr);
3001 if (rc)
3002 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003003
Steve Frenchad7a2922008-02-07 23:25:02 +00003004 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003005 pSMB->t2.TotalDataCount = 0;
3006 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3007 /* BB find exact max data count below from sess structure BB */
3008 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3009 pSMB->t2.MaxSetupCount = 0;
3010 pSMB->t2.Reserved = 0;
3011 pSMB->t2.Flags = 0;
3012 pSMB->t2.Timeout = 0;
3013 pSMB->t2.Reserved2 = 0;
3014 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3015 Fid) - 4);
3016 pSMB->t2.DataCount = 0;
3017 pSMB->t2.DataOffset = 0;
3018 pSMB->t2.SetupCount = 1;
3019 pSMB->t2.Reserved3 = 0;
3020 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3021 byte_count = params + 1 /* pad */ ;
3022 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3023 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3025 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003026 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003027 pSMB->hdr.smb_buf_length += byte_count;
3028 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003029
Steve French790fe572007-07-07 19:25:05 +00003030 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3031 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3032 if (rc) {
3033 cFYI(1, ("error %d in GetExtAttr", rc));
3034 } else {
3035 /* decode response */
3036 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3037 if (rc || (pSMBr->ByteCount < 2))
3038 /* BB also check enough total bytes returned */
3039 /* If rc should we check for EOPNOSUPP and
3040 disable the srvino flag? or in caller? */
3041 rc = -EIO; /* bad smb */
3042 else {
3043 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3044 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3045 struct file_chattr_info *pfinfo;
3046 /* BB Do we need a cast or hash here ? */
3047 if (count != 16) {
3048 cFYI(1, ("Illegal size ret in GetExtAttr"));
3049 rc = -EIO;
3050 goto GetExtAttrOut;
3051 }
3052 pfinfo = (struct file_chattr_info *)
3053 (data_offset + (char *) &pSMBr->hdr.Protocol);
3054 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003055 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003056 }
3057 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003058GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003059 cifs_buf_release(pSMB);
3060 if (rc == -EAGAIN)
3061 goto GetExtAttrRetry;
3062 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003063}
3064
Steve Frenchf654bac2005-04-28 22:41:04 -07003065#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066
Steve French297647c2007-10-12 04:11:59 +00003067#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003068/* Get Security Descriptor (by handle) from remote server for a file or dir */
3069int
3070CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003071 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003072{
3073 int rc = 0;
3074 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003075 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003076 struct kvec iov[1];
3077
3078 cFYI(1, ("GetCifsACL"));
3079
Steve French630f3f02007-10-25 21:17:17 +00003080 *pbuflen = 0;
3081 *acl_inf = NULL;
3082
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003083 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003084 8 /* parm len */, tcon, (void **) &pSMB);
3085 if (rc)
3086 return rc;
3087
3088 pSMB->MaxParameterCount = cpu_to_le32(4);
3089 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3090 pSMB->MaxSetupCount = 0;
3091 pSMB->Fid = fid; /* file handle always le */
3092 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3093 CIFS_ACL_DACL);
3094 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3095 pSMB->hdr.smb_buf_length += 11;
3096 iov[0].iov_base = (char *)pSMB;
3097 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3098
Steve Frencha761ac52007-10-18 21:45:27 +00003099 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003100 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003101 cifs_stats_inc(&tcon->num_acl_get);
3102 if (rc) {
3103 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3104 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003105 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003106 __u32 parm_len;
3107 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003108 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003109 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003110
3111/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003112 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003113 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003114 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003115 goto qsec_out;
3116 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3117
Steve French630f3f02007-10-25 21:17:17 +00003118 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003119
3120 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3121 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003122 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003123 goto qsec_out;
3124 }
3125
3126/* BB check that data area is minimum length and as big as acl_len */
3127
Steve Frenchaf6f4612007-10-16 18:40:37 +00003128 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003129 if (acl_len != *pbuflen) {
3130 cERROR(1, ("acl length %d does not match %d",
3131 acl_len, *pbuflen));
3132 if (*pbuflen > acl_len)
3133 *pbuflen = acl_len;
3134 }
Steve French0a4b92c2006-01-12 15:44:21 -08003135
Steve French630f3f02007-10-25 21:17:17 +00003136 /* check if buffer is big enough for the acl
3137 header followed by the smallest SID */
3138 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3139 (*pbuflen >= 64 * 1024)) {
3140 cERROR(1, ("bad acl length %d", *pbuflen));
3141 rc = -EINVAL;
3142 *pbuflen = 0;
3143 } else {
3144 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3145 if (*acl_inf == NULL) {
3146 *pbuflen = 0;
3147 rc = -ENOMEM;
3148 }
3149 memcpy(*acl_inf, pdata, *pbuflen);
3150 }
Steve French0a4b92c2006-01-12 15:44:21 -08003151 }
3152qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003153 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003154 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003155 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003156 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003157/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003158 return rc;
3159}
Steve French97837582007-12-31 07:47:21 +00003160
3161int
3162CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3163 struct cifs_ntsd *pntsd, __u32 acllen)
3164{
3165 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3166 int rc = 0;
3167 int bytes_returned = 0;
3168 SET_SEC_DESC_REQ *pSMB = NULL;
3169 NTRANSACT_RSP *pSMBr = NULL;
3170
3171setCifsAclRetry:
3172 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3173 (void **) &pSMBr);
3174 if (rc)
3175 return (rc);
3176
3177 pSMB->MaxSetupCount = 0;
3178 pSMB->Reserved = 0;
3179
3180 param_count = 8;
3181 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3182 data_count = acllen;
3183 data_offset = param_offset + param_count;
3184 byte_count = 3 /* pad */ + param_count;
3185
3186 pSMB->DataCount = cpu_to_le32(data_count);
3187 pSMB->TotalDataCount = pSMB->DataCount;
3188 pSMB->MaxParameterCount = cpu_to_le32(4);
3189 pSMB->MaxDataCount = cpu_to_le32(16384);
3190 pSMB->ParameterCount = cpu_to_le32(param_count);
3191 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3192 pSMB->TotalParameterCount = pSMB->ParameterCount;
3193 pSMB->DataOffset = cpu_to_le32(data_offset);
3194 pSMB->SetupCount = 0;
3195 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3196 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3197
3198 pSMB->Fid = fid; /* file handle always le */
3199 pSMB->Reserved2 = 0;
3200 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3201
3202 if (pntsd && acllen) {
3203 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3204 (char *) pntsd,
3205 acllen);
3206 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3207
3208 } else
3209 pSMB->hdr.smb_buf_length += byte_count;
3210
3211 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3212 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3213
3214 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3215 if (rc)
3216 cFYI(1, ("Set CIFS ACL returned %d", rc));
3217 cifs_buf_release(pSMB);
3218
3219 if (rc == -EAGAIN)
3220 goto setCifsAclRetry;
3221
3222 return (rc);
3223}
3224
Steve French297647c2007-10-12 04:11:59 +00003225#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003226
Steve French6b8edfe2005-08-23 20:26:03 -07003227/* Legacy Query Path Information call for lookup to old servers such
3228 as Win9x/WinME */
3229int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003230 const unsigned char *searchName,
3231 FILE_ALL_INFO *pFinfo,
3232 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003233{
Steve Frenchad7a2922008-02-07 23:25:02 +00003234 QUERY_INFORMATION_REQ *pSMB;
3235 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003236 int rc = 0;
3237 int bytes_returned;
3238 int name_len;
3239
Steve French50c2f752007-07-13 00:33:32 +00003240 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003241QInfRetry:
3242 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003243 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003244 if (rc)
3245 return rc;
3246
3247 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3248 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003249 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3250 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003251 name_len++; /* trailing null */
3252 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003253 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003254 name_len = strnlen(searchName, PATH_MAX);
3255 name_len++; /* trailing null */
3256 strncpy(pSMB->FileName, searchName, name_len);
3257 }
3258 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003259 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003260 pSMB->hdr.smb_buf_length += (__u16) name_len;
3261 pSMB->ByteCount = cpu_to_le16(name_len);
3262
3263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003265 if (rc) {
3266 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003267 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003268 struct timespec ts;
3269 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003270
3271 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003272 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003273 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003274 ts.tv_nsec = 0;
3275 ts.tv_sec = time;
3276 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003277 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003278 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3279 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003280 pFinfo->AllocationSize =
3281 cpu_to_le64(le32_to_cpu(pSMBr->size));
3282 pFinfo->EndOfFile = pFinfo->AllocationSize;
3283 pFinfo->Attributes =
3284 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003285 } else
3286 rc = -EIO; /* bad buffer passed in */
3287
3288 cifs_buf_release(pSMB);
3289
3290 if (rc == -EAGAIN)
3291 goto QInfRetry;
3292
3293 return rc;
3294}
3295
3296
3297
3298
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299int
3300CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3301 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003302 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003303 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003304 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305{
3306/* level 263 SMB_QUERY_FILE_ALL_INFO */
3307 TRANSACTION2_QPI_REQ *pSMB = NULL;
3308 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3309 int rc = 0;
3310 int bytes_returned;
3311 int name_len;
3312 __u16 params, byte_count;
3313
3314/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3315QPathInfoRetry:
3316 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3317 (void **) &pSMBr);
3318 if (rc)
3319 return rc;
3320
3321 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3322 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003323 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003324 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 name_len++; /* trailing null */
3326 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003327 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 name_len = strnlen(searchName, PATH_MAX);
3329 name_len++; /* trailing null */
3330 strncpy(pSMB->FileName, searchName, name_len);
3331 }
3332
Steve French50c2f752007-07-13 00:33:32 +00003333 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 pSMB->TotalDataCount = 0;
3335 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003336 /* BB find exact max SMB PDU from sess structure BB */
3337 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 pSMB->MaxSetupCount = 0;
3339 pSMB->Reserved = 0;
3340 pSMB->Flags = 0;
3341 pSMB->Timeout = 0;
3342 pSMB->Reserved2 = 0;
3343 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003344 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 pSMB->DataCount = 0;
3346 pSMB->DataOffset = 0;
3347 pSMB->SetupCount = 1;
3348 pSMB->Reserved3 = 0;
3349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3350 byte_count = params + 1 /* pad */ ;
3351 pSMB->TotalParameterCount = cpu_to_le16(params);
3352 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003353 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003354 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3355 else
3356 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 pSMB->Reserved4 = 0;
3358 pSMB->hdr.smb_buf_length += byte_count;
3359 pSMB->ByteCount = cpu_to_le16(byte_count);
3360
3361 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3362 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3363 if (rc) {
3364 cFYI(1, ("Send error in QPathInfo = %d", rc));
3365 } else { /* decode response */
3366 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3367
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003368 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3369 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003370 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003372 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003373 rc = -EIO; /* 24 or 26 expected but we do not read
3374 last field */
3375 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003376 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003378
3379 /* On legacy responses we do not read the last field,
3380 EAsize, fortunately since it varies by subdialect and
3381 also note it differs on Set vs. Get, ie two bytes or 4
3382 bytes depending but we don't care here */
3383 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003384 size = sizeof(FILE_INFO_STANDARD);
3385 else
3386 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 memcpy((char *) pFindData,
3388 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003389 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 } else
3391 rc = -ENOMEM;
3392 }
3393 cifs_buf_release(pSMB);
3394 if (rc == -EAGAIN)
3395 goto QPathInfoRetry;
3396
3397 return rc;
3398}
3399
3400int
3401CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3402 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003403 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003404 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405{
3406/* SMB_QUERY_FILE_UNIX_BASIC */
3407 TRANSACTION2_QPI_REQ *pSMB = NULL;
3408 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3409 int rc = 0;
3410 int bytes_returned = 0;
3411 int name_len;
3412 __u16 params, byte_count;
3413
3414 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3415UnixQPathInfoRetry:
3416 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3417 (void **) &pSMBr);
3418 if (rc)
3419 return rc;
3420
3421 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3422 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003423 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003424 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 name_len++; /* trailing null */
3426 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003427 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 name_len = strnlen(searchName, PATH_MAX);
3429 name_len++; /* trailing null */
3430 strncpy(pSMB->FileName, searchName, name_len);
3431 }
3432
Steve French50c2f752007-07-13 00:33:32 +00003433 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 pSMB->TotalDataCount = 0;
3435 pSMB->MaxParameterCount = cpu_to_le16(2);
3436 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003437 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 pSMB->MaxSetupCount = 0;
3439 pSMB->Reserved = 0;
3440 pSMB->Flags = 0;
3441 pSMB->Timeout = 0;
3442 pSMB->Reserved2 = 0;
3443 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003444 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445 pSMB->DataCount = 0;
3446 pSMB->DataOffset = 0;
3447 pSMB->SetupCount = 1;
3448 pSMB->Reserved3 = 0;
3449 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3450 byte_count = params + 1 /* pad */ ;
3451 pSMB->TotalParameterCount = cpu_to_le16(params);
3452 pSMB->ParameterCount = pSMB->TotalParameterCount;
3453 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3454 pSMB->Reserved4 = 0;
3455 pSMB->hdr.smb_buf_length += byte_count;
3456 pSMB->ByteCount = cpu_to_le16(byte_count);
3457
3458 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3460 if (rc) {
3461 cFYI(1, ("Send error in QPathInfo = %d", rc));
3462 } else { /* decode response */
3463 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3464
3465 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003466 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3467 "Unix Extensions can be disabled on mount "
3468 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 rc = -EIO; /* bad smb */
3470 } else {
3471 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3472 memcpy((char *) pFindData,
3473 (char *) &pSMBr->hdr.Protocol +
3474 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003475 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476 }
3477 }
3478 cifs_buf_release(pSMB);
3479 if (rc == -EAGAIN)
3480 goto UnixQPathInfoRetry;
3481
3482 return rc;
3483}
3484
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485/* xid, tcon, searchName and codepage are input parms, rest are returned */
3486int
3487CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003488 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003490 __u16 *pnetfid,
3491 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492{
3493/* level 257 SMB_ */
3494 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3495 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003496 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 int rc = 0;
3498 int bytes_returned = 0;
3499 int name_len;
3500 __u16 params, byte_count;
3501
Steve French50c2f752007-07-13 00:33:32 +00003502 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503
3504findFirstRetry:
3505 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3506 (void **) &pSMBr);
3507 if (rc)
3508 return rc;
3509
3510 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3511 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003512 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003513 PATH_MAX, nls_codepage, remap);
3514 /* We can not add the asterik earlier in case
3515 it got remapped to 0xF03A as if it were part of the
3516 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003517 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003518 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003519 pSMB->FileName[name_len+1] = 0;
3520 pSMB->FileName[name_len+2] = '*';
3521 pSMB->FileName[name_len+3] = 0;
3522 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3524 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003525 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 } else { /* BB add check for overrun of SMB buf BB */
3527 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003529 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 free buffer exit; BB */
3531 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003532 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003533 pSMB->FileName[name_len+1] = '*';
3534 pSMB->FileName[name_len+2] = 0;
3535 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 }
3537
3538 params = 12 + name_len /* includes null */ ;
3539 pSMB->TotalDataCount = 0; /* no EAs */
3540 pSMB->MaxParameterCount = cpu_to_le16(10);
3541 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3542 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3543 pSMB->MaxSetupCount = 0;
3544 pSMB->Reserved = 0;
3545 pSMB->Flags = 0;
3546 pSMB->Timeout = 0;
3547 pSMB->Reserved2 = 0;
3548 byte_count = params + 1 /* pad */ ;
3549 pSMB->TotalParameterCount = cpu_to_le16(params);
3550 pSMB->ParameterCount = pSMB->TotalParameterCount;
3551 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003552 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3553 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 pSMB->DataCount = 0;
3555 pSMB->DataOffset = 0;
3556 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3557 pSMB->Reserved3 = 0;
3558 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3559 pSMB->SearchAttributes =
3560 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3561 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003562 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3563 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 CIFS_SEARCH_RETURN_RESUME);
3565 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3566
3567 /* BB what should we set StorageType to? Does it matter? BB */
3568 pSMB->SearchStorageType = 0;
3569 pSMB->hdr.smb_buf_length += byte_count;
3570 pSMB->ByteCount = cpu_to_le16(byte_count);
3571
3572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3573 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003574 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575
Steve French88274812006-03-09 22:21:45 +00003576 if (rc) {/* BB add logic to retry regular search if Unix search
3577 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 /* BB Add code to handle unsupported level rc */
3579 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003580
Steve French88274812006-03-09 22:21:45 +00003581 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
3583 /* BB eventually could optimize out free and realloc of buf */
3584 /* for this case */
3585 if (rc == -EAGAIN)
3586 goto findFirstRetry;
3587 } else { /* decode response */
3588 /* BB remember to free buffer if error BB */
3589 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003590 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003591 unsigned int lnoff;
3592
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003594 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 else
Steve French4b18f2a2008-04-29 00:06:05 +00003596 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
3598 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003599 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003600 psrch_inf->srch_entries_start =
3601 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3604 le16_to_cpu(pSMBr->t2.ParameterOffset));
3605
Steve French790fe572007-07-07 19:25:05 +00003606 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003607 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608 else
Steve French4b18f2a2008-04-29 00:06:05 +00003609 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610
Steve French50c2f752007-07-13 00:33:32 +00003611 psrch_inf->entries_in_buffer =
3612 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003613 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003615 lnoff = le16_to_cpu(parms->LastNameOffset);
3616 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3617 lnoff) {
3618 cERROR(1, ("ignoring corrupt resume name"));
3619 psrch_inf->last_entry = NULL;
3620 return rc;
3621 }
3622
Steve French0752f152008-10-07 20:03:33 +00003623 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003624 lnoff;
3625
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 *pnetfid = parms->SearchHandle;
3627 } else {
3628 cifs_buf_release(pSMB);
3629 }
3630 }
3631
3632 return rc;
3633}
3634
3635int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003636 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637{
3638 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3639 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003640 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 char *response_data;
3642 int rc = 0;
3643 int bytes_returned, name_len;
3644 __u16 params, byte_count;
3645
3646 cFYI(1, ("In FindNext"));
3647
Steve French4b18f2a2008-04-29 00:06:05 +00003648 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 return -ENOENT;
3650
3651 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3652 (void **) &pSMBr);
3653 if (rc)
3654 return rc;
3655
Steve French50c2f752007-07-13 00:33:32 +00003656 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 byte_count = 0;
3658 pSMB->TotalDataCount = 0; /* no EAs */
3659 pSMB->MaxParameterCount = cpu_to_le16(8);
3660 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003661 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3662 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 pSMB->MaxSetupCount = 0;
3664 pSMB->Reserved = 0;
3665 pSMB->Flags = 0;
3666 pSMB->Timeout = 0;
3667 pSMB->Reserved2 = 0;
3668 pSMB->ParameterOffset = cpu_to_le16(
3669 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3670 pSMB->DataCount = 0;
3671 pSMB->DataOffset = 0;
3672 pSMB->SetupCount = 1;
3673 pSMB->Reserved3 = 0;
3674 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3675 pSMB->SearchHandle = searchHandle; /* always kept as le */
3676 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003677 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3679 pSMB->ResumeKey = psrch_inf->resume_key;
3680 pSMB->SearchFlags =
3681 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3682
3683 name_len = psrch_inf->resume_name_len;
3684 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003685 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3687 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003688 /* 14 byte parm len above enough for 2 byte null terminator */
3689 pSMB->ResumeFileName[name_len] = 0;
3690 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 } else {
3692 rc = -EINVAL;
3693 goto FNext2_err_exit;
3694 }
3695 byte_count = params + 1 /* pad */ ;
3696 pSMB->TotalParameterCount = cpu_to_le16(params);
3697 pSMB->ParameterCount = pSMB->TotalParameterCount;
3698 pSMB->hdr.smb_buf_length += byte_count;
3699 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003700
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003703 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 if (rc) {
3705 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003706 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003707 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003708 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 } else
3710 cFYI(1, ("FindNext returned = %d", rc));
3711 } else { /* decode response */
3712 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003713
Steve French790fe572007-07-07 19:25:05 +00003714 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003715 unsigned int lnoff;
3716
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 /* BB fixme add lock for file (srch_info) struct here */
3718 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003719 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 else
Steve French4b18f2a2008-04-29 00:06:05 +00003721 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 response_data = (char *) &pSMBr->hdr.Protocol +
3723 le16_to_cpu(pSMBr->t2.ParameterOffset);
3724 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3725 response_data = (char *)&pSMBr->hdr.Protocol +
3726 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003727 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003728 cifs_small_buf_release(
3729 psrch_inf->ntwrk_buf_start);
3730 else
3731 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 psrch_inf->srch_entries_start = response_data;
3733 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003734 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003735 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003736 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 else
Steve French4b18f2a2008-04-29 00:06:05 +00003738 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003739 psrch_inf->entries_in_buffer =
3740 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 psrch_inf->index_of_last_entry +=
3742 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003743 lnoff = le16_to_cpu(parms->LastNameOffset);
3744 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3745 lnoff) {
3746 cERROR(1, ("ignoring corrupt resume name"));
3747 psrch_inf->last_entry = NULL;
3748 return rc;
3749 } else
3750 psrch_inf->last_entry =
3751 psrch_inf->srch_entries_start + lnoff;
3752
Steve French50c2f752007-07-13 00:33:32 +00003753/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3754 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755
3756 /* BB fixme add unlock here */
3757 }
3758
3759 }
3760
3761 /* BB On error, should we leave previous search buf (and count and
3762 last entry fields) intact or free the previous one? */
3763
3764 /* Note: On -EAGAIN error only caller can retry on handle based calls
3765 since file handle passed in no longer valid */
3766FNext2_err_exit:
3767 if (rc != 0)
3768 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 return rc;
3770}
3771
3772int
Steve French50c2f752007-07-13 00:33:32 +00003773CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3774 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775{
3776 int rc = 0;
3777 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
3779 cFYI(1, ("In CIFSSMBFindClose"));
3780 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3781
3782 /* no sense returning error if session restarted
3783 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003784 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 return 0;
3786 if (rc)
3787 return rc;
3788
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 pSMB->FileID = searchHandle;
3790 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003791 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003792 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003794
Steve Frencha4544342005-08-24 13:59:35 -07003795 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796
3797 /* Since session is dead, search handle closed on server already */
3798 if (rc == -EAGAIN)
3799 rc = 0;
3800
3801 return rc;
3802}
3803
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804int
3805CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003806 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003807 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003808 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809{
3810 int rc = 0;
3811 TRANSACTION2_QPI_REQ *pSMB = NULL;
3812 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3813 int name_len, bytes_returned;
3814 __u16 params, byte_count;
3815
Steve French50c2f752007-07-13 00:33:32 +00003816 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003817 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003818 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819
3820GetInodeNumberRetry:
3821 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003822 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 if (rc)
3824 return rc;
3825
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3827 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003828 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003829 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 name_len++; /* trailing null */
3831 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003832 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 name_len = strnlen(searchName, PATH_MAX);
3834 name_len++; /* trailing null */
3835 strncpy(pSMB->FileName, searchName, name_len);
3836 }
3837
3838 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3839 pSMB->TotalDataCount = 0;
3840 pSMB->MaxParameterCount = cpu_to_le16(2);
3841 /* BB find exact max data count below from sess structure BB */
3842 pSMB->MaxDataCount = cpu_to_le16(4000);
3843 pSMB->MaxSetupCount = 0;
3844 pSMB->Reserved = 0;
3845 pSMB->Flags = 0;
3846 pSMB->Timeout = 0;
3847 pSMB->Reserved2 = 0;
3848 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003849 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 pSMB->DataCount = 0;
3851 pSMB->DataOffset = 0;
3852 pSMB->SetupCount = 1;
3853 pSMB->Reserved3 = 0;
3854 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3855 byte_count = params + 1 /* pad */ ;
3856 pSMB->TotalParameterCount = cpu_to_le16(params);
3857 pSMB->ParameterCount = pSMB->TotalParameterCount;
3858 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3859 pSMB->Reserved4 = 0;
3860 pSMB->hdr.smb_buf_length += byte_count;
3861 pSMB->ByteCount = cpu_to_le16(byte_count);
3862
3863 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3864 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3865 if (rc) {
3866 cFYI(1, ("error %d in QueryInternalInfo", rc));
3867 } else {
3868 /* decode response */
3869 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3870 if (rc || (pSMBr->ByteCount < 2))
3871 /* BB also check enough total bytes returned */
3872 /* If rc should we check for EOPNOSUPP and
3873 disable the srvino flag? or in caller? */
3874 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003875 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3877 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003878 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003880 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3882 rc = -EIO;
3883 goto GetInodeNumOut;
3884 }
3885 pfinfo = (struct file_internal_info *)
3886 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003887 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 }
3889 }
3890GetInodeNumOut:
3891 cifs_buf_release(pSMB);
3892 if (rc == -EAGAIN)
3893 goto GetInodeNumberRetry;
3894 return rc;
3895}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
Igor Mammedovfec45852008-05-16 13:06:30 +04003897/* parses DFS refferal V3 structure
3898 * caller is responsible for freeing target_nodes
3899 * returns:
3900 * on success - 0
3901 * on failure - errno
3902 */
3903static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003904parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003905 unsigned int *num_of_nodes,
3906 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003907 const struct nls_table *nls_codepage, int remap,
3908 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003909{
3910 int i, rc = 0;
3911 char *data_end;
3912 bool is_unicode;
3913 struct dfs_referral_level_3 *ref;
3914
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003915 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3916 is_unicode = true;
3917 else
3918 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003919 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3920
3921 if (*num_of_nodes < 1) {
3922 cERROR(1, ("num_referrals: must be at least > 0,"
3923 "but we get num_referrals = %d\n", *num_of_nodes));
3924 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003925 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003926 }
3927
3928 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003929 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003930 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003931 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003932 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003933 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003934 }
3935
3936 /* get the upper boundary of the resp buffer */
3937 data_end = (char *)(&(pSMBr->PathConsumed)) +
3938 le16_to_cpu(pSMBr->t2.DataCount);
3939
3940 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3941 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00003942 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003943
3944 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3945 *num_of_nodes, GFP_KERNEL);
3946 if (*target_nodes == NULL) {
3947 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3948 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003949 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003950 }
3951
3952 /* collect neccessary data from referrals */
3953 for (i = 0; i < *num_of_nodes; i++) {
3954 char *temp;
3955 int max_len;
3956 struct dfs_info3_param *node = (*target_nodes)+i;
3957
Steve French0e0d2cf2009-05-01 05:27:32 +00003958 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003959 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003960 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3961 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003962 cifsConvertToUCS((__le16 *) tmp, searchName,
3963 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003964 node->path_consumed = cifs_ucs2_bytes(tmp,
3965 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04003966 nls_codepage);
3967 kfree(tmp);
3968 } else
3969 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3970
Igor Mammedovfec45852008-05-16 13:06:30 +04003971 node->server_type = le16_to_cpu(ref->ServerType);
3972 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3973
3974 /* copy DfsPath */
3975 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3976 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003977 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3978 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003979 if (!node->path_name) {
3980 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003981 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003982 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003983
3984 /* copy link target UNC */
3985 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3986 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003987 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3988 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003989 if (!node->node_name)
3990 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04003991 }
3992
Steve Frencha1fe78f2008-05-16 18:48:38 +00003993parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04003994 if (rc) {
3995 free_dfs_info_array(*target_nodes, *num_of_nodes);
3996 *target_nodes = NULL;
3997 *num_of_nodes = 0;
3998 }
3999 return rc;
4000}
4001
Linus Torvalds1da177e2005-04-16 15:20:36 -07004002int
4003CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4004 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004005 struct dfs_info3_param **target_nodes,
4006 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004007 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008{
4009/* TRANS2_GET_DFS_REFERRAL */
4010 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4011 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 int rc = 0;
4013 int bytes_returned;
4014 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004016 *num_of_nodes = 0;
4017 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018
4019 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4020 if (ses == NULL)
4021 return -ENODEV;
4022getDFSRetry:
4023 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4024 (void **) &pSMBr);
4025 if (rc)
4026 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004027
4028 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004029 but should never be null here anyway */
4030 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 pSMB->hdr.Tid = ses->ipc_tid;
4032 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004033 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004035 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037
4038 if (ses->capabilities & CAP_UNICODE) {
4039 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4040 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004041 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004042 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 name_len++; /* trailing null */
4044 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004045 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 name_len = strnlen(searchName, PATH_MAX);
4047 name_len++; /* trailing null */
4048 strncpy(pSMB->RequestFileName, searchName, name_len);
4049 }
4050
Steve French790fe572007-07-07 19:25:05 +00004051 if (ses->server) {
4052 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004053 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4054 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4055 }
4056
Steve French50c2f752007-07-13 00:33:32 +00004057 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004058
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 params = 2 /* level */ + name_len /*includes null */ ;
4060 pSMB->TotalDataCount = 0;
4061 pSMB->DataCount = 0;
4062 pSMB->DataOffset = 0;
4063 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004064 /* BB find exact max SMB PDU from sess structure BB */
4065 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 pSMB->MaxSetupCount = 0;
4067 pSMB->Reserved = 0;
4068 pSMB->Flags = 0;
4069 pSMB->Timeout = 0;
4070 pSMB->Reserved2 = 0;
4071 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004072 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 pSMB->SetupCount = 1;
4074 pSMB->Reserved3 = 0;
4075 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4076 byte_count = params + 3 /* pad */ ;
4077 pSMB->ParameterCount = cpu_to_le16(params);
4078 pSMB->TotalParameterCount = pSMB->ParameterCount;
4079 pSMB->MaxReferralLevel = cpu_to_le16(3);
4080 pSMB->hdr.smb_buf_length += byte_count;
4081 pSMB->ByteCount = cpu_to_le16(byte_count);
4082
4083 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4085 if (rc) {
4086 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004087 goto GetDFSRefExit;
4088 }
4089 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004091 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004092 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004093 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004094 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004096
4097 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4098 pSMBr->ByteCount,
4099 le16_to_cpu(pSMBr->t2.DataOffset)));
4100
4101 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004102 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004103 target_nodes, nls_codepage, remap,
4104 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004105
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004107 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
4109 if (rc == -EAGAIN)
4110 goto getDFSRetry;
4111
4112 return rc;
4113}
4114
Steve French20962432005-09-21 22:05:57 -07004115/* Query File System Info such as free space to old servers such as Win 9x */
4116int
4117SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4118{
4119/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4120 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4121 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4122 FILE_SYSTEM_ALLOC_INFO *response_data;
4123 int rc = 0;
4124 int bytes_returned = 0;
4125 __u16 params, byte_count;
4126
4127 cFYI(1, ("OldQFSInfo"));
4128oldQFSInfoRetry:
4129 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4130 (void **) &pSMBr);
4131 if (rc)
4132 return rc;
Steve French20962432005-09-21 22:05:57 -07004133
4134 params = 2; /* level */
4135 pSMB->TotalDataCount = 0;
4136 pSMB->MaxParameterCount = cpu_to_le16(2);
4137 pSMB->MaxDataCount = cpu_to_le16(1000);
4138 pSMB->MaxSetupCount = 0;
4139 pSMB->Reserved = 0;
4140 pSMB->Flags = 0;
4141 pSMB->Timeout = 0;
4142 pSMB->Reserved2 = 0;
4143 byte_count = params + 1 /* pad */ ;
4144 pSMB->TotalParameterCount = cpu_to_le16(params);
4145 pSMB->ParameterCount = pSMB->TotalParameterCount;
4146 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4147 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4148 pSMB->DataCount = 0;
4149 pSMB->DataOffset = 0;
4150 pSMB->SetupCount = 1;
4151 pSMB->Reserved3 = 0;
4152 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4153 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4154 pSMB->hdr.smb_buf_length += byte_count;
4155 pSMB->ByteCount = cpu_to_le16(byte_count);
4156
4157 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4158 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4159 if (rc) {
4160 cFYI(1, ("Send error in QFSInfo = %d", rc));
4161 } else { /* decode response */
4162 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4163
4164 if (rc || (pSMBr->ByteCount < 18))
4165 rc = -EIO; /* bad smb */
4166 else {
4167 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004168 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004169 pSMBr->ByteCount, data_offset));
4170
Steve French50c2f752007-07-13 00:33:32 +00004171 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004172 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4173 FSData->f_bsize =
4174 le16_to_cpu(response_data->BytesPerSector) *
4175 le32_to_cpu(response_data->
4176 SectorsPerAllocationUnit);
4177 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004178 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004179 FSData->f_bfree = FSData->f_bavail =
4180 le32_to_cpu(response_data->FreeAllocationUnits);
4181 cFYI(1,
4182 ("Blocks: %lld Free: %lld Block size %ld",
4183 (unsigned long long)FSData->f_blocks,
4184 (unsigned long long)FSData->f_bfree,
4185 FSData->f_bsize));
4186 }
4187 }
4188 cifs_buf_release(pSMB);
4189
4190 if (rc == -EAGAIN)
4191 goto oldQFSInfoRetry;
4192
4193 return rc;
4194}
4195
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196int
Steve French737b7582005-04-28 22:41:06 -07004197CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198{
4199/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4200 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4201 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4202 FILE_SYSTEM_INFO *response_data;
4203 int rc = 0;
4204 int bytes_returned = 0;
4205 __u16 params, byte_count;
4206
4207 cFYI(1, ("In QFSInfo"));
4208QFSInfoRetry:
4209 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4210 (void **) &pSMBr);
4211 if (rc)
4212 return rc;
4213
4214 params = 2; /* level */
4215 pSMB->TotalDataCount = 0;
4216 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004217 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 pSMB->MaxSetupCount = 0;
4219 pSMB->Reserved = 0;
4220 pSMB->Flags = 0;
4221 pSMB->Timeout = 0;
4222 pSMB->Reserved2 = 0;
4223 byte_count = params + 1 /* pad */ ;
4224 pSMB->TotalParameterCount = cpu_to_le16(params);
4225 pSMB->ParameterCount = pSMB->TotalParameterCount;
4226 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004227 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 pSMB->DataCount = 0;
4229 pSMB->DataOffset = 0;
4230 pSMB->SetupCount = 1;
4231 pSMB->Reserved3 = 0;
4232 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4233 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4234 pSMB->hdr.smb_buf_length += byte_count;
4235 pSMB->ByteCount = cpu_to_le16(byte_count);
4236
4237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4238 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4239 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004240 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004242 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
Steve French20962432005-09-21 22:05:57 -07004244 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 rc = -EIO; /* bad smb */
4246 else {
4247 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248
4249 response_data =
4250 (FILE_SYSTEM_INFO
4251 *) (((char *) &pSMBr->hdr.Protocol) +
4252 data_offset);
4253 FSData->f_bsize =
4254 le32_to_cpu(response_data->BytesPerSector) *
4255 le32_to_cpu(response_data->
4256 SectorsPerAllocationUnit);
4257 FSData->f_blocks =
4258 le64_to_cpu(response_data->TotalAllocationUnits);
4259 FSData->f_bfree = FSData->f_bavail =
4260 le64_to_cpu(response_data->FreeAllocationUnits);
4261 cFYI(1,
4262 ("Blocks: %lld Free: %lld Block size %ld",
4263 (unsigned long long)FSData->f_blocks,
4264 (unsigned long long)FSData->f_bfree,
4265 FSData->f_bsize));
4266 }
4267 }
4268 cifs_buf_release(pSMB);
4269
4270 if (rc == -EAGAIN)
4271 goto QFSInfoRetry;
4272
4273 return rc;
4274}
4275
4276int
Steve French737b7582005-04-28 22:41:06 -07004277CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278{
4279/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4280 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4281 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4282 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4283 int rc = 0;
4284 int bytes_returned = 0;
4285 __u16 params, byte_count;
4286
4287 cFYI(1, ("In QFSAttributeInfo"));
4288QFSAttributeRetry:
4289 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4290 (void **) &pSMBr);
4291 if (rc)
4292 return rc;
4293
4294 params = 2; /* level */
4295 pSMB->TotalDataCount = 0;
4296 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004297 /* BB find exact max SMB PDU from sess structure BB */
4298 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 pSMB->MaxSetupCount = 0;
4300 pSMB->Reserved = 0;
4301 pSMB->Flags = 0;
4302 pSMB->Timeout = 0;
4303 pSMB->Reserved2 = 0;
4304 byte_count = params + 1 /* pad */ ;
4305 pSMB->TotalParameterCount = cpu_to_le16(params);
4306 pSMB->ParameterCount = pSMB->TotalParameterCount;
4307 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004308 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 pSMB->DataCount = 0;
4310 pSMB->DataOffset = 0;
4311 pSMB->SetupCount = 1;
4312 pSMB->Reserved3 = 0;
4313 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4314 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4315 pSMB->hdr.smb_buf_length += byte_count;
4316 pSMB->ByteCount = cpu_to_le16(byte_count);
4317
4318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4320 if (rc) {
4321 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4322 } else { /* decode response */
4323 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4324
Steve French50c2f752007-07-13 00:33:32 +00004325 if (rc || (pSMBr->ByteCount < 13)) {
4326 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 rc = -EIO; /* bad smb */
4328 } else {
4329 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4330 response_data =
4331 (FILE_SYSTEM_ATTRIBUTE_INFO
4332 *) (((char *) &pSMBr->hdr.Protocol) +
4333 data_offset);
4334 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004335 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 }
4337 }
4338 cifs_buf_release(pSMB);
4339
4340 if (rc == -EAGAIN)
4341 goto QFSAttributeRetry;
4342
4343 return rc;
4344}
4345
4346int
Steve French737b7582005-04-28 22:41:06 -07004347CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348{
4349/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4350 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4351 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4352 FILE_SYSTEM_DEVICE_INFO *response_data;
4353 int rc = 0;
4354 int bytes_returned = 0;
4355 __u16 params, byte_count;
4356
4357 cFYI(1, ("In QFSDeviceInfo"));
4358QFSDeviceRetry:
4359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360 (void **) &pSMBr);
4361 if (rc)
4362 return rc;
4363
4364 params = 2; /* level */
4365 pSMB->TotalDataCount = 0;
4366 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004367 /* BB find exact max SMB PDU from sess structure BB */
4368 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 pSMB->MaxSetupCount = 0;
4370 pSMB->Reserved = 0;
4371 pSMB->Flags = 0;
4372 pSMB->Timeout = 0;
4373 pSMB->Reserved2 = 0;
4374 byte_count = params + 1 /* pad */ ;
4375 pSMB->TotalParameterCount = cpu_to_le16(params);
4376 pSMB->ParameterCount = pSMB->TotalParameterCount;
4377 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004378 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
4380 pSMB->DataCount = 0;
4381 pSMB->DataOffset = 0;
4382 pSMB->SetupCount = 1;
4383 pSMB->Reserved3 = 0;
4384 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4385 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4386 pSMB->hdr.smb_buf_length += byte_count;
4387 pSMB->ByteCount = cpu_to_le16(byte_count);
4388
4389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4391 if (rc) {
4392 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4393 } else { /* decode response */
4394 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4395
Steve French630f3f02007-10-25 21:17:17 +00004396 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 rc = -EIO; /* bad smb */
4398 else {
4399 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4400 response_data =
Steve French737b7582005-04-28 22:41:06 -07004401 (FILE_SYSTEM_DEVICE_INFO *)
4402 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 data_offset);
4404 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004405 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 }
4407 }
4408 cifs_buf_release(pSMB);
4409
4410 if (rc == -EAGAIN)
4411 goto QFSDeviceRetry;
4412
4413 return rc;
4414}
4415
4416int
Steve French737b7582005-04-28 22:41:06 -07004417CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418{
4419/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4420 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4421 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4422 FILE_SYSTEM_UNIX_INFO *response_data;
4423 int rc = 0;
4424 int bytes_returned = 0;
4425 __u16 params, byte_count;
4426
4427 cFYI(1, ("In QFSUnixInfo"));
4428QFSUnixRetry:
4429 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4430 (void **) &pSMBr);
4431 if (rc)
4432 return rc;
4433
4434 params = 2; /* level */
4435 pSMB->TotalDataCount = 0;
4436 pSMB->DataCount = 0;
4437 pSMB->DataOffset = 0;
4438 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004439 /* BB find exact max SMB PDU from sess structure BB */
4440 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 pSMB->MaxSetupCount = 0;
4442 pSMB->Reserved = 0;
4443 pSMB->Flags = 0;
4444 pSMB->Timeout = 0;
4445 pSMB->Reserved2 = 0;
4446 byte_count = params + 1 /* pad */ ;
4447 pSMB->ParameterCount = cpu_to_le16(params);
4448 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004449 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4450 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 pSMB->SetupCount = 1;
4452 pSMB->Reserved3 = 0;
4453 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4454 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4455 pSMB->hdr.smb_buf_length += byte_count;
4456 pSMB->ByteCount = cpu_to_le16(byte_count);
4457
4458 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4460 if (rc) {
4461 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4462 } else { /* decode response */
4463 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4464
4465 if (rc || (pSMBr->ByteCount < 13)) {
4466 rc = -EIO; /* bad smb */
4467 } else {
4468 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4469 response_data =
4470 (FILE_SYSTEM_UNIX_INFO
4471 *) (((char *) &pSMBr->hdr.Protocol) +
4472 data_offset);
4473 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004474 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 }
4476 }
4477 cifs_buf_release(pSMB);
4478
4479 if (rc == -EAGAIN)
4480 goto QFSUnixRetry;
4481
4482
4483 return rc;
4484}
4485
Jeremy Allisonac670552005-06-22 17:26:35 -07004486int
Steve French45abc6e2005-06-23 13:42:03 -05004487CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004488{
4489/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4490 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4491 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4492 int rc = 0;
4493 int bytes_returned = 0;
4494 __u16 params, param_offset, offset, byte_count;
4495
4496 cFYI(1, ("In SETFSUnixInfo"));
4497SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004498 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004499 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4500 (void **) &pSMBr);
4501 if (rc)
4502 return rc;
4503
4504 params = 4; /* 2 bytes zero followed by info level. */
4505 pSMB->MaxSetupCount = 0;
4506 pSMB->Reserved = 0;
4507 pSMB->Flags = 0;
4508 pSMB->Timeout = 0;
4509 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004510 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4511 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004512 offset = param_offset + params;
4513
4514 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004515 /* BB find exact max SMB PDU from sess structure BB */
4516 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004517 pSMB->SetupCount = 1;
4518 pSMB->Reserved3 = 0;
4519 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4520 byte_count = 1 /* pad */ + params + 12;
4521
4522 pSMB->DataCount = cpu_to_le16(12);
4523 pSMB->ParameterCount = cpu_to_le16(params);
4524 pSMB->TotalDataCount = pSMB->DataCount;
4525 pSMB->TotalParameterCount = pSMB->ParameterCount;
4526 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4527 pSMB->DataOffset = cpu_to_le16(offset);
4528
4529 /* Params. */
4530 pSMB->FileNum = 0;
4531 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4532
4533 /* Data. */
4534 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4535 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4536 pSMB->ClientUnixCap = cpu_to_le64(cap);
4537
4538 pSMB->hdr.smb_buf_length += byte_count;
4539 pSMB->ByteCount = cpu_to_le16(byte_count);
4540
4541 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4542 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4543 if (rc) {
4544 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4545 } else { /* decode response */
4546 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004547 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004548 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004549 }
4550 cifs_buf_release(pSMB);
4551
4552 if (rc == -EAGAIN)
4553 goto SETFSUnixRetry;
4554
4555 return rc;
4556}
4557
4558
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559
4560int
4561CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004562 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563{
4564/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4565 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4566 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4567 FILE_SYSTEM_POSIX_INFO *response_data;
4568 int rc = 0;
4569 int bytes_returned = 0;
4570 __u16 params, byte_count;
4571
4572 cFYI(1, ("In QFSPosixInfo"));
4573QFSPosixRetry:
4574 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4575 (void **) &pSMBr);
4576 if (rc)
4577 return rc;
4578
4579 params = 2; /* level */
4580 pSMB->TotalDataCount = 0;
4581 pSMB->DataCount = 0;
4582 pSMB->DataOffset = 0;
4583 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004584 /* BB find exact max SMB PDU from sess structure BB */
4585 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 pSMB->MaxSetupCount = 0;
4587 pSMB->Reserved = 0;
4588 pSMB->Flags = 0;
4589 pSMB->Timeout = 0;
4590 pSMB->Reserved2 = 0;
4591 byte_count = params + 1 /* pad */ ;
4592 pSMB->ParameterCount = cpu_to_le16(params);
4593 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004594 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4595 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 pSMB->SetupCount = 1;
4597 pSMB->Reserved3 = 0;
4598 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4599 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4600 pSMB->hdr.smb_buf_length += byte_count;
4601 pSMB->ByteCount = cpu_to_le16(byte_count);
4602
4603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4605 if (rc) {
4606 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4607 } else { /* decode response */
4608 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4609
4610 if (rc || (pSMBr->ByteCount < 13)) {
4611 rc = -EIO; /* bad smb */
4612 } else {
4613 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4614 response_data =
4615 (FILE_SYSTEM_POSIX_INFO
4616 *) (((char *) &pSMBr->hdr.Protocol) +
4617 data_offset);
4618 FSData->f_bsize =
4619 le32_to_cpu(response_data->BlockSize);
4620 FSData->f_blocks =
4621 le64_to_cpu(response_data->TotalBlocks);
4622 FSData->f_bfree =
4623 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004624 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 FSData->f_bavail = FSData->f_bfree;
4626 } else {
4627 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004628 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 }
Steve French790fe572007-07-07 19:25:05 +00004630 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004632 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004633 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004635 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 }
4637 }
4638 cifs_buf_release(pSMB);
4639
4640 if (rc == -EAGAIN)
4641 goto QFSPosixRetry;
4642
4643 return rc;
4644}
4645
4646
Steve French50c2f752007-07-13 00:33:32 +00004647/* We can not use write of zero bytes trick to
4648 set file size due to need for large file support. Also note that
4649 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 routine which is only needed to work around a sharing violation bug
4651 in Samba which this routine can run into */
4652
4653int
4654CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004655 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004656 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657{
4658 struct smb_com_transaction2_spi_req *pSMB = NULL;
4659 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4660 struct file_end_of_file_info *parm_data;
4661 int name_len;
4662 int rc = 0;
4663 int bytes_returned = 0;
4664 __u16 params, byte_count, data_count, param_offset, offset;
4665
4666 cFYI(1, ("In SetEOF"));
4667SetEOFRetry:
4668 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4669 (void **) &pSMBr);
4670 if (rc)
4671 return rc;
4672
4673 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4674 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004675 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004676 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 name_len++; /* trailing null */
4678 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004679 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 name_len = strnlen(fileName, PATH_MAX);
4681 name_len++; /* trailing null */
4682 strncpy(pSMB->FileName, fileName, name_len);
4683 }
4684 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004685 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004687 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 pSMB->MaxSetupCount = 0;
4689 pSMB->Reserved = 0;
4690 pSMB->Flags = 0;
4691 pSMB->Timeout = 0;
4692 pSMB->Reserved2 = 0;
4693 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004694 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004696 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004697 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4698 pSMB->InformationLevel =
4699 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4700 else
4701 pSMB->InformationLevel =
4702 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4703 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4705 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004706 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 else
4708 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004709 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 }
4711
4712 parm_data =
4713 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4714 offset);
4715 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4716 pSMB->DataOffset = cpu_to_le16(offset);
4717 pSMB->SetupCount = 1;
4718 pSMB->Reserved3 = 0;
4719 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4720 byte_count = 3 /* pad */ + params + data_count;
4721 pSMB->DataCount = cpu_to_le16(data_count);
4722 pSMB->TotalDataCount = pSMB->DataCount;
4723 pSMB->ParameterCount = cpu_to_le16(params);
4724 pSMB->TotalParameterCount = pSMB->ParameterCount;
4725 pSMB->Reserved4 = 0;
4726 pSMB->hdr.smb_buf_length += byte_count;
4727 parm_data->FileSize = cpu_to_le64(size);
4728 pSMB->ByteCount = cpu_to_le16(byte_count);
4729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004731 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733
4734 cifs_buf_release(pSMB);
4735
4736 if (rc == -EAGAIN)
4737 goto SetEOFRetry;
4738
4739 return rc;
4740}
4741
4742int
Steve French50c2f752007-07-13 00:33:32 +00004743CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004744 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745{
4746 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 char *data_offset;
4748 struct file_end_of_file_info *parm_data;
4749 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 __u16 params, param_offset, offset, byte_count, count;
4751
4752 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4753 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004754 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4755
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 if (rc)
4757 return rc;
4758
4759 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4760 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004761
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 params = 6;
4763 pSMB->MaxSetupCount = 0;
4764 pSMB->Reserved = 0;
4765 pSMB->Flags = 0;
4766 pSMB->Timeout = 0;
4767 pSMB->Reserved2 = 0;
4768 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4769 offset = param_offset + params;
4770
Steve French50c2f752007-07-13 00:33:32 +00004771 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
4773 count = sizeof(struct file_end_of_file_info);
4774 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004775 /* BB find exact max SMB PDU from sess structure BB */
4776 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 pSMB->SetupCount = 1;
4778 pSMB->Reserved3 = 0;
4779 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4780 byte_count = 3 /* pad */ + params + count;
4781 pSMB->DataCount = cpu_to_le16(count);
4782 pSMB->ParameterCount = cpu_to_le16(params);
4783 pSMB->TotalDataCount = pSMB->DataCount;
4784 pSMB->TotalParameterCount = pSMB->ParameterCount;
4785 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4786 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004787 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4788 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 pSMB->DataOffset = cpu_to_le16(offset);
4790 parm_data->FileSize = cpu_to_le64(size);
4791 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004792 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4794 pSMB->InformationLevel =
4795 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4796 else
4797 pSMB->InformationLevel =
4798 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004799 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4801 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004802 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 else
4804 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004805 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 }
4807 pSMB->Reserved4 = 0;
4808 pSMB->hdr.smb_buf_length += byte_count;
4809 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004810 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 if (rc) {
4812 cFYI(1,
4813 ("Send error in SetFileInfo (SetFileSize) = %d",
4814 rc));
4815 }
4816
Steve French50c2f752007-07-13 00:33:32 +00004817 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 since file handle passed in no longer valid */
4819
4820 return rc;
4821}
4822
Steve French50c2f752007-07-13 00:33:32 +00004823/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 an open handle, rather than by pathname - this is awkward due to
4825 potential access conflicts on the open, but it is unavoidable for these
4826 old servers since the only other choice is to go from 100 nanosecond DCE
4827 time and resort to the original setpathinfo level which takes the ancient
4828 DOS time format with 2 second granularity */
4829int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004830CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4831 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832{
4833 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 char *data_offset;
4835 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836 __u16 params, param_offset, offset, byte_count, count;
4837
4838 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004839 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4840
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 if (rc)
4842 return rc;
4843
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004844 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4845 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004846
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 params = 6;
4848 pSMB->MaxSetupCount = 0;
4849 pSMB->Reserved = 0;
4850 pSMB->Flags = 0;
4851 pSMB->Timeout = 0;
4852 pSMB->Reserved2 = 0;
4853 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4854 offset = param_offset + params;
4855
Steve French50c2f752007-07-13 00:33:32 +00004856 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857
Steve French26f57362007-08-30 22:09:15 +00004858 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004860 /* BB find max SMB PDU from sess */
4861 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 pSMB->SetupCount = 1;
4863 pSMB->Reserved3 = 0;
4864 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4865 byte_count = 3 /* pad */ + params + count;
4866 pSMB->DataCount = cpu_to_le16(count);
4867 pSMB->ParameterCount = cpu_to_le16(params);
4868 pSMB->TotalDataCount = pSMB->DataCount;
4869 pSMB->TotalParameterCount = pSMB->ParameterCount;
4870 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4871 pSMB->DataOffset = cpu_to_le16(offset);
4872 pSMB->Fid = fid;
4873 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4874 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4875 else
4876 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4877 pSMB->Reserved4 = 0;
4878 pSMB->hdr.smb_buf_length += byte_count;
4879 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004880 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004881 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004882 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004883 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884
Steve French50c2f752007-07-13 00:33:32 +00004885 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 since file handle passed in no longer valid */
4887
4888 return rc;
4889}
4890
Jeff Layton6d22f092008-09-23 11:48:35 -04004891int
4892CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4893 bool delete_file, __u16 fid, __u32 pid_of_opener)
4894{
4895 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4896 char *data_offset;
4897 int rc = 0;
4898 __u16 params, param_offset, offset, byte_count, count;
4899
4900 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4901 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4902
4903 if (rc)
4904 return rc;
4905
4906 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4907 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4908
4909 params = 6;
4910 pSMB->MaxSetupCount = 0;
4911 pSMB->Reserved = 0;
4912 pSMB->Flags = 0;
4913 pSMB->Timeout = 0;
4914 pSMB->Reserved2 = 0;
4915 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4916 offset = param_offset + params;
4917
4918 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4919
4920 count = 1;
4921 pSMB->MaxParameterCount = cpu_to_le16(2);
4922 /* BB find max SMB PDU from sess */
4923 pSMB->MaxDataCount = cpu_to_le16(1000);
4924 pSMB->SetupCount = 1;
4925 pSMB->Reserved3 = 0;
4926 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4927 byte_count = 3 /* pad */ + params + count;
4928 pSMB->DataCount = cpu_to_le16(count);
4929 pSMB->ParameterCount = cpu_to_le16(params);
4930 pSMB->TotalDataCount = pSMB->DataCount;
4931 pSMB->TotalParameterCount = pSMB->ParameterCount;
4932 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4933 pSMB->DataOffset = cpu_to_le16(offset);
4934 pSMB->Fid = fid;
4935 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4936 pSMB->Reserved4 = 0;
4937 pSMB->hdr.smb_buf_length += byte_count;
4938 pSMB->ByteCount = cpu_to_le16(byte_count);
4939 *data_offset = delete_file ? 1 : 0;
4940 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4941 if (rc)
4942 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4943
4944 return rc;
4945}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946
4947int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004948CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4949 const char *fileName, const FILE_BASIC_INFO *data,
4950 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951{
4952 TRANSACTION2_SPI_REQ *pSMB = NULL;
4953 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4954 int name_len;
4955 int rc = 0;
4956 int bytes_returned = 0;
4957 char *data_offset;
4958 __u16 params, param_offset, offset, byte_count, count;
4959
4960 cFYI(1, ("In SetTimes"));
4961
4962SetTimesRetry:
4963 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4964 (void **) &pSMBr);
4965 if (rc)
4966 return rc;
4967
4968 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4969 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004970 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004971 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004972 name_len++; /* trailing null */
4973 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004974 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 name_len = strnlen(fileName, PATH_MAX);
4976 name_len++; /* trailing null */
4977 strncpy(pSMB->FileName, fileName, name_len);
4978 }
4979
4980 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004981 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004982 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004983 /* BB find max SMB PDU from sess structure BB */
4984 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 pSMB->MaxSetupCount = 0;
4986 pSMB->Reserved = 0;
4987 pSMB->Flags = 0;
4988 pSMB->Timeout = 0;
4989 pSMB->Reserved2 = 0;
4990 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004991 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 offset = param_offset + params;
4993 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4994 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4995 pSMB->DataOffset = cpu_to_le16(offset);
4996 pSMB->SetupCount = 1;
4997 pSMB->Reserved3 = 0;
4998 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4999 byte_count = 3 /* pad */ + params + count;
5000
5001 pSMB->DataCount = cpu_to_le16(count);
5002 pSMB->ParameterCount = cpu_to_le16(params);
5003 pSMB->TotalDataCount = pSMB->DataCount;
5004 pSMB->TotalParameterCount = pSMB->ParameterCount;
5005 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5006 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5007 else
5008 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5009 pSMB->Reserved4 = 0;
5010 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005011 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012 pSMB->ByteCount = cpu_to_le16(byte_count);
5013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005015 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017
5018 cifs_buf_release(pSMB);
5019
5020 if (rc == -EAGAIN)
5021 goto SetTimesRetry;
5022
5023 return rc;
5024}
5025
5026/* Can not be used to set time stamps yet (due to old DOS time format) */
5027/* Can be used to set attributes */
5028#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5029 handling it anyway and NT4 was what we thought it would be needed for
5030 Do not delete it until we prove whether needed for Win9x though */
5031int
5032CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5033 __u16 dos_attrs, const struct nls_table *nls_codepage)
5034{
5035 SETATTR_REQ *pSMB = NULL;
5036 SETATTR_RSP *pSMBr = NULL;
5037 int rc = 0;
5038 int bytes_returned;
5039 int name_len;
5040
5041 cFYI(1, ("In SetAttrLegacy"));
5042
5043SetAttrLgcyRetry:
5044 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5045 (void **) &pSMBr);
5046 if (rc)
5047 return rc;
5048
5049 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5050 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005051 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 PATH_MAX, nls_codepage);
5053 name_len++; /* trailing null */
5054 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005055 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 name_len = strnlen(fileName, PATH_MAX);
5057 name_len++; /* trailing null */
5058 strncpy(pSMB->fileName, fileName, name_len);
5059 }
5060 pSMB->attr = cpu_to_le16(dos_attrs);
5061 pSMB->BufferFormat = 0x04;
5062 pSMB->hdr.smb_buf_length += name_len + 1;
5063 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005066 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068
5069 cifs_buf_release(pSMB);
5070
5071 if (rc == -EAGAIN)
5072 goto SetAttrLgcyRetry;
5073
5074 return rc;
5075}
5076#endif /* temporarily unneeded SetAttr legacy function */
5077
5078int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005079CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005080 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005081 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005082{
5083 TRANSACTION2_SPI_REQ *pSMB = NULL;
5084 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5085 int name_len;
5086 int rc = 0;
5087 int bytes_returned = 0;
5088 FILE_UNIX_BASIC_INFO *data_offset;
5089 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005090 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091
5092 cFYI(1, ("In SetUID/GID/Mode"));
5093setPermsRetry:
5094 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5095 (void **) &pSMBr);
5096 if (rc)
5097 return rc;
5098
5099 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5100 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005101 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005102 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 name_len++; /* trailing null */
5104 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005105 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 name_len = strnlen(fileName, PATH_MAX);
5107 name_len++; /* trailing null */
5108 strncpy(pSMB->FileName, fileName, name_len);
5109 }
5110
5111 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005112 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005114 /* BB find max SMB PDU from sess structure BB */
5115 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 pSMB->MaxSetupCount = 0;
5117 pSMB->Reserved = 0;
5118 pSMB->Flags = 0;
5119 pSMB->Timeout = 0;
5120 pSMB->Reserved2 = 0;
5121 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005122 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 offset = param_offset + params;
5124 data_offset =
5125 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5126 offset);
5127 memset(data_offset, 0, count);
5128 pSMB->DataOffset = cpu_to_le16(offset);
5129 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5130 pSMB->SetupCount = 1;
5131 pSMB->Reserved3 = 0;
5132 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5133 byte_count = 3 /* pad */ + params + count;
5134 pSMB->ParameterCount = cpu_to_le16(params);
5135 pSMB->DataCount = cpu_to_le16(count);
5136 pSMB->TotalParameterCount = pSMB->ParameterCount;
5137 pSMB->TotalDataCount = pSMB->DataCount;
5138 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5139 pSMB->Reserved4 = 0;
5140 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005141 /* Samba server ignores set of file size to zero due to bugs in some
5142 older clients, but we should be precise - we use SetFileSize to
5143 set file size and do not want to truncate file size to zero
5144 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005145 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005146 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5147 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5148 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5149 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5150 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5151 data_offset->Uid = cpu_to_le64(args->uid);
5152 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005154 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5155 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005157
Steve French790fe572007-07-07 19:25:05 +00005158 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005160 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005162 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005163 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005164 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005166 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005168 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005170 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5172
5173
5174 pSMB->ByteCount = cpu_to_le16(byte_count);
5175 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5176 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005177 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179
Steve French0d817bc2008-05-22 02:02:03 +00005180 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 if (rc == -EAGAIN)
5182 goto setPermsRetry;
5183 return rc;
5184}
5185
Steve French50c2f752007-07-13 00:33:32 +00005186int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005187 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005188 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005189 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190{
5191 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005192 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5193 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005194 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 int bytes_returned;
5196
Steve French50c2f752007-07-13 00:33:32 +00005197 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005199 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005200 if (rc)
5201 return rc;
5202
5203 pSMB->TotalParameterCount = 0 ;
5204 pSMB->TotalDataCount = 0;
5205 pSMB->MaxParameterCount = cpu_to_le32(2);
5206 /* BB find exact data count max from sess structure BB */
5207 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005208/* BB VERIFY verify which is correct for above BB */
5209 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5210 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5211
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 pSMB->MaxSetupCount = 4;
5213 pSMB->Reserved = 0;
5214 pSMB->ParameterOffset = 0;
5215 pSMB->DataCount = 0;
5216 pSMB->DataOffset = 0;
5217 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5218 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5219 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005220 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5222 pSMB->Reserved2 = 0;
5223 pSMB->CompletionFilter = cpu_to_le32(filter);
5224 pSMB->Fid = netfid; /* file handle always le */
5225 pSMB->ByteCount = 0;
5226
5227 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005228 (struct smb_hdr *)pSMBr, &bytes_returned,
5229 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 if (rc) {
5231 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005232 } else {
5233 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005234 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005235 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005236 sizeof(struct dir_notify_req),
5237 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005238 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005239 dnotify_req->Pid = pSMB->hdr.Pid;
5240 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5241 dnotify_req->Mid = pSMB->hdr.Mid;
5242 dnotify_req->Tid = pSMB->hdr.Tid;
5243 dnotify_req->Uid = pSMB->hdr.Uid;
5244 dnotify_req->netfid = netfid;
5245 dnotify_req->pfile = pfile;
5246 dnotify_req->filter = filter;
5247 dnotify_req->multishot = multishot;
5248 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005249 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005250 &GlobalDnotifyReqList);
5251 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005252 } else
Steve French47c786e2005-10-11 20:03:18 -07005253 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 }
5255 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005256 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257}
5258#ifdef CONFIG_CIFS_XATTR
5259ssize_t
5260CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5261 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005262 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005263 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264{
5265 /* BB assumes one setup word */
5266 TRANSACTION2_QPI_REQ *pSMB = NULL;
5267 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5268 int rc = 0;
5269 int bytes_returned;
5270 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005271 struct fea *temp_fea;
5272 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 __u16 params, byte_count;
5274
5275 cFYI(1, ("In Query All EAs path %s", searchName));
5276QAllEAsRetry:
5277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5278 (void **) &pSMBr);
5279 if (rc)
5280 return rc;
5281
5282 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5283 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005284 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005285 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 name_len++; /* trailing null */
5287 name_len *= 2;
5288 } else { /* BB improve the check for buffer overruns BB */
5289 name_len = strnlen(searchName, PATH_MAX);
5290 name_len++; /* trailing null */
5291 strncpy(pSMB->FileName, searchName, name_len);
5292 }
5293
Steve French50c2f752007-07-13 00:33:32 +00005294 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 pSMB->TotalDataCount = 0;
5296 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005297 /* BB find exact max SMB PDU from sess structure BB */
5298 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 pSMB->MaxSetupCount = 0;
5300 pSMB->Reserved = 0;
5301 pSMB->Flags = 0;
5302 pSMB->Timeout = 0;
5303 pSMB->Reserved2 = 0;
5304 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005305 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306 pSMB->DataCount = 0;
5307 pSMB->DataOffset = 0;
5308 pSMB->SetupCount = 1;
5309 pSMB->Reserved3 = 0;
5310 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5311 byte_count = params + 1 /* pad */ ;
5312 pSMB->TotalParameterCount = cpu_to_le16(params);
5313 pSMB->ParameterCount = pSMB->TotalParameterCount;
5314 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5315 pSMB->Reserved4 = 0;
5316 pSMB->hdr.smb_buf_length += byte_count;
5317 pSMB->ByteCount = cpu_to_le16(byte_count);
5318
5319 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5320 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5321 if (rc) {
5322 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5323 } else { /* decode response */
5324 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5325
5326 /* BB also check enough total bytes returned */
5327 /* BB we need to improve the validity checking
5328 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005329 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 rc = -EIO; /* bad smb */
5331 /* else if (pFindData){
5332 memcpy((char *) pFindData,
5333 (char *) &pSMBr->hdr.Protocol +
5334 data_offset, kl);
5335 }*/ else {
5336 /* check that length of list is not more than bcc */
5337 /* check that each entry does not go beyond length
5338 of list */
5339 /* check that each element of each entry does not
5340 go beyond end of list */
5341 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005342 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 rc = 0;
5344 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005345 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 ea_response_data = (struct fealist *)
5347 (((char *) &pSMBr->hdr.Protocol) +
5348 data_offset);
5349 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005350 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005351 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005353 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 } else {
5355 /* account for ea list len */
5356 name_len -= 4;
5357 temp_fea = ea_response_data->list;
5358 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005359 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 __u16 value_len;
5361 name_len -= 4;
5362 temp_ptr += 4;
5363 rc += temp_fea->name_len;
5364 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005365 rc = rc + 5 + 1;
5366 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005367 memcpy(EAData, "user.", 5);
5368 EAData += 5;
5369 memcpy(EAData, temp_ptr,
5370 temp_fea->name_len);
5371 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 /* null terminate name */
5373 *EAData = 0;
5374 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005375 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 /* skip copy - calc size only */
5377 } else {
5378 /* stop before overrun buffer */
5379 rc = -ERANGE;
5380 break;
5381 }
5382 name_len -= temp_fea->name_len;
5383 temp_ptr += temp_fea->name_len;
5384 /* account for trailing null */
5385 name_len--;
5386 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005387 value_len =
5388 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 name_len -= value_len;
5390 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005391 /* BB check that temp_ptr is still
5392 within the SMB BB*/
5393
5394 /* no trailing null to account for
5395 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396 /* go on to next EA */
5397 temp_fea = (struct fea *)temp_ptr;
5398 }
5399 }
5400 }
5401 }
Steve French0d817bc2008-05-22 02:02:03 +00005402 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 if (rc == -EAGAIN)
5404 goto QAllEAsRetry;
5405
5406 return (ssize_t)rc;
5407}
5408
Steve French50c2f752007-07-13 00:33:32 +00005409ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5410 const unsigned char *searchName, const unsigned char *ea_name,
5411 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005412 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413{
5414 TRANSACTION2_QPI_REQ *pSMB = NULL;
5415 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5416 int rc = 0;
5417 int bytes_returned;
5418 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005419 struct fea *temp_fea;
5420 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 __u16 params, byte_count;
5422
5423 cFYI(1, ("In Query EA path %s", searchName));
5424QEARetry:
5425 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5426 (void **) &pSMBr);
5427 if (rc)
5428 return rc;
5429
5430 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5431 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005432 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005433 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 name_len++; /* trailing null */
5435 name_len *= 2;
5436 } else { /* BB improve the check for buffer overruns BB */
5437 name_len = strnlen(searchName, PATH_MAX);
5438 name_len++; /* trailing null */
5439 strncpy(pSMB->FileName, searchName, name_len);
5440 }
5441
Steve French50c2f752007-07-13 00:33:32 +00005442 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 pSMB->TotalDataCount = 0;
5444 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005445 /* BB find exact max SMB PDU from sess structure BB */
5446 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 pSMB->MaxSetupCount = 0;
5448 pSMB->Reserved = 0;
5449 pSMB->Flags = 0;
5450 pSMB->Timeout = 0;
5451 pSMB->Reserved2 = 0;
5452 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005453 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 pSMB->DataCount = 0;
5455 pSMB->DataOffset = 0;
5456 pSMB->SetupCount = 1;
5457 pSMB->Reserved3 = 0;
5458 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5459 byte_count = params + 1 /* pad */ ;
5460 pSMB->TotalParameterCount = cpu_to_le16(params);
5461 pSMB->ParameterCount = pSMB->TotalParameterCount;
5462 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5463 pSMB->Reserved4 = 0;
5464 pSMB->hdr.smb_buf_length += byte_count;
5465 pSMB->ByteCount = cpu_to_le16(byte_count);
5466
5467 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5468 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5469 if (rc) {
5470 cFYI(1, ("Send error in Query EA = %d", rc));
5471 } else { /* decode response */
5472 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5473
5474 /* BB also check enough total bytes returned */
5475 /* BB we need to improve the validity checking
5476 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005477 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 rc = -EIO; /* bad smb */
5479 /* else if (pFindData){
5480 memcpy((char *) pFindData,
5481 (char *) &pSMBr->hdr.Protocol +
5482 data_offset, kl);
5483 }*/ else {
5484 /* check that length of list is not more than bcc */
5485 /* check that each entry does not go beyond length
5486 of list */
5487 /* check that each element of each entry does not
5488 go beyond end of list */
5489 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005490 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 rc = -ENODATA;
5492 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005493 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 ea_response_data = (struct fealist *)
5495 (((char *) &pSMBr->hdr.Protocol) +
5496 data_offset);
5497 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005498 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005499 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005501 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502 } else {
5503 /* account for ea list len */
5504 name_len -= 4;
5505 temp_fea = ea_response_data->list;
5506 temp_ptr = (char *)temp_fea;
5507 /* loop through checking if we have a matching
5508 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005509 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510 __u16 value_len;
5511 name_len -= 4;
5512 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005513 value_len =
5514 le16_to_cpu(temp_fea->value_len);
5515 /* BB validate that value_len falls within SMB,
5516 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005517 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 temp_fea->name_len) == 0) {
5519 /* found a match */
5520 rc = value_len;
5521 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005522 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 memcpy(ea_value,
5524 temp_fea->name+temp_fea->name_len+1,
5525 rc);
Steve French50c2f752007-07-13 00:33:32 +00005526 /* ea values, unlike ea
5527 names, are not null
5528 terminated */
Steve French790fe572007-07-07 19:25:05 +00005529 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 /* skip copy - calc size only */
5531 } else {
Steve French50c2f752007-07-13 00:33:32 +00005532 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 rc = -ERANGE;
5534 }
5535 break;
5536 }
5537 name_len -= temp_fea->name_len;
5538 temp_ptr += temp_fea->name_len;
5539 /* account for trailing null */
5540 name_len--;
5541 temp_ptr++;
5542 name_len -= value_len;
5543 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005544 /* No trailing null to account for in
5545 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 temp_fea = (struct fea *)temp_ptr;
5547 }
Steve French50c2f752007-07-13 00:33:32 +00005548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 }
5550 }
Steve French0d817bc2008-05-22 02:02:03 +00005551 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 if (rc == -EAGAIN)
5553 goto QEARetry;
5554
5555 return (ssize_t)rc;
5556}
5557
5558int
5559CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005560 const char *ea_name, const void *ea_value,
5561 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5562 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563{
5564 struct smb_com_transaction2_spi_req *pSMB = NULL;
5565 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5566 struct fealist *parm_data;
5567 int name_len;
5568 int rc = 0;
5569 int bytes_returned = 0;
5570 __u16 params, param_offset, byte_count, offset, count;
5571
5572 cFYI(1, ("In SetEA"));
5573SetEARetry:
5574 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5575 (void **) &pSMBr);
5576 if (rc)
5577 return rc;
5578
5579 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5580 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005581 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005582 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005583 name_len++; /* trailing null */
5584 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005585 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 name_len = strnlen(fileName, PATH_MAX);
5587 name_len++; /* trailing null */
5588 strncpy(pSMB->FileName, fileName, name_len);
5589 }
5590
5591 params = 6 + name_len;
5592
5593 /* done calculating parms using name_len of file name,
5594 now use name_len to calculate length of ea name
5595 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005596 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 name_len = 0;
5598 else
Steve French50c2f752007-07-13 00:33:32 +00005599 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005601 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005603 /* BB find max SMB PDU from sess */
5604 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 pSMB->MaxSetupCount = 0;
5606 pSMB->Reserved = 0;
5607 pSMB->Flags = 0;
5608 pSMB->Timeout = 0;
5609 pSMB->Reserved2 = 0;
5610 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005611 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 offset = param_offset + params;
5613 pSMB->InformationLevel =
5614 cpu_to_le16(SMB_SET_FILE_EA);
5615
5616 parm_data =
5617 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5618 offset);
5619 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5620 pSMB->DataOffset = cpu_to_le16(offset);
5621 pSMB->SetupCount = 1;
5622 pSMB->Reserved3 = 0;
5623 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5624 byte_count = 3 /* pad */ + params + count;
5625 pSMB->DataCount = cpu_to_le16(count);
5626 parm_data->list_len = cpu_to_le32(count);
5627 parm_data->list[0].EA_flags = 0;
5628 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005629 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005630 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005631 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005632 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 parm_data->list[0].name[name_len] = 0;
5634 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5635 /* caller ensures that ea_value_len is less than 64K but
5636 we need to ensure that it fits within the smb */
5637
Steve French50c2f752007-07-13 00:33:32 +00005638 /*BB add length check to see if it would fit in
5639 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005640 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5641 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005642 memcpy(parm_data->list[0].name+name_len+1,
5643 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644
5645 pSMB->TotalDataCount = pSMB->DataCount;
5646 pSMB->ParameterCount = cpu_to_le16(params);
5647 pSMB->TotalParameterCount = pSMB->ParameterCount;
5648 pSMB->Reserved4 = 0;
5649 pSMB->hdr.smb_buf_length += byte_count;
5650 pSMB->ByteCount = cpu_to_le16(byte_count);
5651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005653 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655
5656 cifs_buf_release(pSMB);
5657
5658 if (rc == -EAGAIN)
5659 goto SetEARetry;
5660
5661 return rc;
5662}
5663
5664#endif