blob: b968e5bd7df3fb00d77a133cb0dd1cba736c5632 [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 Frencha45443472005-08-24 13:59:35 -0700221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000223}
224
Steve French12b3b8f2006-02-09 21:12:47 +0000225int
Steve French50c2f752007-07-13 00:33:32 +0000226small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000227 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000228{
229 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000230 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000231
Steve French5815449d2006-02-14 01:36:20 +0000232 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000233 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000234 return rc;
235
Steve French04fdabe2006-02-10 05:52:50 +0000236 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000237 buffer->Mid = GetNextMid(ses->server);
238 if (ses->capabilities & CAP_UNICODE)
239 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000240 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000241 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
242
243 /* uid, tid can stay at zero as set in header assemble */
244
Steve French50c2f752007-07-13 00:33:32 +0000245 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000246 this function is used after 1st of session setup requests */
247
248 return rc;
249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251/* If the return code is zero, this function must fill in request_buf pointer */
252static int
253smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
254 void **request_buf /* returned */ ,
255 void **response_buf /* returned */ )
256{
257 int rc = 0;
258
259 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
260 check for tcp and smb session status done differently
261 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000262 if (tcon) {
Steve Frenchbfb598202008-11-18 16:33:48 +0000263 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800264 /* only tree disconnect, open, and write,
265 (and ulogoff which does not have tcon)
266 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000267 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800268 (smb_command != SMB_COM_OPEN_ANDX) &&
269 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000270 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800271 smb_command));
272 return -ENODEV;
273 }
274 }
275
Steve French790fe572007-07-07 19:25:05 +0000276 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000277 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700279 /* Give Demultiplex thread up to 10 seconds to
280 reconnect, should be greater than cifs socket
281 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000282 while (tcon->ses->server->tcpStatus ==
283 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000285 (tcon->ses->server->tcpStatus ==
286 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000287 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700288 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000290 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000292 cFYI(1, ("gave up waiting on "
293 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700295 } /* else "hard" mount - keep retrying
296 until process is killed or server
297 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 } else /* TCP session is reestablished now */
299 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 nls_codepage = load_nls_default();
302 /* need to prevent multiple threads trying to
303 simultaneously reconnect the same SMB session */
304 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000305 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000306 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700307 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000308 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700310 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
311 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000316 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000318 /* tell server Unix caps we support */
319 if (tcon->ses->capabilities & CAP_UNIX)
320 reset_cifs_unix_caps(
321 0 /* no xid */,
322 tcon,
323 NULL /* do not know sb */,
324 NULL /* no vol info */);
325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Removed call to reopen open files here.
329 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700330 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Steve French50c2f752007-07-13 00:33:32 +0000332 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700333 know whether we can continue or not without
334 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000335 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 case SMB_COM_READ_ANDX:
337 case SMB_COM_WRITE_ANDX:
338 case SMB_COM_CLOSE:
339 case SMB_COM_FIND_CLOSE2:
340 case SMB_COM_LOCKING_ANDX: {
341 unload_nls(nls_codepage);
342 return -EAGAIN;
343 }
344 }
345 } else {
346 up(&tcon->ses->sesSem);
347 }
348 unload_nls(nls_codepage);
349
350 } else {
351 return -EIO;
352 }
353 }
Steve French790fe572007-07-07 19:25:05 +0000354 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356
357 *request_buf = cifs_buf_get();
358 if (*request_buf == NULL) {
359 /* BB should we add a retry in here if not a writepage? */
360 return -ENOMEM;
361 }
362 /* Although the original thought was we needed the response buf for */
363 /* potential retries of smb operations it turns out we can determine */
364 /* from the mid flags when the request buffer can be resent without */
365 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000366 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000367 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000370 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Steve French790fe572007-07-07 19:25:05 +0000372 if (tcon != NULL)
373 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return rc;
376}
377
Steve French50c2f752007-07-13 00:33:32 +0000378static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 int rc = -EINVAL;
381 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000382 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 /* check for plausible wct, bcc and t2 data and parm sizes */
385 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000386 if (pSMB->hdr.WordCount >= 10) {
387 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
389 /* check that bcc is at least as big as parms + data */
390 /* check that bcc is less than negotiated smb buffer */
391 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000392 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000393 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000394 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000396 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700397 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000399 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000400 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
402 return 0;
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405 }
406 }
Steve French50c2f752007-07-13 00:33:32 +0000407 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 sizeof(struct smb_t2_rsp) + 16);
409 return rc;
410}
411int
412CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
413{
414 NEGOTIATE_REQ *pSMB;
415 NEGOTIATE_RSP *pSMBr;
416 int rc = 0;
417 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000418 int i;
Steve French50c2f752007-07-13 00:33:32 +0000419 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000421 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100422 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Steve French790fe572007-07-07 19:25:05 +0000424 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 server = ses->server;
426 else {
427 rc = -EIO;
428 return rc;
429 }
430 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
431 (void **) &pSMB, (void **) &pSMBr);
432 if (rc)
433 return rc;
Steve French750d1152006-06-27 06:28:30 +0000434
435 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000436 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000437 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000438 else /* if override flags set only sign/seal OR them with global auth */
439 secFlags = extended_security | ses->overrideSecFlg;
440
Steve French762e5ab2007-06-28 18:41:42 +0000441 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000442
Steve French1982c342005-08-17 12:38:22 -0700443 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000444 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000445
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000446 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000447 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000448 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
449 cFYI(1, ("Kerberos only mechanism, enable extended security"));
450 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
451 }
Steve French50c2f752007-07-13 00:33:32 +0000452
Steve French39798772006-05-31 22:40:51 +0000453 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000454 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000455 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
456 count += strlen(protocols[i].name) + 1;
457 /* null at end of source and target buffers anyway */
458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 pSMB->hdr.smb_buf_length += count;
460 pSMB->ByteCount = cpu_to_le16(count);
461
462 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000464 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000465 goto neg_err_exit;
466
Al Viro733f99a2006-10-14 16:48:26 +0100467 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000468 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000469 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000470 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000471 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000472 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000473 could not negotiate a common dialect */
474 rc = -EOPNOTSUPP;
475 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000476#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000477 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100478 && ((dialect == LANMAN_PROT)
479 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000480 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000481 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000482
Steve French790fe572007-07-07 19:25:05 +0000483 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000484 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000485 server->secType = LANMAN;
486 else {
487 cERROR(1, ("mount failed weak security disabled"
488 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000489 rc = -EOPNOTSUPP;
490 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000491 }
Steve French254e55e2006-06-04 05:53:15 +0000492 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
493 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
494 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000495 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000496 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000497 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
498 /* even though we do not use raw we might as well set this
499 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000500 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000501 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000502 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
503 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000504 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000505 server->capabilities = CAP_MPX_MODE;
506 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000507 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000508 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000509 /* OS/2 often does not set timezone therefore
510 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000511 * Could deviate slightly from the right zone.
512 * Smallest defined timezone difference is 15 minutes
513 * (i.e. Nepal). Rounding up/down is done to match
514 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000515 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000516 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000517 struct timespec ts, utc;
518 utc = CURRENT_TIME;
519 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
520 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000521 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
522 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000523 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000524 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000525 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000526 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000527 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000528 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000529 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000530 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000531 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000532 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000533 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000534 server->timeAdj = (int)tmp;
535 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000536 }
Steve French790fe572007-07-07 19:25:05 +0000537 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000538
Steve French39798772006-05-31 22:40:51 +0000539
Steve French254e55e2006-06-04 05:53:15 +0000540 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000541 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000542
Steve French50c2f752007-07-13 00:33:32 +0000543 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000544 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000545 memcpy(server->cryptKey, rsp->EncryptionKey,
546 CIFS_CRYPTO_KEY_SIZE);
547 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
548 rc = -EIO; /* need cryptkey unless plain text */
549 goto neg_err_exit;
550 }
Steve French39798772006-05-31 22:40:51 +0000551
Steve French790fe572007-07-07 19:25:05 +0000552 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000553 /* we will not end up setting signing flags - as no signing
554 was in LANMAN and server did not return the flags on */
555 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000556#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000557 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000558 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000559 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000560 rc = -EOPNOTSUPP;
561#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000562 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000563 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000564 /* unknown wct */
565 rc = -EOPNOTSUPP;
566 goto neg_err_exit;
567 }
568 /* else wct == 17 NTLM */
569 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000570 if ((server->secMode & SECMODE_USER) == 0)
571 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000572
Steve French790fe572007-07-07 19:25:05 +0000573 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000574#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000575 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000576#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000577 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000578 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000579
Steve French790fe572007-07-07 19:25:05 +0000580 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000581 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000582 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000583 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000584 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000585 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000586 else if (secFlags & CIFSSEC_MAY_KRB5)
587 server->secType = Kerberos;
588 else if (secFlags & CIFSSEC_MAY_LANMAN)
589 server->secType = LANMAN;
590/* #ifdef CONFIG_CIFS_EXPERIMENTAL
591 else if (secFlags & CIFSSEC_MAY_PLNTXT)
592 server->secType = ??
593#endif */
594 else {
595 rc = -EOPNOTSUPP;
596 cERROR(1, ("Invalid security type"));
597 goto neg_err_exit;
598 }
599 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000600
Steve French254e55e2006-06-04 05:53:15 +0000601 /* one byte, so no need to convert this or EncryptionKeyLen from
602 little endian */
603 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
604 /* probably no need to store and check maxvcs */
605 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000607 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000608 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000609 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
610 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000611 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
612 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000613 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
614 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
615 CIFS_CRYPTO_KEY_SIZE);
616 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
617 && (pSMBr->EncryptionKeyLength == 0)) {
618 /* decode security blob */
619 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
620 rc = -EIO; /* no crypt key only if plain text pwd */
621 goto neg_err_exit;
622 }
623
624 /* BB might be helpful to save off the domain of server here */
625
Steve French50c2f752007-07-13 00:33:32 +0000626 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000627 (server->capabilities & CAP_EXTENDED_SECURITY)) {
628 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000629 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000631 goto neg_err_exit;
632 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500633 read_lock(&cifs_tcp_ses_lock);
634 if (server->srv_count > 1) {
635 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000636 if (memcmp(server->server_GUID,
637 pSMBr->u.extended_response.
638 GUID, 16) != 0) {
639 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000640 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000641 pSMBr->u.extended_response.GUID,
642 16);
643 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500644 } else {
645 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000646 memcpy(server->server_GUID,
647 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500648 }
Jeff Laytone187e442007-10-16 17:10:44 +0000649
650 if (count == 16) {
651 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000652 } else {
653 rc = decode_negTokenInit(pSMBr->u.extended_response.
654 SecurityBlob,
655 count - 16,
656 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000657 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000658 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000659 else
Steve French254e55e2006-06-04 05:53:15 +0000660 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
Steve French254e55e2006-06-04 05:53:15 +0000662 } else
663 server->capabilities &= ~CAP_EXTENDED_SECURITY;
664
Steve French6344a422006-06-12 04:18:35 +0000665#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000666signing_check:
Steve French6344a422006-06-12 04:18:35 +0000667#endif
Steve French762e5ab2007-06-28 18:41:42 +0000668 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
669 /* MUST_SIGN already includes the MAY_SIGN FLAG
670 so if this is zero it means that signing is disabled */
671 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000672 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000673 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000674 "packet signing to be enabled in "
675 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000676 rc = -EOPNOTSUPP;
677 }
Steve French50c2f752007-07-13 00:33:32 +0000678 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000679 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000680 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
681 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000682 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000683 if ((server->secMode &
684 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
685 cERROR(1,
686 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000687 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000688 } else
689 server->secMode |= SECMODE_SIGN_REQUIRED;
690 } else {
691 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000692 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000693 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000694 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 }
Steve French50c2f752007-07-13 00:33:32 +0000696
697neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700698 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000699
Steve French790fe572007-07-07 19:25:05 +0000700 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return rc;
702}
703
704int
705CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
706{
707 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500711
712 /* BB: do we need to check this? These should never be NULL. */
713 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
714 return -EIO;
715
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500717 * No need to return error on this operation if tid invalidated and
718 * closed on server already e.g. due to tcp session crashing. Also,
719 * the tcon is no longer on the list, so no need to take lock before
720 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 */
Jeff Laytonf1987b42008-11-15 11:12:47 -0500722 if (tcon->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000723 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
Steve French50c2f752007-07-13 00:33:32 +0000725 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700726 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500727 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return rc;
Steve French133672e2007-11-13 22:41:37 +0000729
730 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700732 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
Steve French50c2f752007-07-13 00:33:32 +0000734 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500735 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (rc == -EAGAIN)
737 rc = 0;
738
739 return rc;
740}
741
742int
743CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
744{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 LOGOFF_ANDX_REQ *pSMB;
746 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500749
750 /*
751 * BB: do we need to check validity of ses and server? They should
752 * always be valid since we have an active reference. If not, that
753 * should probably be a BUG()
754 */
755 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 return -EIO;
757
Jeff Layton14fbf502008-11-14 13:53:46 -0500758 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000759 if (ses->need_reconnect)
760 goto session_already_dead; /* no need to send SMBlogoff if uid
761 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
763 if (rc) {
764 up(&ses->sesSem);
765 return rc;
766 }
767
Steve French3b795212008-11-13 19:45:32 +0000768 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700769
Steve French3b795212008-11-13 19:45:32 +0000770 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
772 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
774 pSMB->hdr.Uid = ses->Suid;
775
776 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000777 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000778session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700779 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000782 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 error */
784 if (rc == -EAGAIN)
785 rc = 0;
786 return rc;
787}
788
789int
Steve French2d785a52007-07-15 01:48:57 +0000790CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
791 __u16 type, const struct nls_table *nls_codepage, int remap)
792{
793 TRANSACTION2_SPI_REQ *pSMB = NULL;
794 TRANSACTION2_SPI_RSP *pSMBr = NULL;
795 struct unlink_psx_rq *pRqD;
796 int name_len;
797 int rc = 0;
798 int bytes_returned = 0;
799 __u16 params, param_offset, offset, byte_count;
800
801 cFYI(1, ("In POSIX delete"));
802PsxDelete:
803 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
804 (void **) &pSMBr);
805 if (rc)
806 return rc;
807
808 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
809 name_len =
810 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
811 PATH_MAX, nls_codepage, remap);
812 name_len++; /* trailing null */
813 name_len *= 2;
814 } else { /* BB add path length overrun check */
815 name_len = strnlen(fileName, PATH_MAX);
816 name_len++; /* trailing null */
817 strncpy(pSMB->FileName, fileName, name_len);
818 }
819
820 params = 6 + name_len;
821 pSMB->MaxParameterCount = cpu_to_le16(2);
822 pSMB->MaxDataCount = 0; /* BB double check this with jra */
823 pSMB->MaxSetupCount = 0;
824 pSMB->Reserved = 0;
825 pSMB->Flags = 0;
826 pSMB->Timeout = 0;
827 pSMB->Reserved2 = 0;
828 param_offset = offsetof(struct smb_com_transaction2_spi_req,
829 InformationLevel) - 4;
830 offset = param_offset + params;
831
832 /* Setup pointer to Request Data (inode type) */
833 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
834 pRqD->type = cpu_to_le16(type);
835 pSMB->ParameterOffset = cpu_to_le16(param_offset);
836 pSMB->DataOffset = cpu_to_le16(offset);
837 pSMB->SetupCount = 1;
838 pSMB->Reserved3 = 0;
839 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
840 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
841
842 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
843 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
844 pSMB->ParameterCount = cpu_to_le16(params);
845 pSMB->TotalParameterCount = pSMB->ParameterCount;
846 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
847 pSMB->Reserved4 = 0;
848 pSMB->hdr.smb_buf_length += byte_count;
849 pSMB->ByteCount = cpu_to_le16(byte_count);
850 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000852 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000853 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000854 cifs_buf_release(pSMB);
855
856 cifs_stats_inc(&tcon->num_deletes);
857
858 if (rc == -EAGAIN)
859 goto PsxDelete;
860
861 return rc;
862}
863
864int
Steve French737b7582005-04-28 22:41:06 -0700865CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
866 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
868 DELETE_FILE_REQ *pSMB = NULL;
869 DELETE_FILE_RSP *pSMBr = NULL;
870 int rc = 0;
871 int bytes_returned;
872 int name_len;
873
874DelFileRetry:
875 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
876 (void **) &pSMBr);
877 if (rc)
878 return rc;
879
880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
881 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000882 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700883 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 name_len++; /* trailing null */
885 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700886 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 name_len = strnlen(fileName, PATH_MAX);
888 name_len++; /* trailing null */
889 strncpy(pSMB->fileName, fileName, name_len);
890 }
891 pSMB->SearchAttributes =
892 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
893 pSMB->BufferFormat = 0x04;
894 pSMB->hdr.smb_buf_length += name_len + 1;
895 pSMB->ByteCount = cpu_to_le16(name_len + 1);
896 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
897 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700898 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000899 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
902 cifs_buf_release(pSMB);
903 if (rc == -EAGAIN)
904 goto DelFileRetry;
905
906 return rc;
907}
908
909int
Steve French50c2f752007-07-13 00:33:32 +0000910CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700911 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
913 DELETE_DIRECTORY_REQ *pSMB = NULL;
914 DELETE_DIRECTORY_RSP *pSMBr = NULL;
915 int rc = 0;
916 int bytes_returned;
917 int name_len;
918
919 cFYI(1, ("In CIFSSMBRmDir"));
920RmDirRetry:
921 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
922 (void **) &pSMBr);
923 if (rc)
924 return rc;
925
926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700927 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
928 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 name_len++; /* trailing null */
930 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700931 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 name_len = strnlen(dirName, PATH_MAX);
933 name_len++; /* trailing null */
934 strncpy(pSMB->DirName, dirName, name_len);
935 }
936
937 pSMB->BufferFormat = 0x04;
938 pSMB->hdr.smb_buf_length += name_len + 1;
939 pSMB->ByteCount = cpu_to_le16(name_len + 1);
940 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
941 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700942 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000943 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 cifs_buf_release(pSMB);
947 if (rc == -EAGAIN)
948 goto RmDirRetry;
949 return rc;
950}
951
952int
953CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700954 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 int rc = 0;
957 CREATE_DIRECTORY_REQ *pSMB = NULL;
958 CREATE_DIRECTORY_RSP *pSMBr = NULL;
959 int bytes_returned;
960 int name_len;
961
962 cFYI(1, ("In CIFSSMBMkDir"));
963MkDirRetry:
964 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
965 (void **) &pSMBr);
966 if (rc)
967 return rc;
968
969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000970 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700971 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 name_len++; /* trailing null */
973 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700974 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 name_len = strnlen(name, PATH_MAX);
976 name_len++; /* trailing null */
977 strncpy(pSMB->DirName, name, name_len);
978 }
979
980 pSMB->BufferFormat = 0x04;
981 pSMB->hdr.smb_buf_length += name_len + 1;
982 pSMB->ByteCount = cpu_to_le16(name_len + 1);
983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700985 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000986 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -0700988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 cifs_buf_release(pSMB);
990 if (rc == -EAGAIN)
991 goto MkDirRetry;
992 return rc;
993}
994
Steve French2dd29d32007-04-23 22:07:35 +0000995int
996CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000997 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000998 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000999 const struct nls_table *nls_codepage, int remap)
1000{
1001 TRANSACTION2_SPI_REQ *pSMB = NULL;
1002 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1003 int name_len;
1004 int rc = 0;
1005 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001006 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 OPEN_PSX_REQ *pdata;
1008 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001009
1010 cFYI(1, ("In POSIX Create"));
1011PsxCreat:
1012 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1013 (void **) &pSMBr);
1014 if (rc)
1015 return rc;
1016
1017 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1018 name_len =
1019 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1020 PATH_MAX, nls_codepage, remap);
1021 name_len++; /* trailing null */
1022 name_len *= 2;
1023 } else { /* BB improve the check for buffer overruns BB */
1024 name_len = strnlen(name, PATH_MAX);
1025 name_len++; /* trailing null */
1026 strncpy(pSMB->FileName, name, name_len);
1027 }
1028
1029 params = 6 + name_len;
1030 count = sizeof(OPEN_PSX_REQ);
1031 pSMB->MaxParameterCount = cpu_to_le16(2);
1032 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1033 pSMB->MaxSetupCount = 0;
1034 pSMB->Reserved = 0;
1035 pSMB->Flags = 0;
1036 pSMB->Timeout = 0;
1037 pSMB->Reserved2 = 0;
1038 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001039 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001040 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001041 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001042 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001043 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001044 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001045 pdata->OpenFlags = cpu_to_le32(*pOplock);
1046 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1047 pSMB->DataOffset = cpu_to_le16(offset);
1048 pSMB->SetupCount = 1;
1049 pSMB->Reserved3 = 0;
1050 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1051 byte_count = 3 /* pad */ + params + count;
1052
1053 pSMB->DataCount = cpu_to_le16(count);
1054 pSMB->ParameterCount = cpu_to_le16(params);
1055 pSMB->TotalDataCount = pSMB->DataCount;
1056 pSMB->TotalParameterCount = pSMB->ParameterCount;
1057 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1058 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001059 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001060 pSMB->ByteCount = cpu_to_le16(byte_count);
1061 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1062 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1063 if (rc) {
1064 cFYI(1, ("Posix create returned %d", rc));
1065 goto psx_create_err;
1066 }
1067
Steve French790fe572007-07-07 19:25:05 +00001068 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001069 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1070
1071 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1072 rc = -EIO; /* bad smb */
1073 goto psx_create_err;
1074 }
1075
1076 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001077 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001078 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001079
Steve French2dd29d32007-04-23 22:07:35 +00001080 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001081 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001082 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1083 /* Let caller know file was created so we can set the mode. */
1084 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001085 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001086 *pOplock |= CIFS_CREATE_ACTION;
1087 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001088 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1089 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001090 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001091 } else {
Steve French790fe572007-07-07 19:25:05 +00001092 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001093 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001094 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001095 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001096 goto psx_create_err;
1097 }
Steve French50c2f752007-07-13 00:33:32 +00001098 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001099 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001100 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001101 }
Steve French2dd29d32007-04-23 22:07:35 +00001102
1103psx_create_err:
1104 cifs_buf_release(pSMB);
1105
1106 cifs_stats_inc(&tcon->num_mkdirs);
1107
1108 if (rc == -EAGAIN)
1109 goto PsxCreat;
1110
Steve French50c2f752007-07-13 00:33:32 +00001111 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001112}
1113
Steve Frencha9d02ad2005-08-24 23:06:05 -07001114static __u16 convert_disposition(int disposition)
1115{
1116 __u16 ofun = 0;
1117
1118 switch (disposition) {
1119 case FILE_SUPERSEDE:
1120 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1121 break;
1122 case FILE_OPEN:
1123 ofun = SMBOPEN_OAPPEND;
1124 break;
1125 case FILE_CREATE:
1126 ofun = SMBOPEN_OCREATE;
1127 break;
1128 case FILE_OPEN_IF:
1129 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1130 break;
1131 case FILE_OVERWRITE:
1132 ofun = SMBOPEN_OTRUNC;
1133 break;
1134 case FILE_OVERWRITE_IF:
1135 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1136 break;
1137 default:
Steve French790fe572007-07-07 19:25:05 +00001138 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139 ofun = SMBOPEN_OAPPEND; /* regular open */
1140 }
1141 return ofun;
1142}
1143
Jeff Layton35fc37d2008-05-14 10:22:03 -07001144static int
1145access_flags_to_smbopen_mode(const int access_flags)
1146{
1147 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1148
1149 if (masked_flags == GENERIC_READ)
1150 return SMBOPEN_READ;
1151 else if (masked_flags == GENERIC_WRITE)
1152 return SMBOPEN_WRITE;
1153
1154 /* just go for read/write */
1155 return SMBOPEN_READWRITE;
1156}
1157
Steve Frencha9d02ad2005-08-24 23:06:05 -07001158int
1159SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1160 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001161 const int access_flags, const int create_options, __u16 *netfid,
1162 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163 const struct nls_table *nls_codepage, int remap)
1164{
1165 int rc = -EACCES;
1166 OPENX_REQ *pSMB = NULL;
1167 OPENX_RSP *pSMBr = NULL;
1168 int bytes_returned;
1169 int name_len;
1170 __u16 count;
1171
1172OldOpenRetry:
1173 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1174 (void **) &pSMBr);
1175 if (rc)
1176 return rc;
1177
1178 pSMB->AndXCommand = 0xFF; /* none */
1179
1180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1181 count = 1; /* account for one byte pad to word boundary */
1182 name_len =
1183 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1184 fileName, PATH_MAX, nls_codepage, remap);
1185 name_len++; /* trailing null */
1186 name_len *= 2;
1187 } else { /* BB improve check for buffer overruns BB */
1188 count = 0; /* no pad */
1189 name_len = strnlen(fileName, PATH_MAX);
1190 name_len++; /* trailing null */
1191 strncpy(pSMB->fileName, fileName, name_len);
1192 }
1193 if (*pOplock & REQ_OPLOCK)
1194 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001195 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001196 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001197
Steve Frencha9d02ad2005-08-24 23:06:05 -07001198 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001199 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001200 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1201 /* set file as system file if special file such
1202 as fifo and server expecting SFU style and
1203 no Unix extensions */
1204
Steve French790fe572007-07-07 19:25:05 +00001205 if (create_options & CREATE_OPTION_SPECIAL)
1206 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001207 else /* BB FIXME BB */
1208 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209
Jeff Layton67750fb2008-05-09 22:28:02 +00001210 if (create_options & CREATE_OPTION_READONLY)
1211 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212
1213 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001214/* pSMB->CreateOptions = cpu_to_le32(create_options &
1215 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001217
1218 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001219 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 count += name_len;
1221 pSMB->hdr.smb_buf_length += count;
1222
1223 pSMB->ByteCount = cpu_to_le16(count);
1224 /* long_op set to 1 to allow for oplock break timeouts */
1225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001226 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227 cifs_stats_inc(&tcon->num_opens);
1228 if (rc) {
1229 cFYI(1, ("Error in Open = %d", rc));
1230 } else {
1231 /* BB verify if wct == 15 */
1232
Steve French582d21e2008-05-13 04:54:12 +00001233/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
1235 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1236 /* Let caller know file was created so we can set the mode. */
1237 /* Do we care about the CreateAction in any other cases? */
1238 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001239/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 *pOplock |= CIFS_CREATE_ACTION; */
1241 /* BB FIXME END */
1242
Steve French790fe572007-07-07 19:25:05 +00001243 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1245 pfile_info->LastAccessTime = 0; /* BB fixme */
1246 pfile_info->LastWriteTime = 0; /* BB fixme */
1247 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001248 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001249 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001251 pfile_info->AllocationSize =
1252 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1253 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001255 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 }
1257 }
1258
1259 cifs_buf_release(pSMB);
1260 if (rc == -EAGAIN)
1261 goto OldOpenRetry;
1262 return rc;
1263}
1264
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265int
1266CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1267 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001268 const int access_flags, const int create_options, __u16 *netfid,
1269 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001270 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271{
1272 int rc = -EACCES;
1273 OPEN_REQ *pSMB = NULL;
1274 OPEN_RSP *pSMBr = NULL;
1275 int bytes_returned;
1276 int name_len;
1277 __u16 count;
1278
1279openRetry:
1280 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1281 (void **) &pSMBr);
1282 if (rc)
1283 return rc;
1284
1285 pSMB->AndXCommand = 0xFF; /* none */
1286
1287 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1288 count = 1; /* account for one byte pad to word boundary */
1289 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001290 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001291 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 name_len++; /* trailing null */
1293 name_len *= 2;
1294 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001295 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 count = 0; /* no pad */
1297 name_len = strnlen(fileName, PATH_MAX);
1298 name_len++; /* trailing null */
1299 pSMB->NameLength = cpu_to_le16(name_len);
1300 strncpy(pSMB->fileName, fileName, name_len);
1301 }
1302 if (*pOplock & REQ_OPLOCK)
1303 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001304 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1307 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001308 /* set file as system file if special file such
1309 as fifo and server expecting SFU style and
1310 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001311 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001312 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1313 else
1314 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 /* XP does not handle ATTR_POSIX_SEMANTICS */
1317 /* but it helps speed up case sensitive checks for other
1318 servers such as Samba */
1319 if (tcon->ses->capabilities & CAP_UNIX)
1320 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1321
Jeff Layton67750fb2008-05-09 22:28:02 +00001322 if (create_options & CREATE_OPTION_READONLY)
1323 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1324
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1326 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001327 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001328 /* BB Expirement with various impersonation levels and verify */
1329 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 pSMB->SecurityFlags =
1331 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1332
1333 count += name_len;
1334 pSMB->hdr.smb_buf_length += count;
1335
1336 pSMB->ByteCount = cpu_to_le16(count);
1337 /* long_op set to 1 to allow for oplock break timeouts */
1338 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001339 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha45443472005-08-24 13:59:35 -07001340 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 if (rc) {
1342 cFYI(1, ("Error in Open = %d", rc));
1343 } else {
Steve French09d1db52005-04-28 22:41:08 -07001344 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1346 /* Let caller know file was created so we can set the mode. */
1347 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001348 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001349 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001350 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001351 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1352 36 /* CreationTime to Attributes */);
1353 /* the file_info buf is endian converted by caller */
1354 pfile_info->AllocationSize = pSMBr->AllocationSize;
1355 pfile_info->EndOfFile = pSMBr->EndOfFile;
1356 pfile_info->NumberOfLinks = cpu_to_le32(1);
1357 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001360
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 cifs_buf_release(pSMB);
1362 if (rc == -EAGAIN)
1363 goto openRetry;
1364 return rc;
1365}
1366
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367int
Steve French50c2f752007-07-13 00:33:32 +00001368CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1369 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1370 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
1372 int rc = -EACCES;
1373 READ_REQ *pSMB = NULL;
1374 READ_RSP *pSMBr = NULL;
1375 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001376 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001377 int resp_buf_type = 0;
1378 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Steve French790fe572007-07-07 19:25:05 +00001380 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1381 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001382 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001383 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001384 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001385 if ((lseek >> 32) > 0) {
1386 /* can not handle this big offset for old */
1387 return -EIO;
1388 }
1389 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001392 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 if (rc)
1394 return rc;
1395
1396 /* tcon and ses pointer are checked in smb_init */
1397 if (tcon->ses->server == NULL)
1398 return -ECONNABORTED;
1399
Steve Frenchec637e32005-12-12 20:53:18 -08001400 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 pSMB->Fid = netfid;
1402 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001403 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001404 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001405
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 pSMB->Remaining = 0;
1407 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1408 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001409 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001410 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1411 else {
1412 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001413 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001415 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001416 }
Steve Frenchec637e32005-12-12 20:53:18 -08001417
1418 iov[0].iov_base = (char *)pSMB;
1419 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001420 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001421 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha45443472005-08-24 13:59:35 -07001422 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001423 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (rc) {
1425 cERROR(1, ("Send error in read = %d", rc));
1426 } else {
1427 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1428 data_length = data_length << 16;
1429 data_length += le16_to_cpu(pSMBr->DataLength);
1430 *nbytes = data_length;
1431
1432 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001433 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001435 cFYI(1, ("bad length %d for count %d",
1436 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 rc = -EIO;
1438 *nbytes = 0;
1439 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001440 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001441 le16_to_cpu(pSMBr->DataOffset);
1442/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001443 cERROR(1,("Faulting on read rc = %d",rc));
1444 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001445 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001446 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001447 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 }
1449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
Steve French4b8f9302006-02-26 16:41:18 +00001451/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001452 if (*buf) {
1453 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001454 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001455 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001456 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001457 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001458 /* return buffer to caller to free */
1459 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001460 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001461 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001462 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001463 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001464 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001465
1466 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 since file handle passed in no longer valid */
1468 return rc;
1469}
1470
Steve Frenchec637e32005-12-12 20:53:18 -08001471
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472int
1473CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1474 const int netfid, const unsigned int count,
1475 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001476 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477{
1478 int rc = -EACCES;
1479 WRITE_REQ *pSMB = NULL;
1480 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001481 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 __u32 bytes_sent;
1483 __u16 byte_count;
1484
Steve French61de8002008-10-30 20:15:22 +00001485 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001486 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001487 return -ECONNABORTED;
1488
Steve French790fe572007-07-07 19:25:05 +00001489 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001490 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001491 else {
Steve French1c955182005-08-30 20:58:07 -07001492 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001493 if ((offset >> 32) > 0) {
1494 /* can not handle big offset for old srv */
1495 return -EIO;
1496 }
1497 }
Steve French1c955182005-08-30 20:58:07 -07001498
1499 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 (void **) &pSMBr);
1501 if (rc)
1502 return rc;
1503 /* tcon and ses pointer are checked in smb_init */
1504 if (tcon->ses->server == NULL)
1505 return -ECONNABORTED;
1506
1507 pSMB->AndXCommand = 0xFF; /* none */
1508 pSMB->Fid = netfid;
1509 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001510 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001511 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 pSMB->Reserved = 0xFFFFFFFF;
1514 pSMB->WriteMode = 0;
1515 pSMB->Remaining = 0;
1516
Steve French50c2f752007-07-13 00:33:32 +00001517 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 can send more if LARGE_WRITE_X capability returned by the server and if
1519 our buffer is big enough or if we convert to iovecs on socket writes
1520 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001521 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1523 } else {
1524 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1525 & ~0xFF;
1526 }
1527
1528 if (bytes_sent > count)
1529 bytes_sent = count;
1530 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001531 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001532 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001533 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001534 else if (ubuf) {
1535 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 cifs_buf_release(pSMB);
1537 return -EFAULT;
1538 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001539 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 /* No buffer */
1541 cifs_buf_release(pSMB);
1542 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001543 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001544 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001545 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001546 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001547 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001548
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1550 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001551 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001552
Steve French790fe572007-07-07 19:25:05 +00001553 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001554 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001555 else { /* old style write has byte count 4 bytes earlier
1556 so 4 bytes pad */
1557 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001558 (struct smb_com_writex_req *)pSMB;
1559 pSMBW->ByteCount = cpu_to_le16(byte_count);
1560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1563 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001564 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (rc) {
1566 cFYI(1, ("Send error in write = %d", rc));
1567 *nbytes = 0;
1568 } else {
1569 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1570 *nbytes = (*nbytes) << 16;
1571 *nbytes += le16_to_cpu(pSMBr->Count);
1572 }
1573
1574 cifs_buf_release(pSMB);
1575
Steve French50c2f752007-07-13 00:33:32 +00001576 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 since file handle passed in no longer valid */
1578
1579 return rc;
1580}
1581
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001582int
1583CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001585 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1586 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587{
1588 int rc = -EACCES;
1589 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001590 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001591 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001592 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001594 *nbytes = 0;
1595
Steve French790fe572007-07-07 19:25:05 +00001596 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001597
Steve French4c3130e2008-12-09 00:28:16 +00001598 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001599 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001600 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001601 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001602 if ((offset >> 32) > 0) {
1603 /* can not handle big offset for old srv */
1604 return -EIO;
1605 }
1606 }
Steve French8cc64c62005-10-03 13:49:43 -07001607 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (rc)
1609 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 /* tcon and ses pointer are checked in smb_init */
1611 if (tcon->ses->server == NULL)
1612 return -ECONNABORTED;
1613
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001614 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 pSMB->Fid = netfid;
1616 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001617 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001618 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 pSMB->Reserved = 0xFFFFFFFF;
1620 pSMB->WriteMode = 0;
1621 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001624 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Steve French3e844692005-10-03 13:37:24 -07001626 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1627 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001628 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001629 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001630 pSMB->hdr.smb_buf_length += count+1;
1631 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001632 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1633 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001634 pSMB->ByteCount = cpu_to_le16(count + 1);
1635 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001636 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001637 (struct smb_com_writex_req *)pSMB;
1638 pSMBW->ByteCount = cpu_to_le16(count + 5);
1639 }
Steve French3e844692005-10-03 13:37:24 -07001640 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001641 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001642 iov[0].iov_len = smb_hdr_len + 4;
1643 else /* wct == 12 pad bigger by four bytes */
1644 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001645
Steve French3e844692005-10-03 13:37:24 -07001646
Steve Frenchec637e32005-12-12 20:53:18 -08001647 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001648 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001649 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001651 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001652 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001653 /* presumably this can not happen, but best to be safe */
1654 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001655 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001656 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001657 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1658 *nbytes = (*nbytes) << 16;
1659 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
Steve French4b8f9302006-02-26 16:41:18 +00001662/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001663 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001664 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001665 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001666 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667
Steve French50c2f752007-07-13 00:33:32 +00001668 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 since file handle passed in no longer valid */
1670
1671 return rc;
1672}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001673
1674
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675int
1676CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1677 const __u16 smb_file_id, const __u64 len,
1678 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001679 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 int rc = 0;
1682 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001683/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 int bytes_returned;
1685 int timeout = 0;
1686 __u16 count;
1687
Steve French4b18f2a2008-04-29 00:06:05 +00001688 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001689 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 if (rc)
1692 return rc;
1693
Steve French790fe572007-07-07 19:25:05 +00001694 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001695 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001697 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001698 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1700 } else {
1701 pSMB->Timeout = 0;
1702 }
1703
1704 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1705 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1706 pSMB->LockType = lockType;
1707 pSMB->AndXCommand = 0xFF; /* none */
1708 pSMB->Fid = smb_file_id; /* netfid stays le */
1709
Steve French790fe572007-07-07 19:25:05 +00001710 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1712 /* BB where to store pid high? */
1713 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1714 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1715 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1716 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1717 count = sizeof(LOCKING_ANDX_RANGE);
1718 } else {
1719 /* oplock break */
1720 count = 0;
1721 }
1722 pSMB->hdr.smb_buf_length += count;
1723 pSMB->ByteCount = cpu_to_le16(count);
1724
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001725 if (waitFlag) {
1726 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001727 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001728 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001729 } else {
Steve French133672e2007-11-13 22:41:37 +00001730 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1731 timeout);
1732 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001733 }
Steve Frencha45443472005-08-24 13:59:35 -07001734 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001735 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
Steve French50c2f752007-07-13 00:33:32 +00001738 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 since file handle passed in no longer valid */
1740 return rc;
1741}
1742
1743int
Steve French08547b02006-02-28 22:39:25 +00001744CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1745 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001746 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001747 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001748{
1749 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1750 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001751 struct cifs_posix_lock *parm_data;
1752 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001753 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001754 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001755 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001756 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001757 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001758
1759 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001760
Steve French790fe572007-07-07 19:25:05 +00001761 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001762 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001763
Steve French08547b02006-02-28 22:39:25 +00001764 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1765
1766 if (rc)
1767 return rc;
1768
1769 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1770
Steve French50c2f752007-07-13 00:33:32 +00001771 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001772 pSMB->MaxSetupCount = 0;
1773 pSMB->Reserved = 0;
1774 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001775 pSMB->Reserved2 = 0;
1776 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1777 offset = param_offset + params;
1778
Steve French08547b02006-02-28 22:39:25 +00001779 count = sizeof(struct cifs_posix_lock);
1780 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001781 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001782 pSMB->SetupCount = 1;
1783 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001784 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001785 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1786 else
1787 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1788 byte_count = 3 /* pad */ + params + count;
1789 pSMB->DataCount = cpu_to_le16(count);
1790 pSMB->ParameterCount = cpu_to_le16(params);
1791 pSMB->TotalDataCount = pSMB->DataCount;
1792 pSMB->TotalParameterCount = pSMB->ParameterCount;
1793 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001794 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001795 (((char *) &pSMB->hdr.Protocol) + offset);
1796
1797 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001798 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001799 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001800 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001801 pSMB->Timeout = cpu_to_le32(-1);
1802 } else
1803 pSMB->Timeout = 0;
1804
Steve French08547b02006-02-28 22:39:25 +00001805 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001806 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001807 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001808
1809 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001810 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001811 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1812 pSMB->Reserved4 = 0;
1813 pSMB->hdr.smb_buf_length += byte_count;
1814 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001815 if (waitFlag) {
1816 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1817 (struct smb_hdr *) pSMBr, &bytes_returned);
1818 } else {
Steve French133672e2007-11-13 22:41:37 +00001819 iov[0].iov_base = (char *)pSMB;
1820 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1821 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1822 &resp_buf_type, timeout);
1823 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1824 not try to free it twice below on exit */
1825 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001826 }
1827
Steve French08547b02006-02-28 22:39:25 +00001828 if (rc) {
1829 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001830 } else if (get_flag) {
1831 /* lock structure can be returned on get */
1832 __u16 data_offset;
1833 __u16 data_count;
1834 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001835
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001836 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1837 rc = -EIO; /* bad smb */
1838 goto plk_err_exit;
1839 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001840 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1841 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001842 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001843 rc = -EIO;
1844 goto plk_err_exit;
1845 }
1846 parm_data = (struct cifs_posix_lock *)
1847 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001848 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001849 pLockData->fl_type = F_UNLCK;
1850 }
Steve French50c2f752007-07-13 00:33:32 +00001851
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001852plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001853 if (pSMB)
1854 cifs_small_buf_release(pSMB);
1855
Steve French133672e2007-11-13 22:41:37 +00001856 if (resp_buf_type == CIFS_SMALL_BUFFER)
1857 cifs_small_buf_release(iov[0].iov_base);
1858 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1859 cifs_buf_release(iov[0].iov_base);
1860
Steve French08547b02006-02-28 22:39:25 +00001861 /* Note: On -EAGAIN error only caller can retry on handle based calls
1862 since file handle passed in no longer valid */
1863
1864 return rc;
1865}
1866
1867
1868int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1870{
1871 int rc = 0;
1872 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 cFYI(1, ("In CIFSSMBClose"));
1874
1875/* do not retry on dead session on close */
1876 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001877 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 return 0;
1879 if (rc)
1880 return rc;
1881
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001883 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001885 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001886 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001888 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 /* EINTR is expected when user ctl-c to kill app */
1890 cERROR(1, ("Send error in Close = %d", rc));
1891 }
1892 }
1893
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001895 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 rc = 0;
1897
1898 return rc;
1899}
1900
1901int
Steve Frenchb298f222009-02-21 21:17:43 +00001902CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1903{
1904 int rc = 0;
1905 FLUSH_REQ *pSMB = NULL;
1906 cFYI(1, ("In CIFSSMBFlush"));
1907
1908 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1909 if (rc)
1910 return rc;
1911
1912 pSMB->FileID = (__u16) smb_file_id;
1913 pSMB->ByteCount = 0;
1914 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1915 cifs_stats_inc(&tcon->num_flushes);
1916 if (rc)
1917 cERROR(1, ("Send error in Flush = %d", rc));
1918
1919 return rc;
1920}
1921
1922int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1924 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926{
1927 int rc = 0;
1928 RENAME_REQ *pSMB = NULL;
1929 RENAME_RSP *pSMBr = NULL;
1930 int bytes_returned;
1931 int name_len, name_len2;
1932 __u16 count;
1933
1934 cFYI(1, ("In CIFSSMBRename"));
1935renameRetry:
1936 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1937 (void **) &pSMBr);
1938 if (rc)
1939 return rc;
1940
1941 pSMB->BufferFormat = 0x04;
1942 pSMB->SearchAttributes =
1943 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1944 ATTR_DIRECTORY);
1945
1946 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1947 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001948 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001949 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 name_len++; /* trailing null */
1951 name_len *= 2;
1952 pSMB->OldFileName[name_len] = 0x04; /* pad */
1953 /* protocol requires ASCII signature byte on Unicode string */
1954 pSMB->OldFileName[name_len + 1] = 0x00;
1955 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001956 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001957 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1959 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001960 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 name_len = strnlen(fromName, PATH_MAX);
1962 name_len++; /* trailing null */
1963 strncpy(pSMB->OldFileName, fromName, name_len);
1964 name_len2 = strnlen(toName, PATH_MAX);
1965 name_len2++; /* trailing null */
1966 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1967 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1968 name_len2++; /* trailing null */
1969 name_len2++; /* signature byte */
1970 }
1971
1972 count = 1 /* 1st signature byte */ + name_len + name_len2;
1973 pSMB->hdr.smb_buf_length += count;
1974 pSMB->ByteCount = cpu_to_le16(count);
1975
1976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001978 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001979 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 cifs_buf_release(pSMB);
1983
1984 if (rc == -EAGAIN)
1985 goto renameRetry;
1986
1987 return rc;
1988}
1989
Steve French50c2f752007-07-13 00:33:32 +00001990int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001991 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001992 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993{
1994 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1995 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001996 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 char *data_offset;
1998 char dummy_string[30];
1999 int rc = 0;
2000 int bytes_returned = 0;
2001 int len_of_str;
2002 __u16 params, param_offset, offset, count, byte_count;
2003
2004 cFYI(1, ("Rename to File by handle"));
2005 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2006 (void **) &pSMBr);
2007 if (rc)
2008 return rc;
2009
2010 params = 6;
2011 pSMB->MaxSetupCount = 0;
2012 pSMB->Reserved = 0;
2013 pSMB->Flags = 0;
2014 pSMB->Timeout = 0;
2015 pSMB->Reserved2 = 0;
2016 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2017 offset = param_offset + params;
2018
2019 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2020 rename_info = (struct set_file_rename *) data_offset;
2021 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002022 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 pSMB->SetupCount = 1;
2024 pSMB->Reserved3 = 0;
2025 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2026 byte_count = 3 /* pad */ + params;
2027 pSMB->ParameterCount = cpu_to_le16(params);
2028 pSMB->TotalParameterCount = pSMB->ParameterCount;
2029 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2030 pSMB->DataOffset = cpu_to_le16(offset);
2031 /* construct random name ".cifs_tmp<inodenum><mid>" */
2032 rename_info->overwrite = cpu_to_le32(1);
2033 rename_info->root_fid = 0;
2034 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002035 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002036 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2037 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002038 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002040 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002041 target_name, PATH_MAX, nls_codepage,
2042 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 }
2044 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002045 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 byte_count += count;
2047 pSMB->DataCount = cpu_to_le16(count);
2048 pSMB->TotalDataCount = pSMB->DataCount;
2049 pSMB->Fid = netfid;
2050 pSMB->InformationLevel =
2051 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2052 pSMB->Reserved4 = 0;
2053 pSMB->hdr.smb_buf_length += byte_count;
2054 pSMB->ByteCount = cpu_to_le16(byte_count);
2055 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002057 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002058 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002059 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 cifs_buf_release(pSMB);
2062
2063 /* Note: On -EAGAIN error only caller can retry on handle based calls
2064 since file handle passed in no longer valid */
2065
2066 return rc;
2067}
2068
2069int
Steve French50c2f752007-07-13 00:33:32 +00002070CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2071 const __u16 target_tid, const char *toName, const int flags,
2072 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073{
2074 int rc = 0;
2075 COPY_REQ *pSMB = NULL;
2076 COPY_RSP *pSMBr = NULL;
2077 int bytes_returned;
2078 int name_len, name_len2;
2079 __u16 count;
2080
2081 cFYI(1, ("In CIFSSMBCopy"));
2082copyRetry:
2083 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2084 (void **) &pSMBr);
2085 if (rc)
2086 return rc;
2087
2088 pSMB->BufferFormat = 0x04;
2089 pSMB->Tid2 = target_tid;
2090
2091 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2092
2093 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002094 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002095 fromName, PATH_MAX, nls_codepage,
2096 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 name_len++; /* trailing null */
2098 name_len *= 2;
2099 pSMB->OldFileName[name_len] = 0x04; /* pad */
2100 /* protocol requires ASCII signature byte on Unicode string */
2101 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002102 name_len2 =
2103 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002104 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2106 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002107 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 name_len = strnlen(fromName, PATH_MAX);
2109 name_len++; /* trailing null */
2110 strncpy(pSMB->OldFileName, fromName, name_len);
2111 name_len2 = strnlen(toName, PATH_MAX);
2112 name_len2++; /* trailing null */
2113 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2114 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2115 name_len2++; /* trailing null */
2116 name_len2++; /* signature byte */
2117 }
2118
2119 count = 1 /* 1st signature byte */ + name_len + name_len2;
2120 pSMB->hdr.smb_buf_length += count;
2121 pSMB->ByteCount = cpu_to_le16(count);
2122
2123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2124 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2125 if (rc) {
2126 cFYI(1, ("Send error in copy = %d with %d files copied",
2127 rc, le16_to_cpu(pSMBr->CopyCount)));
2128 }
Steve French0d817bc2008-05-22 02:02:03 +00002129 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130
2131 if (rc == -EAGAIN)
2132 goto copyRetry;
2133
2134 return rc;
2135}
2136
2137int
2138CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2139 const char *fromName, const char *toName,
2140 const struct nls_table *nls_codepage)
2141{
2142 TRANSACTION2_SPI_REQ *pSMB = NULL;
2143 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2144 char *data_offset;
2145 int name_len;
2146 int name_len_target;
2147 int rc = 0;
2148 int bytes_returned = 0;
2149 __u16 params, param_offset, offset, byte_count;
2150
2151 cFYI(1, ("In Symlink Unix style"));
2152createSymLinkRetry:
2153 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2154 (void **) &pSMBr);
2155 if (rc)
2156 return rc;
2157
2158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2159 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002160 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 /* find define for this maxpathcomponent */
2162 , nls_codepage);
2163 name_len++; /* trailing null */
2164 name_len *= 2;
2165
Steve French50c2f752007-07-13 00:33:32 +00002166 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 name_len = strnlen(fromName, PATH_MAX);
2168 name_len++; /* trailing null */
2169 strncpy(pSMB->FileName, fromName, name_len);
2170 }
2171 params = 6 + name_len;
2172 pSMB->MaxSetupCount = 0;
2173 pSMB->Reserved = 0;
2174 pSMB->Flags = 0;
2175 pSMB->Timeout = 0;
2176 pSMB->Reserved2 = 0;
2177 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002178 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 offset = param_offset + params;
2180
2181 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2183 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002184 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 /* find define for this maxpathcomponent */
2186 , nls_codepage);
2187 name_len_target++; /* trailing null */
2188 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002189 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 name_len_target = strnlen(toName, PATH_MAX);
2191 name_len_target++; /* trailing null */
2192 strncpy(data_offset, toName, name_len_target);
2193 }
2194
2195 pSMB->MaxParameterCount = cpu_to_le16(2);
2196 /* BB find exact max on data count below from sess */
2197 pSMB->MaxDataCount = cpu_to_le16(1000);
2198 pSMB->SetupCount = 1;
2199 pSMB->Reserved3 = 0;
2200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2201 byte_count = 3 /* pad */ + params + name_len_target;
2202 pSMB->DataCount = cpu_to_le16(name_len_target);
2203 pSMB->ParameterCount = cpu_to_le16(params);
2204 pSMB->TotalDataCount = pSMB->DataCount;
2205 pSMB->TotalParameterCount = pSMB->ParameterCount;
2206 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2207 pSMB->DataOffset = cpu_to_le16(offset);
2208 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2209 pSMB->Reserved4 = 0;
2210 pSMB->hdr.smb_buf_length += byte_count;
2211 pSMB->ByteCount = cpu_to_le16(byte_count);
2212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002214 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002215 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002216 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Steve French0d817bc2008-05-22 02:02:03 +00002218 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
2220 if (rc == -EAGAIN)
2221 goto createSymLinkRetry;
2222
2223 return rc;
2224}
2225
2226int
2227CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2228 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002229 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230{
2231 TRANSACTION2_SPI_REQ *pSMB = NULL;
2232 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2233 char *data_offset;
2234 int name_len;
2235 int name_len_target;
2236 int rc = 0;
2237 int bytes_returned = 0;
2238 __u16 params, param_offset, offset, byte_count;
2239
2240 cFYI(1, ("In Create Hard link Unix style"));
2241createHardLinkRetry:
2242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2243 (void **) &pSMBr);
2244 if (rc)
2245 return rc;
2246
2247 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002248 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002249 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 name_len++; /* trailing null */
2251 name_len *= 2;
2252
Steve French50c2f752007-07-13 00:33:32 +00002253 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 name_len = strnlen(toName, PATH_MAX);
2255 name_len++; /* trailing null */
2256 strncpy(pSMB->FileName, toName, name_len);
2257 }
2258 params = 6 + name_len;
2259 pSMB->MaxSetupCount = 0;
2260 pSMB->Reserved = 0;
2261 pSMB->Flags = 0;
2262 pSMB->Timeout = 0;
2263 pSMB->Reserved2 = 0;
2264 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002265 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 offset = param_offset + params;
2267
2268 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2269 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2270 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002271 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002272 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 name_len_target++; /* trailing null */
2274 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002275 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 name_len_target = strnlen(fromName, PATH_MAX);
2277 name_len_target++; /* trailing null */
2278 strncpy(data_offset, fromName, name_len_target);
2279 }
2280
2281 pSMB->MaxParameterCount = cpu_to_le16(2);
2282 /* BB find exact max on data count below from sess*/
2283 pSMB->MaxDataCount = cpu_to_le16(1000);
2284 pSMB->SetupCount = 1;
2285 pSMB->Reserved3 = 0;
2286 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2287 byte_count = 3 /* pad */ + params + name_len_target;
2288 pSMB->ParameterCount = cpu_to_le16(params);
2289 pSMB->TotalParameterCount = pSMB->ParameterCount;
2290 pSMB->DataCount = cpu_to_le16(name_len_target);
2291 pSMB->TotalDataCount = pSMB->DataCount;
2292 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2293 pSMB->DataOffset = cpu_to_le16(offset);
2294 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2295 pSMB->Reserved4 = 0;
2296 pSMB->hdr.smb_buf_length += byte_count;
2297 pSMB->ByteCount = cpu_to_le16(byte_count);
2298 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2299 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002300 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002301 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
2304 cifs_buf_release(pSMB);
2305 if (rc == -EAGAIN)
2306 goto createHardLinkRetry;
2307
2308 return rc;
2309}
2310
2311int
2312CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2313 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002314 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315{
2316 int rc = 0;
2317 NT_RENAME_REQ *pSMB = NULL;
2318 RENAME_RSP *pSMBr = NULL;
2319 int bytes_returned;
2320 int name_len, name_len2;
2321 __u16 count;
2322
2323 cFYI(1, ("In CIFSCreateHardLink"));
2324winCreateHardLinkRetry:
2325
2326 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2327 (void **) &pSMBr);
2328 if (rc)
2329 return rc;
2330
2331 pSMB->SearchAttributes =
2332 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2333 ATTR_DIRECTORY);
2334 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2335 pSMB->ClusterCount = 0;
2336
2337 pSMB->BufferFormat = 0x04;
2338
2339 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2340 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002341 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002342 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 name_len++; /* trailing null */
2344 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002345
2346 /* protocol specifies ASCII buffer format (0x04) for unicode */
2347 pSMB->OldFileName[name_len] = 0x04;
2348 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002350 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002351 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2353 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002354 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 name_len = strnlen(fromName, PATH_MAX);
2356 name_len++; /* trailing null */
2357 strncpy(pSMB->OldFileName, fromName, name_len);
2358 name_len2 = strnlen(toName, PATH_MAX);
2359 name_len2++; /* trailing null */
2360 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2361 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2362 name_len2++; /* trailing null */
2363 name_len2++; /* signature byte */
2364 }
2365
2366 count = 1 /* string type byte */ + name_len + name_len2;
2367 pSMB->hdr.smb_buf_length += count;
2368 pSMB->ByteCount = cpu_to_le16(count);
2369
2370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002372 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002373 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002375
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 cifs_buf_release(pSMB);
2377 if (rc == -EAGAIN)
2378 goto winCreateHardLinkRetry;
2379
2380 return rc;
2381}
2382
2383int
2384CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002385 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 const struct nls_table *nls_codepage)
2387{
2388/* SMB_QUERY_FILE_UNIX_LINK */
2389 TRANSACTION2_QPI_REQ *pSMB = NULL;
2390 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2391 int rc = 0;
2392 int bytes_returned;
2393 int name_len;
2394 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002395 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396
2397 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2398
2399querySymLinkRetry:
2400 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2401 (void **) &pSMBr);
2402 if (rc)
2403 return rc;
2404
2405 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2406 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002407 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2408 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 name_len++; /* trailing null */
2410 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002411 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 name_len = strnlen(searchName, PATH_MAX);
2413 name_len++; /* trailing null */
2414 strncpy(pSMB->FileName, searchName, name_len);
2415 }
2416
2417 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2418 pSMB->TotalDataCount = 0;
2419 pSMB->MaxParameterCount = cpu_to_le16(2);
2420 /* BB find exact max data count below from sess structure BB */
2421 pSMB->MaxDataCount = cpu_to_le16(4000);
2422 pSMB->MaxSetupCount = 0;
2423 pSMB->Reserved = 0;
2424 pSMB->Flags = 0;
2425 pSMB->Timeout = 0;
2426 pSMB->Reserved2 = 0;
2427 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002428 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 pSMB->DataCount = 0;
2430 pSMB->DataOffset = 0;
2431 pSMB->SetupCount = 1;
2432 pSMB->Reserved3 = 0;
2433 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2434 byte_count = params + 1 /* pad */ ;
2435 pSMB->TotalParameterCount = cpu_to_le16(params);
2436 pSMB->ParameterCount = pSMB->TotalParameterCount;
2437 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2438 pSMB->Reserved4 = 0;
2439 pSMB->hdr.smb_buf_length += byte_count;
2440 pSMB->ByteCount = cpu_to_le16(byte_count);
2441
2442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2444 if (rc) {
2445 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2446 } else {
2447 /* decode response */
2448
2449 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002451 if (rc || (pSMBr->ByteCount < 2))
2452 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002454 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002455 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456
Jeff Layton460b9692009-04-30 07:17:56 -04002457 data_start = ((char *) &pSMBr->hdr.Protocol) +
2458 le16_to_cpu(pSMBr->t2.DataOffset);
2459
Steve French0e0d2cf2009-05-01 05:27:32 +00002460 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2461 is_unicode = true;
2462 else
2463 is_unicode = false;
2464
Steve French737b7582005-04-28 22:41:06 -07002465 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002466 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002467 is_unicode, nls_codepage);
Jeff Layton460b9692009-04-30 07:17:56 -04002468 if (!symlinkinfo)
2469 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 }
2471 }
2472 cifs_buf_release(pSMB);
2473 if (rc == -EAGAIN)
2474 goto querySymLinkRetry;
2475 return rc;
2476}
2477
Parag Warudkarc9489772007-10-23 18:09:48 +00002478#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002479/* Initialize NT TRANSACT SMB into small smb request buffer.
2480 This assumes that all NT TRANSACTS that we init here have
2481 total parm and data under about 400 bytes (to fit in small cifs
2482 buffer size), which is the case so far, it easily fits. NB:
2483 Setup words themselves and ByteCount
2484 MaxSetupCount (size of returned setup area) and
2485 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002486static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002487smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002488 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002489 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002490{
2491 int rc;
2492 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002493 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002494
2495 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2496 (void **)&pSMB);
2497 if (rc)
2498 return rc;
2499 *ret_buf = (void *)pSMB;
2500 pSMB->Reserved = 0;
2501 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2502 pSMB->TotalDataCount = 0;
2503 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2504 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2505 pSMB->ParameterCount = pSMB->TotalParameterCount;
2506 pSMB->DataCount = pSMB->TotalDataCount;
2507 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2508 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2509 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2510 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2511 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2512 pSMB->SubCommand = cpu_to_le16(sub_command);
2513 return 0;
2514}
2515
2516static int
Steve French50c2f752007-07-13 00:33:32 +00002517validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002518 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002519{
Steve French50c2f752007-07-13 00:33:32 +00002520 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002521 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002522 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002523
Steve French630f3f0c2007-10-25 21:17:17 +00002524 *pdatalen = 0;
2525 *pparmlen = 0;
2526
Steve French790fe572007-07-07 19:25:05 +00002527 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002528 return -EINVAL;
2529
2530 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2531
2532 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002533 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002534 (char *)&pSMBr->ByteCount;
2535
Steve French0a4b92c2006-01-12 15:44:21 -08002536 data_offset = le32_to_cpu(pSMBr->DataOffset);
2537 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002538 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002539 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2540
2541 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2542 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2543
2544 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002545 if (*ppparm > end_of_smb) {
2546 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002547 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002548 } else if (parm_count + *ppparm > end_of_smb) {
2549 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002550 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002551 } else if (*ppdata > end_of_smb) {
2552 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002553 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002554 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002555 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002556 *ppdata, data_count, (data_count + *ppdata),
2557 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002558 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002559 } else if (parm_count + data_count > pSMBr->ByteCount) {
2560 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002561 return -EINVAL;
2562 }
Steve French630f3f0c2007-10-25 21:17:17 +00002563 *pdatalen = data_count;
2564 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002565 return 0;
2566}
Parag Warudkarc9489772007-10-23 18:09:48 +00002567#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002568
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569int
2570CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2571 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002572 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 const struct nls_table *nls_codepage)
2574{
2575 int rc = 0;
2576 int bytes_returned;
2577 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002578 struct smb_com_transaction_ioctl_req *pSMB;
2579 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2582 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2583 (void **) &pSMBr);
2584 if (rc)
2585 return rc;
2586
2587 pSMB->TotalParameterCount = 0 ;
2588 pSMB->TotalDataCount = 0;
2589 pSMB->MaxParameterCount = cpu_to_le32(2);
2590 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002591 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2592 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 pSMB->MaxSetupCount = 4;
2594 pSMB->Reserved = 0;
2595 pSMB->ParameterOffset = 0;
2596 pSMB->DataCount = 0;
2597 pSMB->DataOffset = 0;
2598 pSMB->SetupCount = 4;
2599 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2600 pSMB->ParameterCount = pSMB->TotalParameterCount;
2601 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2602 pSMB->IsFsctl = 1; /* FSCTL */
2603 pSMB->IsRootFlag = 0;
2604 pSMB->Fid = fid; /* file handle always le */
2605 pSMB->ByteCount = 0;
2606
2607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2609 if (rc) {
2610 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2611 } else { /* decode response */
2612 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2613 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2614 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2615 /* BB also check enough total bytes returned */
2616 rc = -EIO; /* bad smb */
2617 else {
Steve French790fe572007-07-07 19:25:05 +00002618 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002619 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002620 pSMBr->ByteCount +
2621 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622
Steve French50c2f752007-07-13 00:33:32 +00002623 struct reparse_data *reparse_buf =
2624 (struct reparse_data *)
2625 ((char *)&pSMBr->hdr.Protocol
2626 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002627 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 rc = -EIO;
2629 goto qreparse_out;
2630 }
Steve French790fe572007-07-07 19:25:05 +00002631 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 reparse_buf->TargetNameOffset +
2633 reparse_buf->TargetNameLen) >
2634 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002635 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 rc = -EIO;
2637 goto qreparse_out;
2638 }
Steve French50c2f752007-07-13 00:33:32 +00002639
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2641 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002642 (reparse_buf->LinkNamesBuf +
2643 reparse_buf->TargetNameOffset),
2644 min(buflen/2,
2645 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002647 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 reparse_buf->TargetNameOffset),
2649 name_len, nls_codepage);
2650 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002651 strncpy(symlinkinfo,
2652 reparse_buf->LinkNamesBuf +
2653 reparse_buf->TargetNameOffset,
2654 min_t(const int, buflen,
2655 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 }
2657 } else {
2658 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002659 cFYI(1, ("Invalid return data count on "
2660 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 }
2662 symlinkinfo[buflen] = 0; /* just in case so the caller
2663 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002664 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 }
2666 }
2667qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002668 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
2670 /* Note: On -EAGAIN error only caller can retry on handle based calls
2671 since file handle passed in no longer valid */
2672
2673 return rc;
2674}
2675
2676#ifdef CONFIG_CIFS_POSIX
2677
2678/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002679static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2680 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
2682 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002683 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2684 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2685 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2687
2688 return;
2689}
2690
2691/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002692static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2693 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694{
2695 int size = 0;
2696 int i;
2697 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002698 struct cifs_posix_ace *pACE;
2699 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2700 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
2702 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2703 return -EOPNOTSUPP;
2704
Steve French790fe572007-07-07 19:25:05 +00002705 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 count = le16_to_cpu(cifs_acl->access_entry_count);
2707 pACE = &cifs_acl->ace_array[0];
2708 size = sizeof(struct cifs_posix_acl);
2709 size += sizeof(struct cifs_posix_ace) * count;
2710 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002711 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002712 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2713 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 return -EINVAL;
2715 }
Steve French790fe572007-07-07 19:25:05 +00002716 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 count = le16_to_cpu(cifs_acl->access_entry_count);
2718 size = sizeof(struct cifs_posix_acl);
2719 size += sizeof(struct cifs_posix_ace) * count;
2720/* skip past access ACEs to get to default ACEs */
2721 pACE = &cifs_acl->ace_array[count];
2722 count = le16_to_cpu(cifs_acl->default_entry_count);
2723 size += sizeof(struct cifs_posix_ace) * count;
2724 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002725 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 return -EINVAL;
2727 } else {
2728 /* illegal type */
2729 return -EINVAL;
2730 }
2731
2732 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002733 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002734 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002735 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 return -ERANGE;
2737 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002738 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002739 for (i = 0; i < count ; i++) {
2740 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2741 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 }
2743 }
2744 return size;
2745}
2746
Steve French50c2f752007-07-13 00:33:32 +00002747static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2748 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749{
2750 __u16 rc = 0; /* 0 = ACL converted ok */
2751
Steve Frenchff7feac2005-11-15 16:45:16 -08002752 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2753 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002755 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 /* Probably no need to le convert -1 on any arch but can not hurt */
2757 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002758 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002759 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002760 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return rc;
2762}
2763
2764/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002765static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2766 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767{
2768 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002769 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2770 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 int count;
2772 int i;
2773
Steve French790fe572007-07-07 19:25:05 +00002774 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 return 0;
2776
2777 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002778 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002779 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002780 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002781 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002782 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002783 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 return 0;
2785 }
2786 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002787 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002788 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002789 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002790 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 else {
Steve French50c2f752007-07-13 00:33:32 +00002792 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 return 0;
2794 }
Steve French50c2f752007-07-13 00:33:32 +00002795 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2797 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002798 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 /* ACE not converted */
2800 break;
2801 }
2802 }
Steve French790fe572007-07-07 19:25:05 +00002803 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2805 rc += sizeof(struct cifs_posix_acl);
2806 /* BB add check to make sure ACL does not overflow SMB */
2807 }
2808 return rc;
2809}
2810
2811int
2812CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002813 const unsigned char *searchName,
2814 char *acl_inf, const int buflen, const int acl_type,
2815 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816{
2817/* SMB_QUERY_POSIX_ACL */
2818 TRANSACTION2_QPI_REQ *pSMB = NULL;
2819 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2820 int rc = 0;
2821 int bytes_returned;
2822 int name_len;
2823 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002824
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2826
2827queryAclRetry:
2828 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2829 (void **) &pSMBr);
2830 if (rc)
2831 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002832
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2834 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002835 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002836 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 name_len++; /* trailing null */
2838 name_len *= 2;
2839 pSMB->FileName[name_len] = 0;
2840 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002841 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 name_len = strnlen(searchName, PATH_MAX);
2843 name_len++; /* trailing null */
2844 strncpy(pSMB->FileName, searchName, name_len);
2845 }
2846
2847 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2848 pSMB->TotalDataCount = 0;
2849 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002850 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 pSMB->MaxDataCount = cpu_to_le16(4000);
2852 pSMB->MaxSetupCount = 0;
2853 pSMB->Reserved = 0;
2854 pSMB->Flags = 0;
2855 pSMB->Timeout = 0;
2856 pSMB->Reserved2 = 0;
2857 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002858 offsetof(struct smb_com_transaction2_qpi_req,
2859 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 pSMB->DataCount = 0;
2861 pSMB->DataOffset = 0;
2862 pSMB->SetupCount = 1;
2863 pSMB->Reserved3 = 0;
2864 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2865 byte_count = params + 1 /* pad */ ;
2866 pSMB->TotalParameterCount = cpu_to_le16(params);
2867 pSMB->ParameterCount = pSMB->TotalParameterCount;
2868 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2869 pSMB->Reserved4 = 0;
2870 pSMB->hdr.smb_buf_length += byte_count;
2871 pSMB->ByteCount = cpu_to_le16(byte_count);
2872
2873 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2874 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002875 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 if (rc) {
2877 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2878 } else {
2879 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002880
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2882 if (rc || (pSMBr->ByteCount < 2))
2883 /* BB also check enough total bytes returned */
2884 rc = -EIO; /* bad smb */
2885 else {
2886 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2887 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2888 rc = cifs_copy_posix_acl(acl_inf,
2889 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002890 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 }
2892 }
2893 cifs_buf_release(pSMB);
2894 if (rc == -EAGAIN)
2895 goto queryAclRetry;
2896 return rc;
2897}
2898
2899int
2900CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002901 const unsigned char *fileName,
2902 const char *local_acl, const int buflen,
2903 const int acl_type,
2904 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905{
2906 struct smb_com_transaction2_spi_req *pSMB = NULL;
2907 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2908 char *parm_data;
2909 int name_len;
2910 int rc = 0;
2911 int bytes_returned = 0;
2912 __u16 params, byte_count, data_count, param_offset, offset;
2913
2914 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2915setAclRetry:
2916 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002917 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 if (rc)
2919 return rc;
2920 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2921 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002922 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002923 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 name_len++; /* trailing null */
2925 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002926 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 name_len = strnlen(fileName, PATH_MAX);
2928 name_len++; /* trailing null */
2929 strncpy(pSMB->FileName, fileName, name_len);
2930 }
2931 params = 6 + name_len;
2932 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002933 /* BB find max SMB size from sess */
2934 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 pSMB->MaxSetupCount = 0;
2936 pSMB->Reserved = 0;
2937 pSMB->Flags = 0;
2938 pSMB->Timeout = 0;
2939 pSMB->Reserved2 = 0;
2940 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002941 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 offset = param_offset + params;
2943 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2944 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2945
2946 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002947 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948
Steve French790fe572007-07-07 19:25:05 +00002949 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 rc = -EOPNOTSUPP;
2951 goto setACLerrorExit;
2952 }
2953 pSMB->DataOffset = cpu_to_le16(offset);
2954 pSMB->SetupCount = 1;
2955 pSMB->Reserved3 = 0;
2956 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2957 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2958 byte_count = 3 /* pad */ + params + data_count;
2959 pSMB->DataCount = cpu_to_le16(data_count);
2960 pSMB->TotalDataCount = pSMB->DataCount;
2961 pSMB->ParameterCount = cpu_to_le16(params);
2962 pSMB->TotalParameterCount = pSMB->ParameterCount;
2963 pSMB->Reserved4 = 0;
2964 pSMB->hdr.smb_buf_length += byte_count;
2965 pSMB->ByteCount = cpu_to_le16(byte_count);
2966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002967 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002968 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971setACLerrorExit:
2972 cifs_buf_release(pSMB);
2973 if (rc == -EAGAIN)
2974 goto setAclRetry;
2975 return rc;
2976}
2977
Steve Frenchf654bac2005-04-28 22:41:04 -07002978/* BB fix tabs in this function FIXME BB */
2979int
2980CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002981 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002982{
Steve French50c2f752007-07-13 00:33:32 +00002983 int rc = 0;
2984 struct smb_t2_qfi_req *pSMB = NULL;
2985 struct smb_t2_qfi_rsp *pSMBr = NULL;
2986 int bytes_returned;
2987 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002988
Steve French790fe572007-07-07 19:25:05 +00002989 cFYI(1, ("In GetExtAttr"));
2990 if (tcon == NULL)
2991 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002992
2993GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002994 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2995 (void **) &pSMBr);
2996 if (rc)
2997 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002998
Steve Frenchad7a2922008-02-07 23:25:02 +00002999 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003000 pSMB->t2.TotalDataCount = 0;
3001 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3002 /* BB find exact max data count below from sess structure BB */
3003 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3004 pSMB->t2.MaxSetupCount = 0;
3005 pSMB->t2.Reserved = 0;
3006 pSMB->t2.Flags = 0;
3007 pSMB->t2.Timeout = 0;
3008 pSMB->t2.Reserved2 = 0;
3009 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3010 Fid) - 4);
3011 pSMB->t2.DataCount = 0;
3012 pSMB->t2.DataOffset = 0;
3013 pSMB->t2.SetupCount = 1;
3014 pSMB->t2.Reserved3 = 0;
3015 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3016 byte_count = params + 1 /* pad */ ;
3017 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3018 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3019 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3020 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003021 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003022 pSMB->hdr.smb_buf_length += byte_count;
3023 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003024
Steve French790fe572007-07-07 19:25:05 +00003025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3027 if (rc) {
3028 cFYI(1, ("error %d in GetExtAttr", rc));
3029 } else {
3030 /* decode response */
3031 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3032 if (rc || (pSMBr->ByteCount < 2))
3033 /* BB also check enough total bytes returned */
3034 /* If rc should we check for EOPNOSUPP and
3035 disable the srvino flag? or in caller? */
3036 rc = -EIO; /* bad smb */
3037 else {
3038 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3039 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3040 struct file_chattr_info *pfinfo;
3041 /* BB Do we need a cast or hash here ? */
3042 if (count != 16) {
3043 cFYI(1, ("Illegal size ret in GetExtAttr"));
3044 rc = -EIO;
3045 goto GetExtAttrOut;
3046 }
3047 pfinfo = (struct file_chattr_info *)
3048 (data_offset + (char *) &pSMBr->hdr.Protocol);
3049 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003050 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003051 }
3052 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003053GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003054 cifs_buf_release(pSMB);
3055 if (rc == -EAGAIN)
3056 goto GetExtAttrRetry;
3057 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003058}
3059
Steve Frenchf654bac2005-04-28 22:41:04 -07003060#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061
Steve French297647c2007-10-12 04:11:59 +00003062#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003063/* Get Security Descriptor (by handle) from remote server for a file or dir */
3064int
3065CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003066 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003067{
3068 int rc = 0;
3069 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003070 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003071 struct kvec iov[1];
3072
3073 cFYI(1, ("GetCifsACL"));
3074
Steve French630f3f0c2007-10-25 21:17:17 +00003075 *pbuflen = 0;
3076 *acl_inf = NULL;
3077
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003078 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003079 8 /* parm len */, tcon, (void **) &pSMB);
3080 if (rc)
3081 return rc;
3082
3083 pSMB->MaxParameterCount = cpu_to_le32(4);
3084 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3085 pSMB->MaxSetupCount = 0;
3086 pSMB->Fid = fid; /* file handle always le */
3087 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3088 CIFS_ACL_DACL);
3089 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3090 pSMB->hdr.smb_buf_length += 11;
3091 iov[0].iov_base = (char *)pSMB;
3092 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3093
Steve Frencha761ac52007-10-18 21:45:27 +00003094 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003095 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003096 cifs_stats_inc(&tcon->num_acl_get);
3097 if (rc) {
3098 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3099 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003100 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003101 __u32 parm_len;
3102 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003103 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003104 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003105
3106/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003107 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003108 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003109 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003110 goto qsec_out;
3111 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3112
Steve French630f3f0c2007-10-25 21:17:17 +00003113 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003114
3115 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3116 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003117 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003118 goto qsec_out;
3119 }
3120
3121/* BB check that data area is minimum length and as big as acl_len */
3122
Steve Frenchaf6f4612007-10-16 18:40:37 +00003123 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003124 if (acl_len != *pbuflen) {
3125 cERROR(1, ("acl length %d does not match %d",
3126 acl_len, *pbuflen));
3127 if (*pbuflen > acl_len)
3128 *pbuflen = acl_len;
3129 }
Steve French0a4b92c2006-01-12 15:44:21 -08003130
Steve French630f3f0c2007-10-25 21:17:17 +00003131 /* check if buffer is big enough for the acl
3132 header followed by the smallest SID */
3133 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3134 (*pbuflen >= 64 * 1024)) {
3135 cERROR(1, ("bad acl length %d", *pbuflen));
3136 rc = -EINVAL;
3137 *pbuflen = 0;
3138 } else {
3139 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3140 if (*acl_inf == NULL) {
3141 *pbuflen = 0;
3142 rc = -ENOMEM;
3143 }
3144 memcpy(*acl_inf, pdata, *pbuflen);
3145 }
Steve French0a4b92c2006-01-12 15:44:21 -08003146 }
3147qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003148 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003149 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003150 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003151 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003152/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003153 return rc;
3154}
Steve French97837582007-12-31 07:47:21 +00003155
3156int
3157CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3158 struct cifs_ntsd *pntsd, __u32 acllen)
3159{
3160 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3161 int rc = 0;
3162 int bytes_returned = 0;
3163 SET_SEC_DESC_REQ *pSMB = NULL;
3164 NTRANSACT_RSP *pSMBr = NULL;
3165
3166setCifsAclRetry:
3167 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3168 (void **) &pSMBr);
3169 if (rc)
3170 return (rc);
3171
3172 pSMB->MaxSetupCount = 0;
3173 pSMB->Reserved = 0;
3174
3175 param_count = 8;
3176 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3177 data_count = acllen;
3178 data_offset = param_offset + param_count;
3179 byte_count = 3 /* pad */ + param_count;
3180
3181 pSMB->DataCount = cpu_to_le32(data_count);
3182 pSMB->TotalDataCount = pSMB->DataCount;
3183 pSMB->MaxParameterCount = cpu_to_le32(4);
3184 pSMB->MaxDataCount = cpu_to_le32(16384);
3185 pSMB->ParameterCount = cpu_to_le32(param_count);
3186 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3187 pSMB->TotalParameterCount = pSMB->ParameterCount;
3188 pSMB->DataOffset = cpu_to_le32(data_offset);
3189 pSMB->SetupCount = 0;
3190 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3191 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3192
3193 pSMB->Fid = fid; /* file handle always le */
3194 pSMB->Reserved2 = 0;
3195 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3196
3197 if (pntsd && acllen) {
3198 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3199 (char *) pntsd,
3200 acllen);
3201 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3202
3203 } else
3204 pSMB->hdr.smb_buf_length += byte_count;
3205
3206 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3207 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3208
3209 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3210 if (rc)
3211 cFYI(1, ("Set CIFS ACL returned %d", rc));
3212 cifs_buf_release(pSMB);
3213
3214 if (rc == -EAGAIN)
3215 goto setCifsAclRetry;
3216
3217 return (rc);
3218}
3219
Steve French297647c2007-10-12 04:11:59 +00003220#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003221
Steve French6b8edfe2005-08-23 20:26:03 -07003222/* Legacy Query Path Information call for lookup to old servers such
3223 as Win9x/WinME */
3224int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003225 const unsigned char *searchName,
3226 FILE_ALL_INFO *pFinfo,
3227 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003228{
Steve Frenchad7a2922008-02-07 23:25:02 +00003229 QUERY_INFORMATION_REQ *pSMB;
3230 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003231 int rc = 0;
3232 int bytes_returned;
3233 int name_len;
3234
Steve French50c2f752007-07-13 00:33:32 +00003235 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003236QInfRetry:
3237 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003238 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003239 if (rc)
3240 return rc;
3241
3242 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3243 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003244 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3245 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003246 name_len++; /* trailing null */
3247 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003248 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003249 name_len = strnlen(searchName, PATH_MAX);
3250 name_len++; /* trailing null */
3251 strncpy(pSMB->FileName, searchName, name_len);
3252 }
3253 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003254 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003255 pSMB->hdr.smb_buf_length += (__u16) name_len;
3256 pSMB->ByteCount = cpu_to_le16(name_len);
3257
3258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003259 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003260 if (rc) {
3261 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003262 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003263 struct timespec ts;
3264 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003265
3266 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003267 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003268 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003269 ts.tv_nsec = 0;
3270 ts.tv_sec = time;
3271 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003272 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003273 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3274 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003275 pFinfo->AllocationSize =
3276 cpu_to_le64(le32_to_cpu(pSMBr->size));
3277 pFinfo->EndOfFile = pFinfo->AllocationSize;
3278 pFinfo->Attributes =
3279 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003280 } else
3281 rc = -EIO; /* bad buffer passed in */
3282
3283 cifs_buf_release(pSMB);
3284
3285 if (rc == -EAGAIN)
3286 goto QInfRetry;
3287
3288 return rc;
3289}
3290
3291
3292
3293
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294int
3295CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3296 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003297 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003298 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003299 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003300{
3301/* level 263 SMB_QUERY_FILE_ALL_INFO */
3302 TRANSACTION2_QPI_REQ *pSMB = NULL;
3303 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3304 int rc = 0;
3305 int bytes_returned;
3306 int name_len;
3307 __u16 params, byte_count;
3308
3309/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3310QPathInfoRetry:
3311 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3312 (void **) &pSMBr);
3313 if (rc)
3314 return rc;
3315
3316 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3317 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003318 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003319 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320 name_len++; /* trailing null */
3321 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003322 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 name_len = strnlen(searchName, PATH_MAX);
3324 name_len++; /* trailing null */
3325 strncpy(pSMB->FileName, searchName, name_len);
3326 }
3327
Steve French50c2f752007-07-13 00:33:32 +00003328 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 pSMB->TotalDataCount = 0;
3330 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003331 /* BB find exact max SMB PDU from sess structure BB */
3332 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 pSMB->MaxSetupCount = 0;
3334 pSMB->Reserved = 0;
3335 pSMB->Flags = 0;
3336 pSMB->Timeout = 0;
3337 pSMB->Reserved2 = 0;
3338 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003339 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 pSMB->DataCount = 0;
3341 pSMB->DataOffset = 0;
3342 pSMB->SetupCount = 1;
3343 pSMB->Reserved3 = 0;
3344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3345 byte_count = params + 1 /* pad */ ;
3346 pSMB->TotalParameterCount = cpu_to_le16(params);
3347 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003348 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003349 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3350 else
3351 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 pSMB->Reserved4 = 0;
3353 pSMB->hdr.smb_buf_length += byte_count;
3354 pSMB->ByteCount = cpu_to_le16(byte_count);
3355
3356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3358 if (rc) {
3359 cFYI(1, ("Send error in QPathInfo = %d", rc));
3360 } else { /* decode response */
3361 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3362
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003363 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3364 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003365 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003367 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003368 rc = -EIO; /* 24 or 26 expected but we do not read
3369 last field */
3370 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003371 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003373
3374 /* On legacy responses we do not read the last field,
3375 EAsize, fortunately since it varies by subdialect and
3376 also note it differs on Set vs. Get, ie two bytes or 4
3377 bytes depending but we don't care here */
3378 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003379 size = sizeof(FILE_INFO_STANDARD);
3380 else
3381 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 memcpy((char *) pFindData,
3383 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003384 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 } else
3386 rc = -ENOMEM;
3387 }
3388 cifs_buf_release(pSMB);
3389 if (rc == -EAGAIN)
3390 goto QPathInfoRetry;
3391
3392 return rc;
3393}
3394
3395int
3396CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3397 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003398 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003399 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400{
3401/* SMB_QUERY_FILE_UNIX_BASIC */
3402 TRANSACTION2_QPI_REQ *pSMB = NULL;
3403 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3404 int rc = 0;
3405 int bytes_returned = 0;
3406 int name_len;
3407 __u16 params, byte_count;
3408
3409 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3410UnixQPathInfoRetry:
3411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3412 (void **) &pSMBr);
3413 if (rc)
3414 return rc;
3415
3416 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3417 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003418 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003419 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 name_len++; /* trailing null */
3421 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003422 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 name_len = strnlen(searchName, PATH_MAX);
3424 name_len++; /* trailing null */
3425 strncpy(pSMB->FileName, searchName, name_len);
3426 }
3427
Steve French50c2f752007-07-13 00:33:32 +00003428 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 pSMB->TotalDataCount = 0;
3430 pSMB->MaxParameterCount = cpu_to_le16(2);
3431 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003432 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 pSMB->MaxSetupCount = 0;
3434 pSMB->Reserved = 0;
3435 pSMB->Flags = 0;
3436 pSMB->Timeout = 0;
3437 pSMB->Reserved2 = 0;
3438 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003439 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 pSMB->DataCount = 0;
3441 pSMB->DataOffset = 0;
3442 pSMB->SetupCount = 1;
3443 pSMB->Reserved3 = 0;
3444 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3445 byte_count = params + 1 /* pad */ ;
3446 pSMB->TotalParameterCount = cpu_to_le16(params);
3447 pSMB->ParameterCount = pSMB->TotalParameterCount;
3448 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3449 pSMB->Reserved4 = 0;
3450 pSMB->hdr.smb_buf_length += byte_count;
3451 pSMB->ByteCount = cpu_to_le16(byte_count);
3452
3453 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3454 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3455 if (rc) {
3456 cFYI(1, ("Send error in QPathInfo = %d", rc));
3457 } else { /* decode response */
3458 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3459
3460 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003461 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3462 "Unix Extensions can be disabled on mount "
3463 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 rc = -EIO; /* bad smb */
3465 } else {
3466 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3467 memcpy((char *) pFindData,
3468 (char *) &pSMBr->hdr.Protocol +
3469 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003470 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 }
3472 }
3473 cifs_buf_release(pSMB);
3474 if (rc == -EAGAIN)
3475 goto UnixQPathInfoRetry;
3476
3477 return rc;
3478}
3479
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480/* xid, tcon, searchName and codepage are input parms, rest are returned */
3481int
3482CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003483 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003485 __u16 *pnetfid,
3486 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487{
3488/* level 257 SMB_ */
3489 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3490 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003491 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492 int rc = 0;
3493 int bytes_returned = 0;
3494 int name_len;
3495 __u16 params, byte_count;
3496
Steve French50c2f752007-07-13 00:33:32 +00003497 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498
3499findFirstRetry:
3500 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3501 (void **) &pSMBr);
3502 if (rc)
3503 return rc;
3504
3505 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3506 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003507 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003508 PATH_MAX, nls_codepage, remap);
3509 /* We can not add the asterik earlier in case
3510 it got remapped to 0xF03A as if it were part of the
3511 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003513 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003514 pSMB->FileName[name_len+1] = 0;
3515 pSMB->FileName[name_len+2] = '*';
3516 pSMB->FileName[name_len+3] = 0;
3517 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3519 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003520 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 } else { /* BB add check for overrun of SMB buf BB */
3522 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003524 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 free buffer exit; BB */
3526 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003527 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003528 pSMB->FileName[name_len+1] = '*';
3529 pSMB->FileName[name_len+2] = 0;
3530 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 }
3532
3533 params = 12 + name_len /* includes null */ ;
3534 pSMB->TotalDataCount = 0; /* no EAs */
3535 pSMB->MaxParameterCount = cpu_to_le16(10);
3536 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3537 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3538 pSMB->MaxSetupCount = 0;
3539 pSMB->Reserved = 0;
3540 pSMB->Flags = 0;
3541 pSMB->Timeout = 0;
3542 pSMB->Reserved2 = 0;
3543 byte_count = params + 1 /* pad */ ;
3544 pSMB->TotalParameterCount = cpu_to_le16(params);
3545 pSMB->ParameterCount = pSMB->TotalParameterCount;
3546 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003547 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3548 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 pSMB->DataCount = 0;
3550 pSMB->DataOffset = 0;
3551 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3552 pSMB->Reserved3 = 0;
3553 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3554 pSMB->SearchAttributes =
3555 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3556 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003557 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3558 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003559 CIFS_SEARCH_RETURN_RESUME);
3560 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3561
3562 /* BB what should we set StorageType to? Does it matter? BB */
3563 pSMB->SearchStorageType = 0;
3564 pSMB->hdr.smb_buf_length += byte_count;
3565 pSMB->ByteCount = cpu_to_le16(byte_count);
3566
3567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003569 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
Steve French88274812006-03-09 22:21:45 +00003571 if (rc) {/* BB add logic to retry regular search if Unix search
3572 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573 /* BB Add code to handle unsupported level rc */
3574 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003575
Steve French88274812006-03-09 22:21:45 +00003576 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
3578 /* BB eventually could optimize out free and realloc of buf */
3579 /* for this case */
3580 if (rc == -EAGAIN)
3581 goto findFirstRetry;
3582 } else { /* decode response */
3583 /* BB remember to free buffer if error BB */
3584 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003585 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003586 unsigned int lnoff;
3587
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003589 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 else
Steve French4b18f2a2008-04-29 00:06:05 +00003591 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592
3593 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003594 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003595 psrch_inf->srch_entries_start =
3596 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3599 le16_to_cpu(pSMBr->t2.ParameterOffset));
3600
Steve French790fe572007-07-07 19:25:05 +00003601 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003602 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 else
Steve French4b18f2a2008-04-29 00:06:05 +00003604 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605
Steve French50c2f752007-07-13 00:33:32 +00003606 psrch_inf->entries_in_buffer =
3607 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003608 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003610 lnoff = le16_to_cpu(parms->LastNameOffset);
3611 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3612 lnoff) {
3613 cERROR(1, ("ignoring corrupt resume name"));
3614 psrch_inf->last_entry = NULL;
3615 return rc;
3616 }
3617
Steve French0752f152008-10-07 20:03:33 +00003618 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003619 lnoff;
3620
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621 *pnetfid = parms->SearchHandle;
3622 } else {
3623 cifs_buf_release(pSMB);
3624 }
3625 }
3626
3627 return rc;
3628}
3629
3630int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003631 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632{
3633 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3634 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003635 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 char *response_data;
3637 int rc = 0;
3638 int bytes_returned, name_len;
3639 __u16 params, byte_count;
3640
3641 cFYI(1, ("In FindNext"));
3642
Steve French4b18f2a2008-04-29 00:06:05 +00003643 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 return -ENOENT;
3645
3646 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3647 (void **) &pSMBr);
3648 if (rc)
3649 return rc;
3650
Steve French50c2f752007-07-13 00:33:32 +00003651 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003652 byte_count = 0;
3653 pSMB->TotalDataCount = 0; /* no EAs */
3654 pSMB->MaxParameterCount = cpu_to_le16(8);
3655 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003656 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3657 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 pSMB->MaxSetupCount = 0;
3659 pSMB->Reserved = 0;
3660 pSMB->Flags = 0;
3661 pSMB->Timeout = 0;
3662 pSMB->Reserved2 = 0;
3663 pSMB->ParameterOffset = cpu_to_le16(
3664 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3665 pSMB->DataCount = 0;
3666 pSMB->DataOffset = 0;
3667 pSMB->SetupCount = 1;
3668 pSMB->Reserved3 = 0;
3669 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3670 pSMB->SearchHandle = searchHandle; /* always kept as le */
3671 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003672 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3674 pSMB->ResumeKey = psrch_inf->resume_key;
3675 pSMB->SearchFlags =
3676 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3677
3678 name_len = psrch_inf->resume_name_len;
3679 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003680 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3682 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003683 /* 14 byte parm len above enough for 2 byte null terminator */
3684 pSMB->ResumeFileName[name_len] = 0;
3685 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 } else {
3687 rc = -EINVAL;
3688 goto FNext2_err_exit;
3689 }
3690 byte_count = params + 1 /* pad */ ;
3691 pSMB->TotalParameterCount = cpu_to_le16(params);
3692 pSMB->ParameterCount = pSMB->TotalParameterCount;
3693 pSMB->hdr.smb_buf_length += byte_count;
3694 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003695
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3697 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003698 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699 if (rc) {
3700 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003701 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003702 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003703 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 } else
3705 cFYI(1, ("FindNext returned = %d", rc));
3706 } else { /* decode response */
3707 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003708
Steve French790fe572007-07-07 19:25:05 +00003709 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003710 unsigned int lnoff;
3711
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 /* BB fixme add lock for file (srch_info) struct here */
3713 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003714 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 else
Steve French4b18f2a2008-04-29 00:06:05 +00003716 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 response_data = (char *) &pSMBr->hdr.Protocol +
3718 le16_to_cpu(pSMBr->t2.ParameterOffset);
3719 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3720 response_data = (char *)&pSMBr->hdr.Protocol +
3721 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003722 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003723 cifs_small_buf_release(
3724 psrch_inf->ntwrk_buf_start);
3725 else
3726 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 psrch_inf->srch_entries_start = response_data;
3728 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003729 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003730 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003731 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 else
Steve French4b18f2a2008-04-29 00:06:05 +00003733 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003734 psrch_inf->entries_in_buffer =
3735 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 psrch_inf->index_of_last_entry +=
3737 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003738 lnoff = le16_to_cpu(parms->LastNameOffset);
3739 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3740 lnoff) {
3741 cERROR(1, ("ignoring corrupt resume name"));
3742 psrch_inf->last_entry = NULL;
3743 return rc;
3744 } else
3745 psrch_inf->last_entry =
3746 psrch_inf->srch_entries_start + lnoff;
3747
Steve French50c2f752007-07-13 00:33:32 +00003748/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3749 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
3751 /* BB fixme add unlock here */
3752 }
3753
3754 }
3755
3756 /* BB On error, should we leave previous search buf (and count and
3757 last entry fields) intact or free the previous one? */
3758
3759 /* Note: On -EAGAIN error only caller can retry on handle based calls
3760 since file handle passed in no longer valid */
3761FNext2_err_exit:
3762 if (rc != 0)
3763 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 return rc;
3765}
3766
3767int
Steve French50c2f752007-07-13 00:33:32 +00003768CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3769 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770{
3771 int rc = 0;
3772 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773
3774 cFYI(1, ("In CIFSSMBFindClose"));
3775 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3776
3777 /* no sense returning error if session restarted
3778 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003779 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 return 0;
3781 if (rc)
3782 return rc;
3783
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 pSMB->FileID = searchHandle;
3785 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003786 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003787 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003789
Steve Frencha45443472005-08-24 13:59:35 -07003790 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791
3792 /* Since session is dead, search handle closed on server already */
3793 if (rc == -EAGAIN)
3794 rc = 0;
3795
3796 return rc;
3797}
3798
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799int
3800CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003801 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003802 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003803 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804{
3805 int rc = 0;
3806 TRANSACTION2_QPI_REQ *pSMB = NULL;
3807 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3808 int name_len, bytes_returned;
3809 __u16 params, byte_count;
3810
Steve French50c2f752007-07-13 00:33:32 +00003811 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003812 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003813 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814
3815GetInodeNumberRetry:
3816 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003817 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 if (rc)
3819 return rc;
3820
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3822 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003823 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003824 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 name_len++; /* trailing null */
3826 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003827 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 name_len = strnlen(searchName, PATH_MAX);
3829 name_len++; /* trailing null */
3830 strncpy(pSMB->FileName, searchName, name_len);
3831 }
3832
3833 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3834 pSMB->TotalDataCount = 0;
3835 pSMB->MaxParameterCount = cpu_to_le16(2);
3836 /* BB find exact max data count below from sess structure BB */
3837 pSMB->MaxDataCount = cpu_to_le16(4000);
3838 pSMB->MaxSetupCount = 0;
3839 pSMB->Reserved = 0;
3840 pSMB->Flags = 0;
3841 pSMB->Timeout = 0;
3842 pSMB->Reserved2 = 0;
3843 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003844 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 pSMB->DataCount = 0;
3846 pSMB->DataOffset = 0;
3847 pSMB->SetupCount = 1;
3848 pSMB->Reserved3 = 0;
3849 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3850 byte_count = params + 1 /* pad */ ;
3851 pSMB->TotalParameterCount = cpu_to_le16(params);
3852 pSMB->ParameterCount = pSMB->TotalParameterCount;
3853 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3854 pSMB->Reserved4 = 0;
3855 pSMB->hdr.smb_buf_length += byte_count;
3856 pSMB->ByteCount = cpu_to_le16(byte_count);
3857
3858 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3860 if (rc) {
3861 cFYI(1, ("error %d in QueryInternalInfo", rc));
3862 } else {
3863 /* decode response */
3864 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3865 if (rc || (pSMBr->ByteCount < 2))
3866 /* BB also check enough total bytes returned */
3867 /* If rc should we check for EOPNOSUPP and
3868 disable the srvino flag? or in caller? */
3869 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003870 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3872 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003873 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003875 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3877 rc = -EIO;
3878 goto GetInodeNumOut;
3879 }
3880 pfinfo = (struct file_internal_info *)
3881 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003882 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 }
3884 }
3885GetInodeNumOut:
3886 cifs_buf_release(pSMB);
3887 if (rc == -EAGAIN)
3888 goto GetInodeNumberRetry;
3889 return rc;
3890}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891
Igor Mammedovfec45852008-05-16 13:06:30 +04003892/* parses DFS refferal V3 structure
3893 * caller is responsible for freeing target_nodes
3894 * returns:
3895 * on success - 0
3896 * on failure - errno
3897 */
3898static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003899parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003900 unsigned int *num_of_nodes,
3901 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003902 const struct nls_table *nls_codepage, int remap,
3903 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003904{
3905 int i, rc = 0;
3906 char *data_end;
3907 bool is_unicode;
3908 struct dfs_referral_level_3 *ref;
3909
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003910 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3911 is_unicode = true;
3912 else
3913 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003914 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3915
3916 if (*num_of_nodes < 1) {
3917 cERROR(1, ("num_referrals: must be at least > 0,"
3918 "but we get num_referrals = %d\n", *num_of_nodes));
3919 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003920 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003921 }
3922
3923 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003924 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003925 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003926 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003927 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003928 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003929 }
3930
3931 /* get the upper boundary of the resp buffer */
3932 data_end = (char *)(&(pSMBr->PathConsumed)) +
3933 le16_to_cpu(pSMBr->t2.DataCount);
3934
3935 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3936 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00003937 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003938
3939 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3940 *num_of_nodes, GFP_KERNEL);
3941 if (*target_nodes == NULL) {
3942 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3943 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003944 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003945 }
3946
3947 /* collect neccessary data from referrals */
3948 for (i = 0; i < *num_of_nodes; i++) {
3949 char *temp;
3950 int max_len;
3951 struct dfs_info3_param *node = (*target_nodes)+i;
3952
Steve French0e0d2cf2009-05-01 05:27:32 +00003953 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003954 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003955 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3956 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003957 cifsConvertToUCS((__le16 *) tmp, searchName,
3958 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003959 node->path_consumed = cifs_ucs2_bytes(tmp,
3960 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04003961 nls_codepage);
3962 kfree(tmp);
3963 } else
3964 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3965
Igor Mammedovfec45852008-05-16 13:06:30 +04003966 node->server_type = le16_to_cpu(ref->ServerType);
3967 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3968
3969 /* copy DfsPath */
3970 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3971 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003972 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3973 is_unicode, nls_codepage);
Jeff Layton066ce682009-04-30 07:16:14 -04003974 if (IS_ERR(node->path_name)) {
3975 rc = PTR_ERR(node->path_name);
3976 node->path_name = NULL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003977 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003978 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003979
3980 /* copy link target UNC */
3981 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3982 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003983 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3984 is_unicode, nls_codepage);
Jeff Layton066ce682009-04-30 07:16:14 -04003985 if (IS_ERR(node->node_name)) {
3986 rc = PTR_ERR(node->node_name);
3987 node->node_name = NULL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003988 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003989 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003990 }
3991
Steve Frencha1fe78f2008-05-16 18:48:38 +00003992parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04003993 if (rc) {
3994 free_dfs_info_array(*target_nodes, *num_of_nodes);
3995 *target_nodes = NULL;
3996 *num_of_nodes = 0;
3997 }
3998 return rc;
3999}
4000
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001int
4002CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4003 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004004 struct dfs_info3_param **target_nodes,
4005 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004006 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007{
4008/* TRANS2_GET_DFS_REFERRAL */
4009 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4010 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 int rc = 0;
4012 int bytes_returned;
4013 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004015 *num_of_nodes = 0;
4016 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017
4018 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4019 if (ses == NULL)
4020 return -ENODEV;
4021getDFSRetry:
4022 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4023 (void **) &pSMBr);
4024 if (rc)
4025 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004026
4027 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004028 but should never be null here anyway */
4029 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 pSMB->hdr.Tid = ses->ipc_tid;
4031 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004032 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004034 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036
4037 if (ses->capabilities & CAP_UNICODE) {
4038 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4039 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004040 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004041 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 name_len++; /* trailing null */
4043 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004044 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 name_len = strnlen(searchName, PATH_MAX);
4046 name_len++; /* trailing null */
4047 strncpy(pSMB->RequestFileName, searchName, name_len);
4048 }
4049
Steve French790fe572007-07-07 19:25:05 +00004050 if (ses->server) {
4051 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004052 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4053 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4054 }
4055
Steve French50c2f752007-07-13 00:33:32 +00004056 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004057
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 params = 2 /* level */ + name_len /*includes null */ ;
4059 pSMB->TotalDataCount = 0;
4060 pSMB->DataCount = 0;
4061 pSMB->DataOffset = 0;
4062 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004063 /* BB find exact max SMB PDU from sess structure BB */
4064 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 pSMB->MaxSetupCount = 0;
4066 pSMB->Reserved = 0;
4067 pSMB->Flags = 0;
4068 pSMB->Timeout = 0;
4069 pSMB->Reserved2 = 0;
4070 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004071 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 pSMB->SetupCount = 1;
4073 pSMB->Reserved3 = 0;
4074 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4075 byte_count = params + 3 /* pad */ ;
4076 pSMB->ParameterCount = cpu_to_le16(params);
4077 pSMB->TotalParameterCount = pSMB->ParameterCount;
4078 pSMB->MaxReferralLevel = cpu_to_le16(3);
4079 pSMB->hdr.smb_buf_length += byte_count;
4080 pSMB->ByteCount = cpu_to_le16(byte_count);
4081
4082 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4083 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4084 if (rc) {
4085 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004086 goto GetDFSRefExit;
4087 }
4088 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004090 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004091 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004092 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004093 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004095
4096 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4097 pSMBr->ByteCount,
4098 le16_to_cpu(pSMBr->t2.DataOffset)));
4099
4100 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004101 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004102 target_nodes, nls_codepage, remap,
4103 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004104
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004106 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107
4108 if (rc == -EAGAIN)
4109 goto getDFSRetry;
4110
4111 return rc;
4112}
4113
Steve French20962432005-09-21 22:05:57 -07004114/* Query File System Info such as free space to old servers such as Win 9x */
4115int
4116SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4117{
4118/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4119 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4120 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4121 FILE_SYSTEM_ALLOC_INFO *response_data;
4122 int rc = 0;
4123 int bytes_returned = 0;
4124 __u16 params, byte_count;
4125
4126 cFYI(1, ("OldQFSInfo"));
4127oldQFSInfoRetry:
4128 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4129 (void **) &pSMBr);
4130 if (rc)
4131 return rc;
Steve French20962432005-09-21 22:05:57 -07004132
4133 params = 2; /* level */
4134 pSMB->TotalDataCount = 0;
4135 pSMB->MaxParameterCount = cpu_to_le16(2);
4136 pSMB->MaxDataCount = cpu_to_le16(1000);
4137 pSMB->MaxSetupCount = 0;
4138 pSMB->Reserved = 0;
4139 pSMB->Flags = 0;
4140 pSMB->Timeout = 0;
4141 pSMB->Reserved2 = 0;
4142 byte_count = params + 1 /* pad */ ;
4143 pSMB->TotalParameterCount = cpu_to_le16(params);
4144 pSMB->ParameterCount = pSMB->TotalParameterCount;
4145 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4146 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4147 pSMB->DataCount = 0;
4148 pSMB->DataOffset = 0;
4149 pSMB->SetupCount = 1;
4150 pSMB->Reserved3 = 0;
4151 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4152 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4153 pSMB->hdr.smb_buf_length += byte_count;
4154 pSMB->ByteCount = cpu_to_le16(byte_count);
4155
4156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4157 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4158 if (rc) {
4159 cFYI(1, ("Send error in QFSInfo = %d", rc));
4160 } else { /* decode response */
4161 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4162
4163 if (rc || (pSMBr->ByteCount < 18))
4164 rc = -EIO; /* bad smb */
4165 else {
4166 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004167 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004168 pSMBr->ByteCount, data_offset));
4169
Steve French50c2f752007-07-13 00:33:32 +00004170 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004171 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4172 FSData->f_bsize =
4173 le16_to_cpu(response_data->BytesPerSector) *
4174 le32_to_cpu(response_data->
4175 SectorsPerAllocationUnit);
4176 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004177 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004178 FSData->f_bfree = FSData->f_bavail =
4179 le32_to_cpu(response_data->FreeAllocationUnits);
4180 cFYI(1,
4181 ("Blocks: %lld Free: %lld Block size %ld",
4182 (unsigned long long)FSData->f_blocks,
4183 (unsigned long long)FSData->f_bfree,
4184 FSData->f_bsize));
4185 }
4186 }
4187 cifs_buf_release(pSMB);
4188
4189 if (rc == -EAGAIN)
4190 goto oldQFSInfoRetry;
4191
4192 return rc;
4193}
4194
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195int
Steve French737b7582005-04-28 22:41:06 -07004196CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197{
4198/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4199 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4200 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4201 FILE_SYSTEM_INFO *response_data;
4202 int rc = 0;
4203 int bytes_returned = 0;
4204 __u16 params, byte_count;
4205
4206 cFYI(1, ("In QFSInfo"));
4207QFSInfoRetry:
4208 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4209 (void **) &pSMBr);
4210 if (rc)
4211 return rc;
4212
4213 params = 2; /* level */
4214 pSMB->TotalDataCount = 0;
4215 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004216 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 pSMB->MaxSetupCount = 0;
4218 pSMB->Reserved = 0;
4219 pSMB->Flags = 0;
4220 pSMB->Timeout = 0;
4221 pSMB->Reserved2 = 0;
4222 byte_count = params + 1 /* pad */ ;
4223 pSMB->TotalParameterCount = cpu_to_le16(params);
4224 pSMB->ParameterCount = pSMB->TotalParameterCount;
4225 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004226 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 pSMB->DataCount = 0;
4228 pSMB->DataOffset = 0;
4229 pSMB->SetupCount = 1;
4230 pSMB->Reserved3 = 0;
4231 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4232 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4233 pSMB->hdr.smb_buf_length += byte_count;
4234 pSMB->ByteCount = cpu_to_le16(byte_count);
4235
4236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4237 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4238 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004239 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004241 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242
Steve French20962432005-09-21 22:05:57 -07004243 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 rc = -EIO; /* bad smb */
4245 else {
4246 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247
4248 response_data =
4249 (FILE_SYSTEM_INFO
4250 *) (((char *) &pSMBr->hdr.Protocol) +
4251 data_offset);
4252 FSData->f_bsize =
4253 le32_to_cpu(response_data->BytesPerSector) *
4254 le32_to_cpu(response_data->
4255 SectorsPerAllocationUnit);
4256 FSData->f_blocks =
4257 le64_to_cpu(response_data->TotalAllocationUnits);
4258 FSData->f_bfree = FSData->f_bavail =
4259 le64_to_cpu(response_data->FreeAllocationUnits);
4260 cFYI(1,
4261 ("Blocks: %lld Free: %lld Block size %ld",
4262 (unsigned long long)FSData->f_blocks,
4263 (unsigned long long)FSData->f_bfree,
4264 FSData->f_bsize));
4265 }
4266 }
4267 cifs_buf_release(pSMB);
4268
4269 if (rc == -EAGAIN)
4270 goto QFSInfoRetry;
4271
4272 return rc;
4273}
4274
4275int
Steve French737b7582005-04-28 22:41:06 -07004276CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277{
4278/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4279 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4280 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4281 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4282 int rc = 0;
4283 int bytes_returned = 0;
4284 __u16 params, byte_count;
4285
4286 cFYI(1, ("In QFSAttributeInfo"));
4287QFSAttributeRetry:
4288 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4289 (void **) &pSMBr);
4290 if (rc)
4291 return rc;
4292
4293 params = 2; /* level */
4294 pSMB->TotalDataCount = 0;
4295 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004296 /* BB find exact max SMB PDU from sess structure BB */
4297 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 pSMB->MaxSetupCount = 0;
4299 pSMB->Reserved = 0;
4300 pSMB->Flags = 0;
4301 pSMB->Timeout = 0;
4302 pSMB->Reserved2 = 0;
4303 byte_count = params + 1 /* pad */ ;
4304 pSMB->TotalParameterCount = cpu_to_le16(params);
4305 pSMB->ParameterCount = pSMB->TotalParameterCount;
4306 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004307 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 pSMB->DataCount = 0;
4309 pSMB->DataOffset = 0;
4310 pSMB->SetupCount = 1;
4311 pSMB->Reserved3 = 0;
4312 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4313 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4314 pSMB->hdr.smb_buf_length += byte_count;
4315 pSMB->ByteCount = cpu_to_le16(byte_count);
4316
4317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4318 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4319 if (rc) {
4320 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4321 } else { /* decode response */
4322 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4323
Steve French50c2f752007-07-13 00:33:32 +00004324 if (rc || (pSMBr->ByteCount < 13)) {
4325 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 rc = -EIO; /* bad smb */
4327 } else {
4328 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4329 response_data =
4330 (FILE_SYSTEM_ATTRIBUTE_INFO
4331 *) (((char *) &pSMBr->hdr.Protocol) +
4332 data_offset);
4333 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004334 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 }
4336 }
4337 cifs_buf_release(pSMB);
4338
4339 if (rc == -EAGAIN)
4340 goto QFSAttributeRetry;
4341
4342 return rc;
4343}
4344
4345int
Steve French737b7582005-04-28 22:41:06 -07004346CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347{
4348/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4349 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4350 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4351 FILE_SYSTEM_DEVICE_INFO *response_data;
4352 int rc = 0;
4353 int bytes_returned = 0;
4354 __u16 params, byte_count;
4355
4356 cFYI(1, ("In QFSDeviceInfo"));
4357QFSDeviceRetry:
4358 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4359 (void **) &pSMBr);
4360 if (rc)
4361 return rc;
4362
4363 params = 2; /* level */
4364 pSMB->TotalDataCount = 0;
4365 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004366 /* BB find exact max SMB PDU from sess structure BB */
4367 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368 pSMB->MaxSetupCount = 0;
4369 pSMB->Reserved = 0;
4370 pSMB->Flags = 0;
4371 pSMB->Timeout = 0;
4372 pSMB->Reserved2 = 0;
4373 byte_count = params + 1 /* pad */ ;
4374 pSMB->TotalParameterCount = cpu_to_le16(params);
4375 pSMB->ParameterCount = pSMB->TotalParameterCount;
4376 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004377 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378
4379 pSMB->DataCount = 0;
4380 pSMB->DataOffset = 0;
4381 pSMB->SetupCount = 1;
4382 pSMB->Reserved3 = 0;
4383 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4384 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4385 pSMB->hdr.smb_buf_length += byte_count;
4386 pSMB->ByteCount = cpu_to_le16(byte_count);
4387
4388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4390 if (rc) {
4391 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4392 } else { /* decode response */
4393 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4394
Steve French630f3f0c2007-10-25 21:17:17 +00004395 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 rc = -EIO; /* bad smb */
4397 else {
4398 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4399 response_data =
Steve French737b7582005-04-28 22:41:06 -07004400 (FILE_SYSTEM_DEVICE_INFO *)
4401 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 data_offset);
4403 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004404 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 }
4406 }
4407 cifs_buf_release(pSMB);
4408
4409 if (rc == -EAGAIN)
4410 goto QFSDeviceRetry;
4411
4412 return rc;
4413}
4414
4415int
Steve French737b7582005-04-28 22:41:06 -07004416CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417{
4418/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4419 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4420 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4421 FILE_SYSTEM_UNIX_INFO *response_data;
4422 int rc = 0;
4423 int bytes_returned = 0;
4424 __u16 params, byte_count;
4425
4426 cFYI(1, ("In QFSUnixInfo"));
4427QFSUnixRetry:
4428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429 (void **) &pSMBr);
4430 if (rc)
4431 return rc;
4432
4433 params = 2; /* level */
4434 pSMB->TotalDataCount = 0;
4435 pSMB->DataCount = 0;
4436 pSMB->DataOffset = 0;
4437 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004438 /* BB find exact max SMB PDU from sess structure BB */
4439 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 pSMB->MaxSetupCount = 0;
4441 pSMB->Reserved = 0;
4442 pSMB->Flags = 0;
4443 pSMB->Timeout = 0;
4444 pSMB->Reserved2 = 0;
4445 byte_count = params + 1 /* pad */ ;
4446 pSMB->ParameterCount = cpu_to_le16(params);
4447 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004448 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4449 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 pSMB->SetupCount = 1;
4451 pSMB->Reserved3 = 0;
4452 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4453 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4454 pSMB->hdr.smb_buf_length += byte_count;
4455 pSMB->ByteCount = cpu_to_le16(byte_count);
4456
4457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4459 if (rc) {
4460 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4461 } else { /* decode response */
4462 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4463
4464 if (rc || (pSMBr->ByteCount < 13)) {
4465 rc = -EIO; /* bad smb */
4466 } else {
4467 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4468 response_data =
4469 (FILE_SYSTEM_UNIX_INFO
4470 *) (((char *) &pSMBr->hdr.Protocol) +
4471 data_offset);
4472 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004473 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 }
4475 }
4476 cifs_buf_release(pSMB);
4477
4478 if (rc == -EAGAIN)
4479 goto QFSUnixRetry;
4480
4481
4482 return rc;
4483}
4484
Jeremy Allisonac670552005-06-22 17:26:35 -07004485int
Steve French45abc6e2005-06-23 13:42:03 -05004486CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004487{
4488/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4489 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4490 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4491 int rc = 0;
4492 int bytes_returned = 0;
4493 __u16 params, param_offset, offset, byte_count;
4494
4495 cFYI(1, ("In SETFSUnixInfo"));
4496SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004497 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004498 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4499 (void **) &pSMBr);
4500 if (rc)
4501 return rc;
4502
4503 params = 4; /* 2 bytes zero followed by info level. */
4504 pSMB->MaxSetupCount = 0;
4505 pSMB->Reserved = 0;
4506 pSMB->Flags = 0;
4507 pSMB->Timeout = 0;
4508 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004509 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4510 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004511 offset = param_offset + params;
4512
4513 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004514 /* BB find exact max SMB PDU from sess structure BB */
4515 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004516 pSMB->SetupCount = 1;
4517 pSMB->Reserved3 = 0;
4518 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4519 byte_count = 1 /* pad */ + params + 12;
4520
4521 pSMB->DataCount = cpu_to_le16(12);
4522 pSMB->ParameterCount = cpu_to_le16(params);
4523 pSMB->TotalDataCount = pSMB->DataCount;
4524 pSMB->TotalParameterCount = pSMB->ParameterCount;
4525 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4526 pSMB->DataOffset = cpu_to_le16(offset);
4527
4528 /* Params. */
4529 pSMB->FileNum = 0;
4530 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4531
4532 /* Data. */
4533 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4534 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4535 pSMB->ClientUnixCap = cpu_to_le64(cap);
4536
4537 pSMB->hdr.smb_buf_length += byte_count;
4538 pSMB->ByteCount = cpu_to_le16(byte_count);
4539
4540 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4541 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4542 if (rc) {
4543 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4544 } else { /* decode response */
4545 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004546 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004547 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004548 }
4549 cifs_buf_release(pSMB);
4550
4551 if (rc == -EAGAIN)
4552 goto SETFSUnixRetry;
4553
4554 return rc;
4555}
4556
4557
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558
4559int
4560CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004561 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562{
4563/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4564 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4565 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4566 FILE_SYSTEM_POSIX_INFO *response_data;
4567 int rc = 0;
4568 int bytes_returned = 0;
4569 __u16 params, byte_count;
4570
4571 cFYI(1, ("In QFSPosixInfo"));
4572QFSPosixRetry:
4573 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4574 (void **) &pSMBr);
4575 if (rc)
4576 return rc;
4577
4578 params = 2; /* level */
4579 pSMB->TotalDataCount = 0;
4580 pSMB->DataCount = 0;
4581 pSMB->DataOffset = 0;
4582 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004583 /* BB find exact max SMB PDU from sess structure BB */
4584 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 pSMB->MaxSetupCount = 0;
4586 pSMB->Reserved = 0;
4587 pSMB->Flags = 0;
4588 pSMB->Timeout = 0;
4589 pSMB->Reserved2 = 0;
4590 byte_count = params + 1 /* pad */ ;
4591 pSMB->ParameterCount = cpu_to_le16(params);
4592 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004593 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4594 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 pSMB->SetupCount = 1;
4596 pSMB->Reserved3 = 0;
4597 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4599 pSMB->hdr.smb_buf_length += byte_count;
4600 pSMB->ByteCount = cpu_to_le16(byte_count);
4601
4602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4604 if (rc) {
4605 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4606 } else { /* decode response */
4607 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4608
4609 if (rc || (pSMBr->ByteCount < 13)) {
4610 rc = -EIO; /* bad smb */
4611 } else {
4612 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4613 response_data =
4614 (FILE_SYSTEM_POSIX_INFO
4615 *) (((char *) &pSMBr->hdr.Protocol) +
4616 data_offset);
4617 FSData->f_bsize =
4618 le32_to_cpu(response_data->BlockSize);
4619 FSData->f_blocks =
4620 le64_to_cpu(response_data->TotalBlocks);
4621 FSData->f_bfree =
4622 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004623 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 FSData->f_bavail = FSData->f_bfree;
4625 } else {
4626 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004627 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 }
Steve French790fe572007-07-07 19:25:05 +00004629 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004631 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004632 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004634 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 }
4636 }
4637 cifs_buf_release(pSMB);
4638
4639 if (rc == -EAGAIN)
4640 goto QFSPosixRetry;
4641
4642 return rc;
4643}
4644
4645
Steve French50c2f752007-07-13 00:33:32 +00004646/* We can not use write of zero bytes trick to
4647 set file size due to need for large file support. Also note that
4648 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 routine which is only needed to work around a sharing violation bug
4650 in Samba which this routine can run into */
4651
4652int
4653CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004654 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004655 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656{
4657 struct smb_com_transaction2_spi_req *pSMB = NULL;
4658 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4659 struct file_end_of_file_info *parm_data;
4660 int name_len;
4661 int rc = 0;
4662 int bytes_returned = 0;
4663 __u16 params, byte_count, data_count, param_offset, offset;
4664
4665 cFYI(1, ("In SetEOF"));
4666SetEOFRetry:
4667 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4668 (void **) &pSMBr);
4669 if (rc)
4670 return rc;
4671
4672 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4673 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004674 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004675 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 name_len++; /* trailing null */
4677 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004678 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 name_len = strnlen(fileName, PATH_MAX);
4680 name_len++; /* trailing null */
4681 strncpy(pSMB->FileName, fileName, name_len);
4682 }
4683 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004684 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004686 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 pSMB->MaxSetupCount = 0;
4688 pSMB->Reserved = 0;
4689 pSMB->Flags = 0;
4690 pSMB->Timeout = 0;
4691 pSMB->Reserved2 = 0;
4692 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004693 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004695 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004696 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4697 pSMB->InformationLevel =
4698 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4699 else
4700 pSMB->InformationLevel =
4701 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4702 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4704 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004705 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 else
4707 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004708 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 }
4710
4711 parm_data =
4712 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4713 offset);
4714 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4715 pSMB->DataOffset = cpu_to_le16(offset);
4716 pSMB->SetupCount = 1;
4717 pSMB->Reserved3 = 0;
4718 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4719 byte_count = 3 /* pad */ + params + data_count;
4720 pSMB->DataCount = cpu_to_le16(data_count);
4721 pSMB->TotalDataCount = pSMB->DataCount;
4722 pSMB->ParameterCount = cpu_to_le16(params);
4723 pSMB->TotalParameterCount = pSMB->ParameterCount;
4724 pSMB->Reserved4 = 0;
4725 pSMB->hdr.smb_buf_length += byte_count;
4726 parm_data->FileSize = cpu_to_le64(size);
4727 pSMB->ByteCount = cpu_to_le16(byte_count);
4728 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4729 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004730 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
4733 cifs_buf_release(pSMB);
4734
4735 if (rc == -EAGAIN)
4736 goto SetEOFRetry;
4737
4738 return rc;
4739}
4740
4741int
Steve French50c2f752007-07-13 00:33:32 +00004742CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004743 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744{
4745 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 char *data_offset;
4747 struct file_end_of_file_info *parm_data;
4748 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 __u16 params, param_offset, offset, byte_count, count;
4750
4751 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4752 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004753 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4754
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 if (rc)
4756 return rc;
4757
4758 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4759 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004760
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 params = 6;
4762 pSMB->MaxSetupCount = 0;
4763 pSMB->Reserved = 0;
4764 pSMB->Flags = 0;
4765 pSMB->Timeout = 0;
4766 pSMB->Reserved2 = 0;
4767 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4768 offset = param_offset + params;
4769
Steve French50c2f752007-07-13 00:33:32 +00004770 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
4772 count = sizeof(struct file_end_of_file_info);
4773 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004774 /* BB find exact max SMB PDU from sess structure BB */
4775 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 pSMB->SetupCount = 1;
4777 pSMB->Reserved3 = 0;
4778 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4779 byte_count = 3 /* pad */ + params + count;
4780 pSMB->DataCount = cpu_to_le16(count);
4781 pSMB->ParameterCount = cpu_to_le16(params);
4782 pSMB->TotalDataCount = pSMB->DataCount;
4783 pSMB->TotalParameterCount = pSMB->ParameterCount;
4784 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4785 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004786 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4787 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 pSMB->DataOffset = cpu_to_le16(offset);
4789 parm_data->FileSize = cpu_to_le64(size);
4790 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004791 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4793 pSMB->InformationLevel =
4794 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4795 else
4796 pSMB->InformationLevel =
4797 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004798 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4800 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004801 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 else
4803 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004804 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 }
4806 pSMB->Reserved4 = 0;
4807 pSMB->hdr.smb_buf_length += byte_count;
4808 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004809 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 if (rc) {
4811 cFYI(1,
4812 ("Send error in SetFileInfo (SetFileSize) = %d",
4813 rc));
4814 }
4815
Steve French50c2f752007-07-13 00:33:32 +00004816 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 since file handle passed in no longer valid */
4818
4819 return rc;
4820}
4821
Steve French50c2f752007-07-13 00:33:32 +00004822/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 an open handle, rather than by pathname - this is awkward due to
4824 potential access conflicts on the open, but it is unavoidable for these
4825 old servers since the only other choice is to go from 100 nanosecond DCE
4826 time and resort to the original setpathinfo level which takes the ancient
4827 DOS time format with 2 second granularity */
4828int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004829CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4830 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831{
4832 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 char *data_offset;
4834 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 __u16 params, param_offset, offset, byte_count, count;
4836
4837 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004838 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4839
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 if (rc)
4841 return rc;
4842
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004843 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4844 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004845
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 params = 6;
4847 pSMB->MaxSetupCount = 0;
4848 pSMB->Reserved = 0;
4849 pSMB->Flags = 0;
4850 pSMB->Timeout = 0;
4851 pSMB->Reserved2 = 0;
4852 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4853 offset = param_offset + params;
4854
Steve French50c2f752007-07-13 00:33:32 +00004855 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856
Steve French26f57362007-08-30 22:09:15 +00004857 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004859 /* BB find max SMB PDU from sess */
4860 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 pSMB->SetupCount = 1;
4862 pSMB->Reserved3 = 0;
4863 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4864 byte_count = 3 /* pad */ + params + count;
4865 pSMB->DataCount = cpu_to_le16(count);
4866 pSMB->ParameterCount = cpu_to_le16(params);
4867 pSMB->TotalDataCount = pSMB->DataCount;
4868 pSMB->TotalParameterCount = pSMB->ParameterCount;
4869 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4870 pSMB->DataOffset = cpu_to_le16(offset);
4871 pSMB->Fid = fid;
4872 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4873 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4874 else
4875 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4876 pSMB->Reserved4 = 0;
4877 pSMB->hdr.smb_buf_length += byte_count;
4878 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004879 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004880 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004881 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004882 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883
Steve French50c2f752007-07-13 00:33:32 +00004884 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 since file handle passed in no longer valid */
4886
4887 return rc;
4888}
4889
Jeff Layton6d22f092008-09-23 11:48:35 -04004890int
4891CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4892 bool delete_file, __u16 fid, __u32 pid_of_opener)
4893{
4894 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4895 char *data_offset;
4896 int rc = 0;
4897 __u16 params, param_offset, offset, byte_count, count;
4898
4899 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4900 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4901
4902 if (rc)
4903 return rc;
4904
4905 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4906 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4907
4908 params = 6;
4909 pSMB->MaxSetupCount = 0;
4910 pSMB->Reserved = 0;
4911 pSMB->Flags = 0;
4912 pSMB->Timeout = 0;
4913 pSMB->Reserved2 = 0;
4914 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4915 offset = param_offset + params;
4916
4917 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4918
4919 count = 1;
4920 pSMB->MaxParameterCount = cpu_to_le16(2);
4921 /* BB find max SMB PDU from sess */
4922 pSMB->MaxDataCount = cpu_to_le16(1000);
4923 pSMB->SetupCount = 1;
4924 pSMB->Reserved3 = 0;
4925 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4926 byte_count = 3 /* pad */ + params + count;
4927 pSMB->DataCount = cpu_to_le16(count);
4928 pSMB->ParameterCount = cpu_to_le16(params);
4929 pSMB->TotalDataCount = pSMB->DataCount;
4930 pSMB->TotalParameterCount = pSMB->ParameterCount;
4931 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4932 pSMB->DataOffset = cpu_to_le16(offset);
4933 pSMB->Fid = fid;
4934 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4935 pSMB->Reserved4 = 0;
4936 pSMB->hdr.smb_buf_length += byte_count;
4937 pSMB->ByteCount = cpu_to_le16(byte_count);
4938 *data_offset = delete_file ? 1 : 0;
4939 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4940 if (rc)
4941 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4942
4943 return rc;
4944}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945
4946int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004947CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4948 const char *fileName, const FILE_BASIC_INFO *data,
4949 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950{
4951 TRANSACTION2_SPI_REQ *pSMB = NULL;
4952 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4953 int name_len;
4954 int rc = 0;
4955 int bytes_returned = 0;
4956 char *data_offset;
4957 __u16 params, param_offset, offset, byte_count, count;
4958
4959 cFYI(1, ("In SetTimes"));
4960
4961SetTimesRetry:
4962 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4963 (void **) &pSMBr);
4964 if (rc)
4965 return rc;
4966
4967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4968 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004969 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004970 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 name_len++; /* trailing null */
4972 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004973 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 name_len = strnlen(fileName, PATH_MAX);
4975 name_len++; /* trailing null */
4976 strncpy(pSMB->FileName, fileName, name_len);
4977 }
4978
4979 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004980 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004982 /* BB find max SMB PDU from sess structure BB */
4983 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984 pSMB->MaxSetupCount = 0;
4985 pSMB->Reserved = 0;
4986 pSMB->Flags = 0;
4987 pSMB->Timeout = 0;
4988 pSMB->Reserved2 = 0;
4989 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004990 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 offset = param_offset + params;
4992 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4993 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4994 pSMB->DataOffset = cpu_to_le16(offset);
4995 pSMB->SetupCount = 1;
4996 pSMB->Reserved3 = 0;
4997 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4998 byte_count = 3 /* pad */ + params + count;
4999
5000 pSMB->DataCount = cpu_to_le16(count);
5001 pSMB->ParameterCount = cpu_to_le16(params);
5002 pSMB->TotalDataCount = pSMB->DataCount;
5003 pSMB->TotalParameterCount = pSMB->ParameterCount;
5004 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5005 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5006 else
5007 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5008 pSMB->Reserved4 = 0;
5009 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005010 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 pSMB->ByteCount = cpu_to_le16(byte_count);
5012 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5013 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005014 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016
5017 cifs_buf_release(pSMB);
5018
5019 if (rc == -EAGAIN)
5020 goto SetTimesRetry;
5021
5022 return rc;
5023}
5024
5025/* Can not be used to set time stamps yet (due to old DOS time format) */
5026/* Can be used to set attributes */
5027#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5028 handling it anyway and NT4 was what we thought it would be needed for
5029 Do not delete it until we prove whether needed for Win9x though */
5030int
5031CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5032 __u16 dos_attrs, const struct nls_table *nls_codepage)
5033{
5034 SETATTR_REQ *pSMB = NULL;
5035 SETATTR_RSP *pSMBr = NULL;
5036 int rc = 0;
5037 int bytes_returned;
5038 int name_len;
5039
5040 cFYI(1, ("In SetAttrLegacy"));
5041
5042SetAttrLgcyRetry:
5043 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5044 (void **) &pSMBr);
5045 if (rc)
5046 return rc;
5047
5048 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5049 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005050 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 PATH_MAX, nls_codepage);
5052 name_len++; /* trailing null */
5053 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005054 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 name_len = strnlen(fileName, PATH_MAX);
5056 name_len++; /* trailing null */
5057 strncpy(pSMB->fileName, fileName, name_len);
5058 }
5059 pSMB->attr = cpu_to_le16(dos_attrs);
5060 pSMB->BufferFormat = 0x04;
5061 pSMB->hdr.smb_buf_length += name_len + 1;
5062 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5063 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5064 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005065 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067
5068 cifs_buf_release(pSMB);
5069
5070 if (rc == -EAGAIN)
5071 goto SetAttrLgcyRetry;
5072
5073 return rc;
5074}
5075#endif /* temporarily unneeded SetAttr legacy function */
5076
5077int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005078CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005079 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005080 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081{
5082 TRANSACTION2_SPI_REQ *pSMB = NULL;
5083 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5084 int name_len;
5085 int rc = 0;
5086 int bytes_returned = 0;
5087 FILE_UNIX_BASIC_INFO *data_offset;
5088 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005089 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090
5091 cFYI(1, ("In SetUID/GID/Mode"));
5092setPermsRetry:
5093 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5094 (void **) &pSMBr);
5095 if (rc)
5096 return rc;
5097
5098 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5099 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005100 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005101 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102 name_len++; /* trailing null */
5103 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005104 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 name_len = strnlen(fileName, PATH_MAX);
5106 name_len++; /* trailing null */
5107 strncpy(pSMB->FileName, fileName, name_len);
5108 }
5109
5110 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005111 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005113 /* BB find max SMB PDU from sess structure BB */
5114 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 pSMB->MaxSetupCount = 0;
5116 pSMB->Reserved = 0;
5117 pSMB->Flags = 0;
5118 pSMB->Timeout = 0;
5119 pSMB->Reserved2 = 0;
5120 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005121 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 offset = param_offset + params;
5123 data_offset =
5124 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5125 offset);
5126 memset(data_offset, 0, count);
5127 pSMB->DataOffset = cpu_to_le16(offset);
5128 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5129 pSMB->SetupCount = 1;
5130 pSMB->Reserved3 = 0;
5131 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5132 byte_count = 3 /* pad */ + params + count;
5133 pSMB->ParameterCount = cpu_to_le16(params);
5134 pSMB->DataCount = cpu_to_le16(count);
5135 pSMB->TotalParameterCount = pSMB->ParameterCount;
5136 pSMB->TotalDataCount = pSMB->DataCount;
5137 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5138 pSMB->Reserved4 = 0;
5139 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005140 /* Samba server ignores set of file size to zero due to bugs in some
5141 older clients, but we should be precise - we use SetFileSize to
5142 set file size and do not want to truncate file size to zero
5143 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005144 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005145 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5146 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5147 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5148 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5149 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5150 data_offset->Uid = cpu_to_le64(args->uid);
5151 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005153 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5154 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005156
Steve French790fe572007-07-07 19:25:05 +00005157 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005159 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005161 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005163 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005165 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005167 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005169 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5171
5172
5173 pSMB->ByteCount = cpu_to_le16(byte_count);
5174 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5175 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005176 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178
Steve French0d817bc2008-05-22 02:02:03 +00005179 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180 if (rc == -EAGAIN)
5181 goto setPermsRetry;
5182 return rc;
5183}
5184
Steve French50c2f752007-07-13 00:33:32 +00005185int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005186 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005187 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005188 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189{
5190 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005191 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5192 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005193 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 int bytes_returned;
5195
Steve French50c2f752007-07-13 00:33:32 +00005196 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005198 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005199 if (rc)
5200 return rc;
5201
5202 pSMB->TotalParameterCount = 0 ;
5203 pSMB->TotalDataCount = 0;
5204 pSMB->MaxParameterCount = cpu_to_le32(2);
5205 /* BB find exact data count max from sess structure BB */
5206 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005207/* BB VERIFY verify which is correct for above BB */
5208 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5209 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5210
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 pSMB->MaxSetupCount = 4;
5212 pSMB->Reserved = 0;
5213 pSMB->ParameterOffset = 0;
5214 pSMB->DataCount = 0;
5215 pSMB->DataOffset = 0;
5216 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5217 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5218 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005219 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5221 pSMB->Reserved2 = 0;
5222 pSMB->CompletionFilter = cpu_to_le32(filter);
5223 pSMB->Fid = netfid; /* file handle always le */
5224 pSMB->ByteCount = 0;
5225
5226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005227 (struct smb_hdr *)pSMBr, &bytes_returned,
5228 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 if (rc) {
5230 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005231 } else {
5232 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005233 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005234 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005235 sizeof(struct dir_notify_req),
5236 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005237 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005238 dnotify_req->Pid = pSMB->hdr.Pid;
5239 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5240 dnotify_req->Mid = pSMB->hdr.Mid;
5241 dnotify_req->Tid = pSMB->hdr.Tid;
5242 dnotify_req->Uid = pSMB->hdr.Uid;
5243 dnotify_req->netfid = netfid;
5244 dnotify_req->pfile = pfile;
5245 dnotify_req->filter = filter;
5246 dnotify_req->multishot = multishot;
5247 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005248 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005249 &GlobalDnotifyReqList);
5250 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005251 } else
Steve French47c786e2005-10-11 20:03:18 -07005252 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 }
5254 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005255 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256}
5257#ifdef CONFIG_CIFS_XATTR
5258ssize_t
5259CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5260 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005261 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005262 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263{
5264 /* BB assumes one setup word */
5265 TRANSACTION2_QPI_REQ *pSMB = NULL;
5266 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5267 int rc = 0;
5268 int bytes_returned;
5269 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005270 struct fea *temp_fea;
5271 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 __u16 params, byte_count;
5273
5274 cFYI(1, ("In Query All EAs path %s", searchName));
5275QAllEAsRetry:
5276 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5277 (void **) &pSMBr);
5278 if (rc)
5279 return rc;
5280
5281 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5282 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005283 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005284 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 name_len++; /* trailing null */
5286 name_len *= 2;
5287 } else { /* BB improve the check for buffer overruns BB */
5288 name_len = strnlen(searchName, PATH_MAX);
5289 name_len++; /* trailing null */
5290 strncpy(pSMB->FileName, searchName, name_len);
5291 }
5292
Steve French50c2f752007-07-13 00:33:32 +00005293 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 pSMB->TotalDataCount = 0;
5295 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005296 /* BB find exact max SMB PDU from sess structure BB */
5297 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 pSMB->MaxSetupCount = 0;
5299 pSMB->Reserved = 0;
5300 pSMB->Flags = 0;
5301 pSMB->Timeout = 0;
5302 pSMB->Reserved2 = 0;
5303 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005304 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 pSMB->DataCount = 0;
5306 pSMB->DataOffset = 0;
5307 pSMB->SetupCount = 1;
5308 pSMB->Reserved3 = 0;
5309 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5310 byte_count = params + 1 /* pad */ ;
5311 pSMB->TotalParameterCount = cpu_to_le16(params);
5312 pSMB->ParameterCount = pSMB->TotalParameterCount;
5313 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5314 pSMB->Reserved4 = 0;
5315 pSMB->hdr.smb_buf_length += byte_count;
5316 pSMB->ByteCount = cpu_to_le16(byte_count);
5317
5318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5320 if (rc) {
5321 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5322 } else { /* decode response */
5323 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5324
5325 /* BB also check enough total bytes returned */
5326 /* BB we need to improve the validity checking
5327 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005328 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 rc = -EIO; /* bad smb */
5330 /* else if (pFindData){
5331 memcpy((char *) pFindData,
5332 (char *) &pSMBr->hdr.Protocol +
5333 data_offset, kl);
5334 }*/ else {
5335 /* check that length of list is not more than bcc */
5336 /* check that each entry does not go beyond length
5337 of list */
5338 /* check that each element of each entry does not
5339 go beyond end of list */
5340 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005341 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 rc = 0;
5343 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005344 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 ea_response_data = (struct fealist *)
5346 (((char *) &pSMBr->hdr.Protocol) +
5347 data_offset);
5348 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005349 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005350 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005352 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 } else {
5354 /* account for ea list len */
5355 name_len -= 4;
5356 temp_fea = ea_response_data->list;
5357 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005358 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 __u16 value_len;
5360 name_len -= 4;
5361 temp_ptr += 4;
5362 rc += temp_fea->name_len;
5363 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005364 rc = rc + 5 + 1;
5365 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005366 memcpy(EAData, "user.", 5);
5367 EAData += 5;
5368 memcpy(EAData, temp_ptr,
5369 temp_fea->name_len);
5370 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371 /* null terminate name */
5372 *EAData = 0;
5373 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005374 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 /* skip copy - calc size only */
5376 } else {
5377 /* stop before overrun buffer */
5378 rc = -ERANGE;
5379 break;
5380 }
5381 name_len -= temp_fea->name_len;
5382 temp_ptr += temp_fea->name_len;
5383 /* account for trailing null */
5384 name_len--;
5385 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005386 value_len =
5387 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 name_len -= value_len;
5389 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005390 /* BB check that temp_ptr is still
5391 within the SMB BB*/
5392
5393 /* no trailing null to account for
5394 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 /* go on to next EA */
5396 temp_fea = (struct fea *)temp_ptr;
5397 }
5398 }
5399 }
5400 }
Steve French0d817bc2008-05-22 02:02:03 +00005401 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 if (rc == -EAGAIN)
5403 goto QAllEAsRetry;
5404
5405 return (ssize_t)rc;
5406}
5407
Steve French50c2f752007-07-13 00:33:32 +00005408ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5409 const unsigned char *searchName, const unsigned char *ea_name,
5410 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005411 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412{
5413 TRANSACTION2_QPI_REQ *pSMB = NULL;
5414 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5415 int rc = 0;
5416 int bytes_returned;
5417 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005418 struct fea *temp_fea;
5419 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 __u16 params, byte_count;
5421
5422 cFYI(1, ("In Query EA path %s", searchName));
5423QEARetry:
5424 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5425 (void **) &pSMBr);
5426 if (rc)
5427 return rc;
5428
5429 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5430 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005431 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005432 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 name_len++; /* trailing null */
5434 name_len *= 2;
5435 } else { /* BB improve the check for buffer overruns BB */
5436 name_len = strnlen(searchName, PATH_MAX);
5437 name_len++; /* trailing null */
5438 strncpy(pSMB->FileName, searchName, name_len);
5439 }
5440
Steve French50c2f752007-07-13 00:33:32 +00005441 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 pSMB->TotalDataCount = 0;
5443 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005444 /* BB find exact max SMB PDU from sess structure BB */
5445 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 pSMB->MaxSetupCount = 0;
5447 pSMB->Reserved = 0;
5448 pSMB->Flags = 0;
5449 pSMB->Timeout = 0;
5450 pSMB->Reserved2 = 0;
5451 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005452 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005453 pSMB->DataCount = 0;
5454 pSMB->DataOffset = 0;
5455 pSMB->SetupCount = 1;
5456 pSMB->Reserved3 = 0;
5457 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5458 byte_count = params + 1 /* pad */ ;
5459 pSMB->TotalParameterCount = cpu_to_le16(params);
5460 pSMB->ParameterCount = pSMB->TotalParameterCount;
5461 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5462 pSMB->Reserved4 = 0;
5463 pSMB->hdr.smb_buf_length += byte_count;
5464 pSMB->ByteCount = cpu_to_le16(byte_count);
5465
5466 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5467 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5468 if (rc) {
5469 cFYI(1, ("Send error in Query EA = %d", rc));
5470 } else { /* decode response */
5471 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5472
5473 /* BB also check enough total bytes returned */
5474 /* BB we need to improve the validity checking
5475 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005476 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477 rc = -EIO; /* bad smb */
5478 /* else if (pFindData){
5479 memcpy((char *) pFindData,
5480 (char *) &pSMBr->hdr.Protocol +
5481 data_offset, kl);
5482 }*/ else {
5483 /* check that length of list is not more than bcc */
5484 /* check that each entry does not go beyond length
5485 of list */
5486 /* check that each element of each entry does not
5487 go beyond end of list */
5488 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005489 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 rc = -ENODATA;
5491 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005492 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 ea_response_data = (struct fealist *)
5494 (((char *) &pSMBr->hdr.Protocol) +
5495 data_offset);
5496 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005497 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005498 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005500 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 } else {
5502 /* account for ea list len */
5503 name_len -= 4;
5504 temp_fea = ea_response_data->list;
5505 temp_ptr = (char *)temp_fea;
5506 /* loop through checking if we have a matching
5507 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005508 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 __u16 value_len;
5510 name_len -= 4;
5511 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005512 value_len =
5513 le16_to_cpu(temp_fea->value_len);
5514 /* BB validate that value_len falls within SMB,
5515 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005516 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 temp_fea->name_len) == 0) {
5518 /* found a match */
5519 rc = value_len;
5520 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005521 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 memcpy(ea_value,
5523 temp_fea->name+temp_fea->name_len+1,
5524 rc);
Steve French50c2f752007-07-13 00:33:32 +00005525 /* ea values, unlike ea
5526 names, are not null
5527 terminated */
Steve French790fe572007-07-07 19:25:05 +00005528 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 /* skip copy - calc size only */
5530 } else {
Steve French50c2f752007-07-13 00:33:32 +00005531 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 rc = -ERANGE;
5533 }
5534 break;
5535 }
5536 name_len -= temp_fea->name_len;
5537 temp_ptr += temp_fea->name_len;
5538 /* account for trailing null */
5539 name_len--;
5540 temp_ptr++;
5541 name_len -= value_len;
5542 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005543 /* No trailing null to account for in
5544 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545 temp_fea = (struct fea *)temp_ptr;
5546 }
Steve French50c2f752007-07-13 00:33:32 +00005547 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548 }
5549 }
Steve French0d817bc2008-05-22 02:02:03 +00005550 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 if (rc == -EAGAIN)
5552 goto QEARetry;
5553
5554 return (ssize_t)rc;
5555}
5556
5557int
5558CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005559 const char *ea_name, const void *ea_value,
5560 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5561 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562{
5563 struct smb_com_transaction2_spi_req *pSMB = NULL;
5564 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5565 struct fealist *parm_data;
5566 int name_len;
5567 int rc = 0;
5568 int bytes_returned = 0;
5569 __u16 params, param_offset, byte_count, offset, count;
5570
5571 cFYI(1, ("In SetEA"));
5572SetEARetry:
5573 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5574 (void **) &pSMBr);
5575 if (rc)
5576 return rc;
5577
5578 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5579 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005580 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005581 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005582 name_len++; /* trailing null */
5583 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005584 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005585 name_len = strnlen(fileName, PATH_MAX);
5586 name_len++; /* trailing null */
5587 strncpy(pSMB->FileName, fileName, name_len);
5588 }
5589
5590 params = 6 + name_len;
5591
5592 /* done calculating parms using name_len of file name,
5593 now use name_len to calculate length of ea name
5594 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005595 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 name_len = 0;
5597 else
Steve French50c2f752007-07-13 00:33:32 +00005598 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005600 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005601 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005602 /* BB find max SMB PDU from sess */
5603 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005604 pSMB->MaxSetupCount = 0;
5605 pSMB->Reserved = 0;
5606 pSMB->Flags = 0;
5607 pSMB->Timeout = 0;
5608 pSMB->Reserved2 = 0;
5609 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005610 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005611 offset = param_offset + params;
5612 pSMB->InformationLevel =
5613 cpu_to_le16(SMB_SET_FILE_EA);
5614
5615 parm_data =
5616 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5617 offset);
5618 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5619 pSMB->DataOffset = cpu_to_le16(offset);
5620 pSMB->SetupCount = 1;
5621 pSMB->Reserved3 = 0;
5622 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5623 byte_count = 3 /* pad */ + params + count;
5624 pSMB->DataCount = cpu_to_le16(count);
5625 parm_data->list_len = cpu_to_le32(count);
5626 parm_data->list[0].EA_flags = 0;
5627 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005628 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005629 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005630 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005631 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 parm_data->list[0].name[name_len] = 0;
5633 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5634 /* caller ensures that ea_value_len is less than 64K but
5635 we need to ensure that it fits within the smb */
5636
Steve French50c2f752007-07-13 00:33:32 +00005637 /*BB add length check to see if it would fit in
5638 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005639 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5640 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005641 memcpy(parm_data->list[0].name+name_len+1,
5642 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643
5644 pSMB->TotalDataCount = pSMB->DataCount;
5645 pSMB->ParameterCount = cpu_to_le16(params);
5646 pSMB->TotalParameterCount = pSMB->ParameterCount;
5647 pSMB->Reserved4 = 0;
5648 pSMB->hdr.smb_buf_length += byte_count;
5649 pSMB->ByteCount = cpu_to_le16(byte_count);
5650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005652 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654
5655 cifs_buf_release(pSMB);
5656
5657 if (rc == -EAGAIN)
5658 goto SetEARetry;
5659
5660 return rc;
5661}
5662
5663#endif