blob: f15848374cfa1a8897db63c81ea6cf7e2bdacce5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchad7a2922008-02-07 23:25:02 +00004 * Copyright (C) International Business Machines Corp., 2002,2008
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000086static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000089 struct list_head *tmp;
90 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92/* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000095 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000096 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 }
98 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070099 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101}
102
Steve Frenchad7a2922008-02-07 23:25:02 +0000103/* Allocate and return pointer to an SMB request buffer, and set basic
104 SMB information in the SMB header. If the return code is zero, this
105 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000108 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000142 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000158 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000161 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700166 /* BB FIXME add code to check if wsize needs
167 update due to negotiated smb buffer size
168 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000169 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000171 /* tell server Unix caps we support */
172 if (tcon->ses->capabilities & CAP_UNIX)
173 reset_cifs_unix_caps(
174 0 /* no xid */,
175 tcon,
176 NULL /* we do not know sb */,
177 NULL /* no vol info */);
178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000181 /* Removed call to reopen open files here.
182 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700183 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Steve French50c2f752007-07-13 00:33:32 +0000185 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700186 know whether we can continue or not without
187 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000188 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 case SMB_COM_READ_ANDX:
190 case SMB_COM_WRITE_ANDX:
191 case SMB_COM_CLOSE:
192 case SMB_COM_FIND_CLOSE2:
193 case SMB_COM_LOCKING_ANDX: {
194 unload_nls(nls_codepage);
195 return -EAGAIN;
196 }
197 }
198 } else {
199 up(&tcon->ses->sesSem);
200 }
201 unload_nls(nls_codepage);
202
203 } else {
204 return -EIO;
205 }
206 }
Steve French790fe572007-07-07 19:25:05 +0000207 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 return rc;
209
210 *request_buf = cifs_small_buf_get();
211 if (*request_buf == NULL) {
212 /* BB should we add a retry in here if not a writepage? */
213 return -ENOMEM;
214 }
215
Steve French63135e02007-07-17 17:34:02 +0000216 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000217 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Steve French790fe572007-07-07 19:25:05 +0000219 if (tcon != NULL)
220 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000223}
224
Steve French12b3b8f2006-02-09 21:12:47 +0000225int
Steve French50c2f752007-07-13 00:33:32 +0000226small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000227 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000228{
229 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000230 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000231
Steve French5815449d2006-02-14 01:36:20 +0000232 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000233 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000234 return rc;
235
Steve French04fdabe2006-02-10 05:52:50 +0000236 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000237 buffer->Mid = GetNextMid(ses->server);
238 if (ses->capabilities & CAP_UNICODE)
239 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000240 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000241 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
242
243 /* uid, tid can stay at zero as set in header assemble */
244
Steve French50c2f752007-07-13 00:33:32 +0000245 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000246 this function is used after 1st of session setup requests */
247
248 return rc;
249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251/* If the return code is zero, this function must fill in request_buf pointer */
252static int
253smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
254 void **request_buf /* returned */ ,
255 void **response_buf /* returned */ )
256{
257 int rc = 0;
258
259 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
260 check for tcp and smb session status done differently
261 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000262 if (tcon) {
Steve Frenchbfb59822008-11-18 16:33:48 +0000263 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800264 /* only tree disconnect, open, and write,
265 (and ulogoff which does not have tcon)
266 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000267 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800268 (smb_command != SMB_COM_OPEN_ANDX) &&
269 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000270 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800271 smb_command));
272 return -ENODEV;
273 }
274 }
275
Steve French790fe572007-07-07 19:25:05 +0000276 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000277 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700279 /* Give Demultiplex thread up to 10 seconds to
280 reconnect, should be greater than cifs socket
281 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000282 while (tcon->ses->server->tcpStatus ==
283 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000285 (tcon->ses->server->tcpStatus ==
286 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000287 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700288 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000290 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000292 cFYI(1, ("gave up waiting on "
293 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700295 } /* else "hard" mount - keep retrying
296 until process is killed or server
297 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 } else /* TCP session is reestablished now */
299 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 nls_codepage = load_nls_default();
302 /* need to prevent multiple threads trying to
303 simultaneously reconnect the same SMB session */
304 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000305 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000306 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700307 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000308 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700310 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
311 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000316 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000318 /* tell server Unix caps we support */
319 if (tcon->ses->capabilities & CAP_UNIX)
320 reset_cifs_unix_caps(
321 0 /* no xid */,
322 tcon,
323 NULL /* do not know sb */,
324 NULL /* no vol info */);
325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Removed call to reopen open files here.
329 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700330 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Steve French50c2f752007-07-13 00:33:32 +0000332 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700333 know whether we can continue or not without
334 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000335 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 case SMB_COM_READ_ANDX:
337 case SMB_COM_WRITE_ANDX:
338 case SMB_COM_CLOSE:
339 case SMB_COM_FIND_CLOSE2:
340 case SMB_COM_LOCKING_ANDX: {
341 unload_nls(nls_codepage);
342 return -EAGAIN;
343 }
344 }
345 } else {
346 up(&tcon->ses->sesSem);
347 }
348 unload_nls(nls_codepage);
349
350 } else {
351 return -EIO;
352 }
353 }
Steve French790fe572007-07-07 19:25:05 +0000354 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356
357 *request_buf = cifs_buf_get();
358 if (*request_buf == NULL) {
359 /* BB should we add a retry in here if not a writepage? */
360 return -ENOMEM;
361 }
362 /* Although the original thought was we needed the response buf for */
363 /* potential retries of smb operations it turns out we can determine */
364 /* from the mid flags when the request buffer can be resent without */
365 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000366 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000367 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000370 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Steve French790fe572007-07-07 19:25:05 +0000372 if (tcon != NULL)
373 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return rc;
376}
377
Steve French50c2f752007-07-13 00:33:32 +0000378static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 int rc = -EINVAL;
381 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000382 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 /* check for plausible wct, bcc and t2 data and parm sizes */
385 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000386 if (pSMB->hdr.WordCount >= 10) {
387 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
389 /* check that bcc is at least as big as parms + data */
390 /* check that bcc is less than negotiated smb buffer */
391 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000392 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000393 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000394 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000396 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700397 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000399 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000400 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
402 return 0;
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405 }
406 }
Steve French50c2f752007-07-13 00:33:32 +0000407 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 sizeof(struct smb_t2_rsp) + 16);
409 return rc;
410}
411int
412CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
413{
414 NEGOTIATE_REQ *pSMB;
415 NEGOTIATE_RSP *pSMBr;
416 int rc = 0;
417 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000418 int i;
Steve French50c2f752007-07-13 00:33:32 +0000419 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000421 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100422 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Steve French790fe572007-07-07 19:25:05 +0000424 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 server = ses->server;
426 else {
427 rc = -EIO;
428 return rc;
429 }
430 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
431 (void **) &pSMB, (void **) &pSMBr);
432 if (rc)
433 return rc;
Steve French750d1152006-06-27 06:28:30 +0000434
435 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000436 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000437 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000438 else /* if override flags set only sign/seal OR them with global auth */
439 secFlags = extended_security | ses->overrideSecFlg;
440
Steve French762e5ab2007-06-28 18:41:42 +0000441 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000442
Steve French1982c342005-08-17 12:38:22 -0700443 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000444 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000445
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000446 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000447 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000448 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
449 cFYI(1, ("Kerberos only mechanism, enable extended security"));
450 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
451 }
Steve 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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-10-02 05:53:29 +0000532 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000533 } else {
Steve Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencheda3c022005-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 Frencheda3c022005-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 Frencheda3c022005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frenchb815f1e2006-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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,
2385 const unsigned char *searchName,
2386 char *symlinkinfo, const int buflen,
2387 const struct nls_table *nls_codepage)
2388{
2389/* SMB_QUERY_FILE_UNIX_LINK */
2390 TRANSACTION2_QPI_REQ *pSMB = NULL;
2391 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2392 int rc = 0;
2393 int bytes_returned;
2394 int name_len;
2395 __u16 params, byte_count;
2396
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);
2450 if (rc || (pSMBr->ByteCount < 2))
2451 /* BB also check enough total bytes returned */
2452 rc = -EIO; /* bad smb */
2453 else {
2454 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2455 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2456
2457 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2458 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002459 &pSMBr->hdr.Protocol + data_offset),
2460 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002461 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002463 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2464 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 name_len, nls_codepage);
2466 } else {
2467 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002468 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 data_offset,
2470 min_t(const int, buflen, count));
2471 }
2472 symlinkinfo[buflen] = 0;
2473 /* just in case so calling code does not go off the end of buffer */
2474 }
2475 }
2476 cifs_buf_release(pSMB);
2477 if (rc == -EAGAIN)
2478 goto querySymLinkRetry;
2479 return rc;
2480}
2481
Parag Warudkarc9489772007-10-23 18:09:48 +00002482#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002483/* Initialize NT TRANSACT SMB into small smb request buffer.
2484 This assumes that all NT TRANSACTS that we init here have
2485 total parm and data under about 400 bytes (to fit in small cifs
2486 buffer size), which is the case so far, it easily fits. NB:
2487 Setup words themselves and ByteCount
2488 MaxSetupCount (size of returned setup area) and
2489 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002490static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002491smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002492 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002493 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002494{
2495 int rc;
2496 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002497 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002498
2499 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2500 (void **)&pSMB);
2501 if (rc)
2502 return rc;
2503 *ret_buf = (void *)pSMB;
2504 pSMB->Reserved = 0;
2505 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2506 pSMB->TotalDataCount = 0;
2507 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2508 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2509 pSMB->ParameterCount = pSMB->TotalParameterCount;
2510 pSMB->DataCount = pSMB->TotalDataCount;
2511 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2512 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2513 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2514 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2515 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2516 pSMB->SubCommand = cpu_to_le16(sub_command);
2517 return 0;
2518}
2519
2520static int
Steve French50c2f752007-07-13 00:33:32 +00002521validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002522 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002523{
Steve French50c2f752007-07-13 00:33:32 +00002524 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002525 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002526 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002527
Steve French630f3f02007-10-25 21:17:17 +00002528 *pdatalen = 0;
2529 *pparmlen = 0;
2530
Steve French790fe572007-07-07 19:25:05 +00002531 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002532 return -EINVAL;
2533
2534 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2535
2536 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002537 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002538 (char *)&pSMBr->ByteCount;
2539
Steve French0a4b92c2006-01-12 15:44:21 -08002540 data_offset = le32_to_cpu(pSMBr->DataOffset);
2541 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002542 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002543 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2544
2545 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2546 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2547
2548 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002549 if (*ppparm > end_of_smb) {
2550 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002551 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002552 } else if (parm_count + *ppparm > end_of_smb) {
2553 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002554 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002555 } else if (*ppdata > end_of_smb) {
2556 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002558 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002559 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002560 *ppdata, data_count, (data_count + *ppdata),
2561 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002562 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002563 } else if (parm_count + data_count > pSMBr->ByteCount) {
2564 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002565 return -EINVAL;
2566 }
Steve French630f3f02007-10-25 21:17:17 +00002567 *pdatalen = data_count;
2568 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002569 return 0;
2570}
Parag Warudkarc9489772007-10-23 18:09:48 +00002571#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573int
2574CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2575 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002576 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 const struct nls_table *nls_codepage)
2578{
2579 int rc = 0;
2580 int bytes_returned;
2581 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002582 struct smb_com_transaction_ioctl_req *pSMB;
2583 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
2585 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2586 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2587 (void **) &pSMBr);
2588 if (rc)
2589 return rc;
2590
2591 pSMB->TotalParameterCount = 0 ;
2592 pSMB->TotalDataCount = 0;
2593 pSMB->MaxParameterCount = cpu_to_le32(2);
2594 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002595 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2596 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 pSMB->MaxSetupCount = 4;
2598 pSMB->Reserved = 0;
2599 pSMB->ParameterOffset = 0;
2600 pSMB->DataCount = 0;
2601 pSMB->DataOffset = 0;
2602 pSMB->SetupCount = 4;
2603 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2604 pSMB->ParameterCount = pSMB->TotalParameterCount;
2605 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2606 pSMB->IsFsctl = 1; /* FSCTL */
2607 pSMB->IsRootFlag = 0;
2608 pSMB->Fid = fid; /* file handle always le */
2609 pSMB->ByteCount = 0;
2610
2611 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2612 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2613 if (rc) {
2614 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2615 } else { /* decode response */
2616 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2617 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2618 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2619 /* BB also check enough total bytes returned */
2620 rc = -EIO; /* bad smb */
2621 else {
Steve French790fe572007-07-07 19:25:05 +00002622 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002623 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002624 pSMBr->ByteCount +
2625 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
Steve French50c2f752007-07-13 00:33:32 +00002627 struct reparse_data *reparse_buf =
2628 (struct reparse_data *)
2629 ((char *)&pSMBr->hdr.Protocol
2630 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002631 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 rc = -EIO;
2633 goto qreparse_out;
2634 }
Steve French790fe572007-07-07 19:25:05 +00002635 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 reparse_buf->TargetNameOffset +
2637 reparse_buf->TargetNameLen) >
2638 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002639 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 rc = -EIO;
2641 goto qreparse_out;
2642 }
Steve French50c2f752007-07-13 00:33:32 +00002643
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2645 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002646 (reparse_buf->LinkNamesBuf +
2647 reparse_buf->TargetNameOffset),
2648 min(buflen/2,
2649 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002651 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 reparse_buf->TargetNameOffset),
2653 name_len, nls_codepage);
2654 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002655 strncpy(symlinkinfo,
2656 reparse_buf->LinkNamesBuf +
2657 reparse_buf->TargetNameOffset,
2658 min_t(const int, buflen,
2659 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
2661 } else {
2662 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002663 cFYI(1, ("Invalid return data count on "
2664 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 }
2666 symlinkinfo[buflen] = 0; /* just in case so the caller
2667 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002668 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 }
2670 }
2671qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002672 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
2674 /* Note: On -EAGAIN error only caller can retry on handle based calls
2675 since file handle passed in no longer valid */
2676
2677 return rc;
2678}
2679
2680#ifdef CONFIG_CIFS_POSIX
2681
2682/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002683static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2684 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685{
2686 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002687 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2688 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2689 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2691
2692 return;
2693}
2694
2695/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002696static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2697 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698{
2699 int size = 0;
2700 int i;
2701 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002702 struct cifs_posix_ace *pACE;
2703 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2704 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
2706 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2707 return -EOPNOTSUPP;
2708
Steve French790fe572007-07-07 19:25:05 +00002709 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 count = le16_to_cpu(cifs_acl->access_entry_count);
2711 pACE = &cifs_acl->ace_array[0];
2712 size = sizeof(struct cifs_posix_acl);
2713 size += sizeof(struct cifs_posix_ace) * count;
2714 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002715 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002716 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2717 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return -EINVAL;
2719 }
Steve French790fe572007-07-07 19:25:05 +00002720 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 count = le16_to_cpu(cifs_acl->access_entry_count);
2722 size = sizeof(struct cifs_posix_acl);
2723 size += sizeof(struct cifs_posix_ace) * count;
2724/* skip past access ACEs to get to default ACEs */
2725 pACE = &cifs_acl->ace_array[count];
2726 count = le16_to_cpu(cifs_acl->default_entry_count);
2727 size += sizeof(struct cifs_posix_ace) * count;
2728 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002729 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 return -EINVAL;
2731 } else {
2732 /* illegal type */
2733 return -EINVAL;
2734 }
2735
2736 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002737 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002738 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002739 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 return -ERANGE;
2741 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002742 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002743 for (i = 0; i < count ; i++) {
2744 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2745 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 }
2747 }
2748 return size;
2749}
2750
Steve French50c2f752007-07-13 00:33:32 +00002751static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2752 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753{
2754 __u16 rc = 0; /* 0 = ACL converted ok */
2755
Steve Frenchff7feac2005-11-15 16:45:16 -08002756 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2757 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002759 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 /* Probably no need to le convert -1 on any arch but can not hurt */
2761 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002762 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002763 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002764 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 return rc;
2766}
2767
2768/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002769static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2770 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771{
2772 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002773 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2774 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 int count;
2776 int i;
2777
Steve French790fe572007-07-07 19:25:05 +00002778 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 return 0;
2780
2781 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002782 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002783 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002784 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002785 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002786 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002787 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 return 0;
2789 }
2790 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002791 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002792 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002793 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002794 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 else {
Steve French50c2f752007-07-13 00:33:32 +00002796 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 return 0;
2798 }
Steve French50c2f752007-07-13 00:33:32 +00002799 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2801 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002802 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 /* ACE not converted */
2804 break;
2805 }
2806 }
Steve French790fe572007-07-07 19:25:05 +00002807 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2809 rc += sizeof(struct cifs_posix_acl);
2810 /* BB add check to make sure ACL does not overflow SMB */
2811 }
2812 return rc;
2813}
2814
2815int
2816CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002817 const unsigned char *searchName,
2818 char *acl_inf, const int buflen, const int acl_type,
2819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820{
2821/* SMB_QUERY_POSIX_ACL */
2822 TRANSACTION2_QPI_REQ *pSMB = NULL;
2823 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2824 int rc = 0;
2825 int bytes_returned;
2826 int name_len;
2827 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002828
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2830
2831queryAclRetry:
2832 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2833 (void **) &pSMBr);
2834 if (rc)
2835 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2838 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002839 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002840 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 name_len++; /* trailing null */
2842 name_len *= 2;
2843 pSMB->FileName[name_len] = 0;
2844 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002845 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 name_len = strnlen(searchName, PATH_MAX);
2847 name_len++; /* trailing null */
2848 strncpy(pSMB->FileName, searchName, name_len);
2849 }
2850
2851 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2852 pSMB->TotalDataCount = 0;
2853 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002854 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 pSMB->MaxDataCount = cpu_to_le16(4000);
2856 pSMB->MaxSetupCount = 0;
2857 pSMB->Reserved = 0;
2858 pSMB->Flags = 0;
2859 pSMB->Timeout = 0;
2860 pSMB->Reserved2 = 0;
2861 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002862 offsetof(struct smb_com_transaction2_qpi_req,
2863 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 pSMB->DataCount = 0;
2865 pSMB->DataOffset = 0;
2866 pSMB->SetupCount = 1;
2867 pSMB->Reserved3 = 0;
2868 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2869 byte_count = params + 1 /* pad */ ;
2870 pSMB->TotalParameterCount = cpu_to_le16(params);
2871 pSMB->ParameterCount = pSMB->TotalParameterCount;
2872 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2873 pSMB->Reserved4 = 0;
2874 pSMB->hdr.smb_buf_length += byte_count;
2875 pSMB->ByteCount = cpu_to_le16(byte_count);
2876
2877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002879 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 if (rc) {
2881 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2882 } else {
2883 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002884
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2886 if (rc || (pSMBr->ByteCount < 2))
2887 /* BB also check enough total bytes returned */
2888 rc = -EIO; /* bad smb */
2889 else {
2890 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2891 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2892 rc = cifs_copy_posix_acl(acl_inf,
2893 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002894 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 }
2896 }
2897 cifs_buf_release(pSMB);
2898 if (rc == -EAGAIN)
2899 goto queryAclRetry;
2900 return rc;
2901}
2902
2903int
2904CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002905 const unsigned char *fileName,
2906 const char *local_acl, const int buflen,
2907 const int acl_type,
2908 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909{
2910 struct smb_com_transaction2_spi_req *pSMB = NULL;
2911 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2912 char *parm_data;
2913 int name_len;
2914 int rc = 0;
2915 int bytes_returned = 0;
2916 __u16 params, byte_count, data_count, param_offset, offset;
2917
2918 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2919setAclRetry:
2920 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002921 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 if (rc)
2923 return rc;
2924 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2925 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002926 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002927 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 name_len++; /* trailing null */
2929 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002930 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 name_len = strnlen(fileName, PATH_MAX);
2932 name_len++; /* trailing null */
2933 strncpy(pSMB->FileName, fileName, name_len);
2934 }
2935 params = 6 + name_len;
2936 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002937 /* BB find max SMB size from sess */
2938 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 pSMB->MaxSetupCount = 0;
2940 pSMB->Reserved = 0;
2941 pSMB->Flags = 0;
2942 pSMB->Timeout = 0;
2943 pSMB->Reserved2 = 0;
2944 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002945 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 offset = param_offset + params;
2947 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2948 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2949
2950 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002951 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
Steve French790fe572007-07-07 19:25:05 +00002953 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 rc = -EOPNOTSUPP;
2955 goto setACLerrorExit;
2956 }
2957 pSMB->DataOffset = cpu_to_le16(offset);
2958 pSMB->SetupCount = 1;
2959 pSMB->Reserved3 = 0;
2960 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2961 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2962 byte_count = 3 /* pad */ + params + data_count;
2963 pSMB->DataCount = cpu_to_le16(data_count);
2964 pSMB->TotalDataCount = pSMB->DataCount;
2965 pSMB->ParameterCount = cpu_to_le16(params);
2966 pSMB->TotalParameterCount = pSMB->ParameterCount;
2967 pSMB->Reserved4 = 0;
2968 pSMB->hdr.smb_buf_length += byte_count;
2969 pSMB->ByteCount = cpu_to_le16(byte_count);
2970 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002971 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002972 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974
2975setACLerrorExit:
2976 cifs_buf_release(pSMB);
2977 if (rc == -EAGAIN)
2978 goto setAclRetry;
2979 return rc;
2980}
2981
Steve Frenchf654bac2005-04-28 22:41:04 -07002982/* BB fix tabs in this function FIXME BB */
2983int
2984CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002985 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002986{
Steve French50c2f752007-07-13 00:33:32 +00002987 int rc = 0;
2988 struct smb_t2_qfi_req *pSMB = NULL;
2989 struct smb_t2_qfi_rsp *pSMBr = NULL;
2990 int bytes_returned;
2991 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002992
Steve French790fe572007-07-07 19:25:05 +00002993 cFYI(1, ("In GetExtAttr"));
2994 if (tcon == NULL)
2995 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002996
2997GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999 (void **) &pSMBr);
3000 if (rc)
3001 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003002
Steve Frenchad7a2922008-02-07 23:25:02 +00003003 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003004 pSMB->t2.TotalDataCount = 0;
3005 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3006 /* BB find exact max data count below from sess structure BB */
3007 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3008 pSMB->t2.MaxSetupCount = 0;
3009 pSMB->t2.Reserved = 0;
3010 pSMB->t2.Flags = 0;
3011 pSMB->t2.Timeout = 0;
3012 pSMB->t2.Reserved2 = 0;
3013 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3014 Fid) - 4);
3015 pSMB->t2.DataCount = 0;
3016 pSMB->t2.DataOffset = 0;
3017 pSMB->t2.SetupCount = 1;
3018 pSMB->t2.Reserved3 = 0;
3019 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3020 byte_count = params + 1 /* pad */ ;
3021 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3022 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3023 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3024 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003025 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003026 pSMB->hdr.smb_buf_length += byte_count;
3027 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003028
Steve French790fe572007-07-07 19:25:05 +00003029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3031 if (rc) {
3032 cFYI(1, ("error %d in GetExtAttr", rc));
3033 } else {
3034 /* decode response */
3035 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3036 if (rc || (pSMBr->ByteCount < 2))
3037 /* BB also check enough total bytes returned */
3038 /* If rc should we check for EOPNOSUPP and
3039 disable the srvino flag? or in caller? */
3040 rc = -EIO; /* bad smb */
3041 else {
3042 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3043 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3044 struct file_chattr_info *pfinfo;
3045 /* BB Do we need a cast or hash here ? */
3046 if (count != 16) {
3047 cFYI(1, ("Illegal size ret in GetExtAttr"));
3048 rc = -EIO;
3049 goto GetExtAttrOut;
3050 }
3051 pfinfo = (struct file_chattr_info *)
3052 (data_offset + (char *) &pSMBr->hdr.Protocol);
3053 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003054 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003055 }
3056 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003057GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003058 cifs_buf_release(pSMB);
3059 if (rc == -EAGAIN)
3060 goto GetExtAttrRetry;
3061 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003062}
3063
Steve Frenchf654bac2005-04-28 22:41:04 -07003064#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065
Steve French297647c2007-10-12 04:11:59 +00003066#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003067/* Get Security Descriptor (by handle) from remote server for a file or dir */
3068int
3069CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003070 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003071{
3072 int rc = 0;
3073 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003074 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003075 struct kvec iov[1];
3076
3077 cFYI(1, ("GetCifsACL"));
3078
Steve French630f3f02007-10-25 21:17:17 +00003079 *pbuflen = 0;
3080 *acl_inf = NULL;
3081
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003082 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003083 8 /* parm len */, tcon, (void **) &pSMB);
3084 if (rc)
3085 return rc;
3086
3087 pSMB->MaxParameterCount = cpu_to_le32(4);
3088 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3089 pSMB->MaxSetupCount = 0;
3090 pSMB->Fid = fid; /* file handle always le */
3091 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3092 CIFS_ACL_DACL);
3093 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3094 pSMB->hdr.smb_buf_length += 11;
3095 iov[0].iov_base = (char *)pSMB;
3096 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3097
Steve Frencha761ac52007-10-18 21:45:27 +00003098 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003099 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003100 cifs_stats_inc(&tcon->num_acl_get);
3101 if (rc) {
3102 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3103 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003104 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003105 __u32 parm_len;
3106 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003107 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003108 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003109
3110/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003111 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003112 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003113 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003114 goto qsec_out;
3115 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3116
Steve French630f3f02007-10-25 21:17:17 +00003117 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003118
3119 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3120 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003121 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003122 goto qsec_out;
3123 }
3124
3125/* BB check that data area is minimum length and as big as acl_len */
3126
Steve Frenchaf6f4612007-10-16 18:40:37 +00003127 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003128 if (acl_len != *pbuflen) {
3129 cERROR(1, ("acl length %d does not match %d",
3130 acl_len, *pbuflen));
3131 if (*pbuflen > acl_len)
3132 *pbuflen = acl_len;
3133 }
Steve French0a4b92c2006-01-12 15:44:21 -08003134
Steve French630f3f02007-10-25 21:17:17 +00003135 /* check if buffer is big enough for the acl
3136 header followed by the smallest SID */
3137 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3138 (*pbuflen >= 64 * 1024)) {
3139 cERROR(1, ("bad acl length %d", *pbuflen));
3140 rc = -EINVAL;
3141 *pbuflen = 0;
3142 } else {
3143 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3144 if (*acl_inf == NULL) {
3145 *pbuflen = 0;
3146 rc = -ENOMEM;
3147 }
3148 memcpy(*acl_inf, pdata, *pbuflen);
3149 }
Steve French0a4b92c2006-01-12 15:44:21 -08003150 }
3151qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003152 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003153 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003154 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003155 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003156/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003157 return rc;
3158}
Steve French97837582007-12-31 07:47:21 +00003159
3160int
3161CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3162 struct cifs_ntsd *pntsd, __u32 acllen)
3163{
3164 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3165 int rc = 0;
3166 int bytes_returned = 0;
3167 SET_SEC_DESC_REQ *pSMB = NULL;
3168 NTRANSACT_RSP *pSMBr = NULL;
3169
3170setCifsAclRetry:
3171 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3172 (void **) &pSMBr);
3173 if (rc)
3174 return (rc);
3175
3176 pSMB->MaxSetupCount = 0;
3177 pSMB->Reserved = 0;
3178
3179 param_count = 8;
3180 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3181 data_count = acllen;
3182 data_offset = param_offset + param_count;
3183 byte_count = 3 /* pad */ + param_count;
3184
3185 pSMB->DataCount = cpu_to_le32(data_count);
3186 pSMB->TotalDataCount = pSMB->DataCount;
3187 pSMB->MaxParameterCount = cpu_to_le32(4);
3188 pSMB->MaxDataCount = cpu_to_le32(16384);
3189 pSMB->ParameterCount = cpu_to_le32(param_count);
3190 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3191 pSMB->TotalParameterCount = pSMB->ParameterCount;
3192 pSMB->DataOffset = cpu_to_le32(data_offset);
3193 pSMB->SetupCount = 0;
3194 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3195 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3196
3197 pSMB->Fid = fid; /* file handle always le */
3198 pSMB->Reserved2 = 0;
3199 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3200
3201 if (pntsd && acllen) {
3202 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3203 (char *) pntsd,
3204 acllen);
3205 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3206
3207 } else
3208 pSMB->hdr.smb_buf_length += byte_count;
3209
3210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3212
3213 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3214 if (rc)
3215 cFYI(1, ("Set CIFS ACL returned %d", rc));
3216 cifs_buf_release(pSMB);
3217
3218 if (rc == -EAGAIN)
3219 goto setCifsAclRetry;
3220
3221 return (rc);
3222}
3223
Steve French297647c2007-10-12 04:11:59 +00003224#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003225
Steve French6b8edfe2005-08-23 20:26:03 -07003226/* Legacy Query Path Information call for lookup to old servers such
3227 as Win9x/WinME */
3228int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003229 const unsigned char *searchName,
3230 FILE_ALL_INFO *pFinfo,
3231 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003232{
Steve Frenchad7a2922008-02-07 23:25:02 +00003233 QUERY_INFORMATION_REQ *pSMB;
3234 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003235 int rc = 0;
3236 int bytes_returned;
3237 int name_len;
3238
Steve French50c2f752007-07-13 00:33:32 +00003239 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003240QInfRetry:
3241 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003242 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003243 if (rc)
3244 return rc;
3245
3246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3247 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003248 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3249 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003250 name_len++; /* trailing null */
3251 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003252 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003253 name_len = strnlen(searchName, PATH_MAX);
3254 name_len++; /* trailing null */
3255 strncpy(pSMB->FileName, searchName, name_len);
3256 }
3257 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003258 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003259 pSMB->hdr.smb_buf_length += (__u16) name_len;
3260 pSMB->ByteCount = cpu_to_le16(name_len);
3261
3262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003264 if (rc) {
3265 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003266 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003267 struct timespec ts;
3268 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003269
3270 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003271 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003272 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003273 ts.tv_nsec = 0;
3274 ts.tv_sec = time;
3275 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003276 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003277 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3278 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003279 pFinfo->AllocationSize =
3280 cpu_to_le64(le32_to_cpu(pSMBr->size));
3281 pFinfo->EndOfFile = pFinfo->AllocationSize;
3282 pFinfo->Attributes =
3283 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003284 } else
3285 rc = -EIO; /* bad buffer passed in */
3286
3287 cifs_buf_release(pSMB);
3288
3289 if (rc == -EAGAIN)
3290 goto QInfRetry;
3291
3292 return rc;
3293}
3294
3295
3296
3297
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298int
3299CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3300 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003301 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003302 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003303 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304{
3305/* level 263 SMB_QUERY_FILE_ALL_INFO */
3306 TRANSACTION2_QPI_REQ *pSMB = NULL;
3307 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3308 int rc = 0;
3309 int bytes_returned;
3310 int name_len;
3311 __u16 params, byte_count;
3312
3313/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3314QPathInfoRetry:
3315 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3316 (void **) &pSMBr);
3317 if (rc)
3318 return rc;
3319
3320 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3321 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003322 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003323 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 name_len++; /* trailing null */
3325 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003326 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 name_len = strnlen(searchName, PATH_MAX);
3328 name_len++; /* trailing null */
3329 strncpy(pSMB->FileName, searchName, name_len);
3330 }
3331
Steve French50c2f752007-07-13 00:33:32 +00003332 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 pSMB->TotalDataCount = 0;
3334 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003335 /* BB find exact max SMB PDU from sess structure BB */
3336 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 pSMB->MaxSetupCount = 0;
3338 pSMB->Reserved = 0;
3339 pSMB->Flags = 0;
3340 pSMB->Timeout = 0;
3341 pSMB->Reserved2 = 0;
3342 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003343 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 pSMB->DataCount = 0;
3345 pSMB->DataOffset = 0;
3346 pSMB->SetupCount = 1;
3347 pSMB->Reserved3 = 0;
3348 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3349 byte_count = params + 1 /* pad */ ;
3350 pSMB->TotalParameterCount = cpu_to_le16(params);
3351 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003352 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003353 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3354 else
3355 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 pSMB->Reserved4 = 0;
3357 pSMB->hdr.smb_buf_length += byte_count;
3358 pSMB->ByteCount = cpu_to_le16(byte_count);
3359
3360 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3361 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3362 if (rc) {
3363 cFYI(1, ("Send error in QPathInfo = %d", rc));
3364 } else { /* decode response */
3365 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3366
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003367 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3368 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003369 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003371 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003372 rc = -EIO; /* 24 or 26 expected but we do not read
3373 last field */
3374 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003375 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003377
3378 /* On legacy responses we do not read the last field,
3379 EAsize, fortunately since it varies by subdialect and
3380 also note it differs on Set vs. Get, ie two bytes or 4
3381 bytes depending but we don't care here */
3382 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003383 size = sizeof(FILE_INFO_STANDARD);
3384 else
3385 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003386 memcpy((char *) pFindData,
3387 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003388 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 } else
3390 rc = -ENOMEM;
3391 }
3392 cifs_buf_release(pSMB);
3393 if (rc == -EAGAIN)
3394 goto QPathInfoRetry;
3395
3396 return rc;
3397}
3398
3399int
3400CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3401 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003402 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003403 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404{
3405/* SMB_QUERY_FILE_UNIX_BASIC */
3406 TRANSACTION2_QPI_REQ *pSMB = NULL;
3407 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3408 int rc = 0;
3409 int bytes_returned = 0;
3410 int name_len;
3411 __u16 params, byte_count;
3412
3413 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3414UnixQPathInfoRetry:
3415 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3416 (void **) &pSMBr);
3417 if (rc)
3418 return rc;
3419
3420 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3421 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003422 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003423 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 name_len++; /* trailing null */
3425 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003426 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 name_len = strnlen(searchName, PATH_MAX);
3428 name_len++; /* trailing null */
3429 strncpy(pSMB->FileName, searchName, name_len);
3430 }
3431
Steve French50c2f752007-07-13 00:33:32 +00003432 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 pSMB->TotalDataCount = 0;
3434 pSMB->MaxParameterCount = cpu_to_le16(2);
3435 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003436 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 pSMB->MaxSetupCount = 0;
3438 pSMB->Reserved = 0;
3439 pSMB->Flags = 0;
3440 pSMB->Timeout = 0;
3441 pSMB->Reserved2 = 0;
3442 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003443 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 pSMB->DataCount = 0;
3445 pSMB->DataOffset = 0;
3446 pSMB->SetupCount = 1;
3447 pSMB->Reserved3 = 0;
3448 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3449 byte_count = params + 1 /* pad */ ;
3450 pSMB->TotalParameterCount = cpu_to_le16(params);
3451 pSMB->ParameterCount = pSMB->TotalParameterCount;
3452 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3453 pSMB->Reserved4 = 0;
3454 pSMB->hdr.smb_buf_length += byte_count;
3455 pSMB->ByteCount = cpu_to_le16(byte_count);
3456
3457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3459 if (rc) {
3460 cFYI(1, ("Send error in QPathInfo = %d", rc));
3461 } else { /* decode response */
3462 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3463
3464 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003465 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3466 "Unix Extensions can be disabled on mount "
3467 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 rc = -EIO; /* bad smb */
3469 } else {
3470 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3471 memcpy((char *) pFindData,
3472 (char *) &pSMBr->hdr.Protocol +
3473 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003474 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 }
3476 }
3477 cifs_buf_release(pSMB);
3478 if (rc == -EAGAIN)
3479 goto UnixQPathInfoRetry;
3480
3481 return rc;
3482}
3483
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484/* xid, tcon, searchName and codepage are input parms, rest are returned */
3485int
3486CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003487 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003489 __u16 *pnetfid,
3490 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491{
3492/* level 257 SMB_ */
3493 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3494 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003495 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 int rc = 0;
3497 int bytes_returned = 0;
3498 int name_len;
3499 __u16 params, byte_count;
3500
Steve French50c2f752007-07-13 00:33:32 +00003501 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502
3503findFirstRetry:
3504 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3505 (void **) &pSMBr);
3506 if (rc)
3507 return rc;
3508
3509 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3510 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003511 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003512 PATH_MAX, nls_codepage, remap);
3513 /* We can not add the asterik earlier in case
3514 it got remapped to 0xF03A as if it were part of the
3515 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003517 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003518 pSMB->FileName[name_len+1] = 0;
3519 pSMB->FileName[name_len+2] = '*';
3520 pSMB->FileName[name_len+3] = 0;
3521 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3523 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003524 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 } else { /* BB add check for overrun of SMB buf BB */
3526 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003528 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 free buffer exit; BB */
3530 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003531 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003532 pSMB->FileName[name_len+1] = '*';
3533 pSMB->FileName[name_len+2] = 0;
3534 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 }
3536
3537 params = 12 + name_len /* includes null */ ;
3538 pSMB->TotalDataCount = 0; /* no EAs */
3539 pSMB->MaxParameterCount = cpu_to_le16(10);
3540 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3541 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3542 pSMB->MaxSetupCount = 0;
3543 pSMB->Reserved = 0;
3544 pSMB->Flags = 0;
3545 pSMB->Timeout = 0;
3546 pSMB->Reserved2 = 0;
3547 byte_count = params + 1 /* pad */ ;
3548 pSMB->TotalParameterCount = cpu_to_le16(params);
3549 pSMB->ParameterCount = pSMB->TotalParameterCount;
3550 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003551 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3552 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 pSMB->DataCount = 0;
3554 pSMB->DataOffset = 0;
3555 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3556 pSMB->Reserved3 = 0;
3557 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3558 pSMB->SearchAttributes =
3559 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3560 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003561 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3562 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 CIFS_SEARCH_RETURN_RESUME);
3564 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3565
3566 /* BB what should we set StorageType to? Does it matter? BB */
3567 pSMB->SearchStorageType = 0;
3568 pSMB->hdr.smb_buf_length += byte_count;
3569 pSMB->ByteCount = cpu_to_le16(byte_count);
3570
3571 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3572 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003573 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
Steve French88274812006-03-09 22:21:45 +00003575 if (rc) {/* BB add logic to retry regular search if Unix search
3576 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 /* BB Add code to handle unsupported level rc */
3578 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003579
Steve French88274812006-03-09 22:21:45 +00003580 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581
3582 /* BB eventually could optimize out free and realloc of buf */
3583 /* for this case */
3584 if (rc == -EAGAIN)
3585 goto findFirstRetry;
3586 } else { /* decode response */
3587 /* BB remember to free buffer if error BB */
3588 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003589 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003590 unsigned int lnoff;
3591
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003593 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 else
Steve French4b18f2a2008-04-29 00:06:05 +00003595 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003598 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003599 psrch_inf->srch_entries_start =
3600 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3603 le16_to_cpu(pSMBr->t2.ParameterOffset));
3604
Steve French790fe572007-07-07 19:25:05 +00003605 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003606 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 else
Steve French4b18f2a2008-04-29 00:06:05 +00003608 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609
Steve French50c2f752007-07-13 00:33:32 +00003610 psrch_inf->entries_in_buffer =
3611 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003612 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003614 lnoff = le16_to_cpu(parms->LastNameOffset);
3615 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3616 lnoff) {
3617 cERROR(1, ("ignoring corrupt resume name"));
3618 psrch_inf->last_entry = NULL;
3619 return rc;
3620 }
3621
Steve French0752f152008-10-07 20:03:33 +00003622 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003623 lnoff;
3624
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 *pnetfid = parms->SearchHandle;
3626 } else {
3627 cifs_buf_release(pSMB);
3628 }
3629 }
3630
3631 return rc;
3632}
3633
3634int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003635 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636{
3637 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3638 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003639 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 char *response_data;
3641 int rc = 0;
3642 int bytes_returned, name_len;
3643 __u16 params, byte_count;
3644
3645 cFYI(1, ("In FindNext"));
3646
Steve French4b18f2a2008-04-29 00:06:05 +00003647 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648 return -ENOENT;
3649
3650 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3651 (void **) &pSMBr);
3652 if (rc)
3653 return rc;
3654
Steve French50c2f752007-07-13 00:33:32 +00003655 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 byte_count = 0;
3657 pSMB->TotalDataCount = 0; /* no EAs */
3658 pSMB->MaxParameterCount = cpu_to_le16(8);
3659 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003660 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3661 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 pSMB->MaxSetupCount = 0;
3663 pSMB->Reserved = 0;
3664 pSMB->Flags = 0;
3665 pSMB->Timeout = 0;
3666 pSMB->Reserved2 = 0;
3667 pSMB->ParameterOffset = cpu_to_le16(
3668 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3669 pSMB->DataCount = 0;
3670 pSMB->DataOffset = 0;
3671 pSMB->SetupCount = 1;
3672 pSMB->Reserved3 = 0;
3673 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3674 pSMB->SearchHandle = searchHandle; /* always kept as le */
3675 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003676 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3678 pSMB->ResumeKey = psrch_inf->resume_key;
3679 pSMB->SearchFlags =
3680 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3681
3682 name_len = psrch_inf->resume_name_len;
3683 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003684 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3686 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003687 /* 14 byte parm len above enough for 2 byte null terminator */
3688 pSMB->ResumeFileName[name_len] = 0;
3689 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 } else {
3691 rc = -EINVAL;
3692 goto FNext2_err_exit;
3693 }
3694 byte_count = params + 1 /* pad */ ;
3695 pSMB->TotalParameterCount = cpu_to_le16(params);
3696 pSMB->ParameterCount = pSMB->TotalParameterCount;
3697 pSMB->hdr.smb_buf_length += byte_count;
3698 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003699
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3701 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003702 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 if (rc) {
3704 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003705 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003706 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003707 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 } else
3709 cFYI(1, ("FindNext returned = %d", rc));
3710 } else { /* decode response */
3711 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003712
Steve French790fe572007-07-07 19:25:05 +00003713 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003714 unsigned int lnoff;
3715
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 /* BB fixme add lock for file (srch_info) struct here */
3717 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003718 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 else
Steve French4b18f2a2008-04-29 00:06:05 +00003720 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 response_data = (char *) &pSMBr->hdr.Protocol +
3722 le16_to_cpu(pSMBr->t2.ParameterOffset);
3723 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3724 response_data = (char *)&pSMBr->hdr.Protocol +
3725 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003726 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003727 cifs_small_buf_release(
3728 psrch_inf->ntwrk_buf_start);
3729 else
3730 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 psrch_inf->srch_entries_start = response_data;
3732 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003733 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003734 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003735 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 else
Steve French4b18f2a2008-04-29 00:06:05 +00003737 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003738 psrch_inf->entries_in_buffer =
3739 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 psrch_inf->index_of_last_entry +=
3741 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003742 lnoff = le16_to_cpu(parms->LastNameOffset);
3743 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3744 lnoff) {
3745 cERROR(1, ("ignoring corrupt resume name"));
3746 psrch_inf->last_entry = NULL;
3747 return rc;
3748 } else
3749 psrch_inf->last_entry =
3750 psrch_inf->srch_entries_start + lnoff;
3751
Steve French50c2f752007-07-13 00:33:32 +00003752/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3753 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754
3755 /* BB fixme add unlock here */
3756 }
3757
3758 }
3759
3760 /* BB On error, should we leave previous search buf (and count and
3761 last entry fields) intact or free the previous one? */
3762
3763 /* Note: On -EAGAIN error only caller can retry on handle based calls
3764 since file handle passed in no longer valid */
3765FNext2_err_exit:
3766 if (rc != 0)
3767 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 return rc;
3769}
3770
3771int
Steve French50c2f752007-07-13 00:33:32 +00003772CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3773 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774{
3775 int rc = 0;
3776 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777
3778 cFYI(1, ("In CIFSSMBFindClose"));
3779 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3780
3781 /* no sense returning error if session restarted
3782 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003783 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 return 0;
3785 if (rc)
3786 return rc;
3787
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 pSMB->FileID = searchHandle;
3789 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003790 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003791 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003793
Steve Frencha4544342005-08-24 13:59:35 -07003794 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795
3796 /* Since session is dead, search handle closed on server already */
3797 if (rc == -EAGAIN)
3798 rc = 0;
3799
3800 return rc;
3801}
3802
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803int
3804CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003805 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003806 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003807 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808{
3809 int rc = 0;
3810 TRANSACTION2_QPI_REQ *pSMB = NULL;
3811 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3812 int name_len, bytes_returned;
3813 __u16 params, byte_count;
3814
Steve French50c2f752007-07-13 00:33:32 +00003815 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003816 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003817 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818
3819GetInodeNumberRetry:
3820 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003821 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822 if (rc)
3823 return rc;
3824
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3826 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003827 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003828 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 name_len++; /* trailing null */
3830 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003831 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 name_len = strnlen(searchName, PATH_MAX);
3833 name_len++; /* trailing null */
3834 strncpy(pSMB->FileName, searchName, name_len);
3835 }
3836
3837 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3838 pSMB->TotalDataCount = 0;
3839 pSMB->MaxParameterCount = cpu_to_le16(2);
3840 /* BB find exact max data count below from sess structure BB */
3841 pSMB->MaxDataCount = cpu_to_le16(4000);
3842 pSMB->MaxSetupCount = 0;
3843 pSMB->Reserved = 0;
3844 pSMB->Flags = 0;
3845 pSMB->Timeout = 0;
3846 pSMB->Reserved2 = 0;
3847 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003848 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 pSMB->DataCount = 0;
3850 pSMB->DataOffset = 0;
3851 pSMB->SetupCount = 1;
3852 pSMB->Reserved3 = 0;
3853 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3854 byte_count = params + 1 /* pad */ ;
3855 pSMB->TotalParameterCount = cpu_to_le16(params);
3856 pSMB->ParameterCount = pSMB->TotalParameterCount;
3857 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3858 pSMB->Reserved4 = 0;
3859 pSMB->hdr.smb_buf_length += byte_count;
3860 pSMB->ByteCount = cpu_to_le16(byte_count);
3861
3862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3864 if (rc) {
3865 cFYI(1, ("error %d in QueryInternalInfo", rc));
3866 } else {
3867 /* decode response */
3868 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3869 if (rc || (pSMBr->ByteCount < 2))
3870 /* BB also check enough total bytes returned */
3871 /* If rc should we check for EOPNOSUPP and
3872 disable the srvino flag? or in caller? */
3873 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003874 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3876 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003877 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003879 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3881 rc = -EIO;
3882 goto GetInodeNumOut;
3883 }
3884 pfinfo = (struct file_internal_info *)
3885 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003886 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 }
3888 }
3889GetInodeNumOut:
3890 cifs_buf_release(pSMB);
3891 if (rc == -EAGAIN)
3892 goto GetInodeNumberRetry;
3893 return rc;
3894}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895
Igor Mammedovfec45852008-05-16 13:06:30 +04003896/* parses DFS refferal V3 structure
3897 * caller is responsible for freeing target_nodes
3898 * returns:
3899 * on success - 0
3900 * on failure - errno
3901 */
3902static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003903parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003904 unsigned int *num_of_nodes,
3905 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003906 const struct nls_table *nls_codepage, int remap,
3907 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003908{
3909 int i, rc = 0;
3910 char *data_end;
3911 bool is_unicode;
3912 struct dfs_referral_level_3 *ref;
3913
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003914 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3915 is_unicode = true;
3916 else
3917 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003918 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3919
3920 if (*num_of_nodes < 1) {
3921 cERROR(1, ("num_referrals: must be at least > 0,"
3922 "but we get num_referrals = %d\n", *num_of_nodes));
3923 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003924 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003925 }
3926
3927 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003928 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003929 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003930 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003931 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003932 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003933 }
3934
3935 /* get the upper boundary of the resp buffer */
3936 data_end = (char *)(&(pSMBr->PathConsumed)) +
3937 le16_to_cpu(pSMBr->t2.DataCount);
3938
3939 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3940 *num_of_nodes,
3941 le16_to_cpu(pSMBr->DFSFlags)));
3942
3943 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3944 *num_of_nodes, GFP_KERNEL);
3945 if (*target_nodes == NULL) {
3946 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3947 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003948 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003949 }
3950
3951 /* collect neccessary data from referrals */
3952 for (i = 0; i < *num_of_nodes; i++) {
3953 char *temp;
3954 int max_len;
3955 struct dfs_info3_param *node = (*target_nodes)+i;
3956
3957 node->flags = le16_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003958 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003959 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3960 GFP_KERNEL);
Igor Mammedov2c556082008-10-23 13:58:42 +04003961 cifsConvertToUCS((__le16 *) tmp, searchName,
3962 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003963 node->path_consumed = cifs_ucs2_bytes(tmp,
3964 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04003965 nls_codepage);
3966 kfree(tmp);
3967 } else
3968 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3969
Igor Mammedovfec45852008-05-16 13:06:30 +04003970 node->server_type = le16_to_cpu(ref->ServerType);
3971 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3972
3973 /* copy DfsPath */
3974 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3975 max_len = data_end - temp;
Jeff Layton066ce682009-04-30 07:16:14 -04003976 node->path_name = cifs_strndup(temp, max_len, is_unicode,
3977 nls_codepage);
3978 if (IS_ERR(node->path_name)) {
3979 rc = PTR_ERR(node->path_name);
3980 node->path_name = NULL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003981 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003982 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003983
3984 /* copy link target UNC */
3985 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3986 max_len = data_end - temp;
Jeff Layton066ce682009-04-30 07:16:14 -04003987 node->node_name = cifs_strndup(temp, max_len, is_unicode,
3988 nls_codepage);
3989 if (IS_ERR(node->node_name)) {
3990 rc = PTR_ERR(node->node_name);
3991 node->node_name = NULL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003992 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003993 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003994 }
3995
Steve Frencha1fe78f2008-05-16 18:48:38 +00003996parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04003997 if (rc) {
3998 free_dfs_info_array(*target_nodes, *num_of_nodes);
3999 *target_nodes = NULL;
4000 *num_of_nodes = 0;
4001 }
4002 return rc;
4003}
4004
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005int
4006CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4007 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004008 struct dfs_info3_param **target_nodes,
4009 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004010 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011{
4012/* TRANS2_GET_DFS_REFERRAL */
4013 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4014 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 int rc = 0;
4016 int bytes_returned;
4017 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004019 *num_of_nodes = 0;
4020 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
4022 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4023 if (ses == NULL)
4024 return -ENODEV;
4025getDFSRetry:
4026 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4027 (void **) &pSMBr);
4028 if (rc)
4029 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004030
4031 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004032 but should never be null here anyway */
4033 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 pSMB->hdr.Tid = ses->ipc_tid;
4035 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004036 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004038 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040
4041 if (ses->capabilities & CAP_UNICODE) {
4042 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4043 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004044 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004045 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 name_len++; /* trailing null */
4047 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004048 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 name_len = strnlen(searchName, PATH_MAX);
4050 name_len++; /* trailing null */
4051 strncpy(pSMB->RequestFileName, searchName, name_len);
4052 }
4053
Steve French790fe572007-07-07 19:25:05 +00004054 if (ses->server) {
4055 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004056 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4057 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4058 }
4059
Steve French50c2f752007-07-13 00:33:32 +00004060 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004061
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 params = 2 /* level */ + name_len /*includes null */ ;
4063 pSMB->TotalDataCount = 0;
4064 pSMB->DataCount = 0;
4065 pSMB->DataOffset = 0;
4066 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004067 /* BB find exact max SMB PDU from sess structure BB */
4068 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 pSMB->MaxSetupCount = 0;
4070 pSMB->Reserved = 0;
4071 pSMB->Flags = 0;
4072 pSMB->Timeout = 0;
4073 pSMB->Reserved2 = 0;
4074 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004075 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 pSMB->SetupCount = 1;
4077 pSMB->Reserved3 = 0;
4078 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4079 byte_count = params + 3 /* pad */ ;
4080 pSMB->ParameterCount = cpu_to_le16(params);
4081 pSMB->TotalParameterCount = pSMB->ParameterCount;
4082 pSMB->MaxReferralLevel = cpu_to_le16(3);
4083 pSMB->hdr.smb_buf_length += byte_count;
4084 pSMB->ByteCount = cpu_to_le16(byte_count);
4085
4086 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4087 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4088 if (rc) {
4089 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004090 goto GetDFSRefExit;
4091 }
4092 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004094 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004095 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004096 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004097 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004099
4100 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4101 pSMBr->ByteCount,
4102 le16_to_cpu(pSMBr->t2.DataOffset)));
4103
4104 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004105 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004106 target_nodes, nls_codepage, remap,
4107 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004108
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004110 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
4112 if (rc == -EAGAIN)
4113 goto getDFSRetry;
4114
4115 return rc;
4116}
4117
Steve French20962432005-09-21 22:05:57 -07004118/* Query File System Info such as free space to old servers such as Win 9x */
4119int
4120SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4121{
4122/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4123 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4124 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4125 FILE_SYSTEM_ALLOC_INFO *response_data;
4126 int rc = 0;
4127 int bytes_returned = 0;
4128 __u16 params, byte_count;
4129
4130 cFYI(1, ("OldQFSInfo"));
4131oldQFSInfoRetry:
4132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4133 (void **) &pSMBr);
4134 if (rc)
4135 return rc;
Steve French20962432005-09-21 22:05:57 -07004136
4137 params = 2; /* level */
4138 pSMB->TotalDataCount = 0;
4139 pSMB->MaxParameterCount = cpu_to_le16(2);
4140 pSMB->MaxDataCount = cpu_to_le16(1000);
4141 pSMB->MaxSetupCount = 0;
4142 pSMB->Reserved = 0;
4143 pSMB->Flags = 0;
4144 pSMB->Timeout = 0;
4145 pSMB->Reserved2 = 0;
4146 byte_count = params + 1 /* pad */ ;
4147 pSMB->TotalParameterCount = cpu_to_le16(params);
4148 pSMB->ParameterCount = pSMB->TotalParameterCount;
4149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4150 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4151 pSMB->DataCount = 0;
4152 pSMB->DataOffset = 0;
4153 pSMB->SetupCount = 1;
4154 pSMB->Reserved3 = 0;
4155 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4156 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4157 pSMB->hdr.smb_buf_length += byte_count;
4158 pSMB->ByteCount = cpu_to_le16(byte_count);
4159
4160 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4161 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4162 if (rc) {
4163 cFYI(1, ("Send error in QFSInfo = %d", rc));
4164 } else { /* decode response */
4165 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4166
4167 if (rc || (pSMBr->ByteCount < 18))
4168 rc = -EIO; /* bad smb */
4169 else {
4170 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004171 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004172 pSMBr->ByteCount, data_offset));
4173
Steve French50c2f752007-07-13 00:33:32 +00004174 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004175 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4176 FSData->f_bsize =
4177 le16_to_cpu(response_data->BytesPerSector) *
4178 le32_to_cpu(response_data->
4179 SectorsPerAllocationUnit);
4180 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004181 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004182 FSData->f_bfree = FSData->f_bavail =
4183 le32_to_cpu(response_data->FreeAllocationUnits);
4184 cFYI(1,
4185 ("Blocks: %lld Free: %lld Block size %ld",
4186 (unsigned long long)FSData->f_blocks,
4187 (unsigned long long)FSData->f_bfree,
4188 FSData->f_bsize));
4189 }
4190 }
4191 cifs_buf_release(pSMB);
4192
4193 if (rc == -EAGAIN)
4194 goto oldQFSInfoRetry;
4195
4196 return rc;
4197}
4198
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199int
Steve French737b7582005-04-28 22:41:06 -07004200CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201{
4202/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4203 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4204 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4205 FILE_SYSTEM_INFO *response_data;
4206 int rc = 0;
4207 int bytes_returned = 0;
4208 __u16 params, byte_count;
4209
4210 cFYI(1, ("In QFSInfo"));
4211QFSInfoRetry:
4212 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4213 (void **) &pSMBr);
4214 if (rc)
4215 return rc;
4216
4217 params = 2; /* level */
4218 pSMB->TotalDataCount = 0;
4219 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004220 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 pSMB->MaxSetupCount = 0;
4222 pSMB->Reserved = 0;
4223 pSMB->Flags = 0;
4224 pSMB->Timeout = 0;
4225 pSMB->Reserved2 = 0;
4226 byte_count = params + 1 /* pad */ ;
4227 pSMB->TotalParameterCount = cpu_to_le16(params);
4228 pSMB->ParameterCount = pSMB->TotalParameterCount;
4229 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004230 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 pSMB->DataCount = 0;
4232 pSMB->DataOffset = 0;
4233 pSMB->SetupCount = 1;
4234 pSMB->Reserved3 = 0;
4235 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4236 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4237 pSMB->hdr.smb_buf_length += byte_count;
4238 pSMB->ByteCount = cpu_to_le16(byte_count);
4239
4240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4241 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4242 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004243 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004245 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
Steve French20962432005-09-21 22:05:57 -07004247 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 rc = -EIO; /* bad smb */
4249 else {
4250 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251
4252 response_data =
4253 (FILE_SYSTEM_INFO
4254 *) (((char *) &pSMBr->hdr.Protocol) +
4255 data_offset);
4256 FSData->f_bsize =
4257 le32_to_cpu(response_data->BytesPerSector) *
4258 le32_to_cpu(response_data->
4259 SectorsPerAllocationUnit);
4260 FSData->f_blocks =
4261 le64_to_cpu(response_data->TotalAllocationUnits);
4262 FSData->f_bfree = FSData->f_bavail =
4263 le64_to_cpu(response_data->FreeAllocationUnits);
4264 cFYI(1,
4265 ("Blocks: %lld Free: %lld Block size %ld",
4266 (unsigned long long)FSData->f_blocks,
4267 (unsigned long long)FSData->f_bfree,
4268 FSData->f_bsize));
4269 }
4270 }
4271 cifs_buf_release(pSMB);
4272
4273 if (rc == -EAGAIN)
4274 goto QFSInfoRetry;
4275
4276 return rc;
4277}
4278
4279int
Steve French737b7582005-04-28 22:41:06 -07004280CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281{
4282/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4283 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4284 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4285 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4286 int rc = 0;
4287 int bytes_returned = 0;
4288 __u16 params, byte_count;
4289
4290 cFYI(1, ("In QFSAttributeInfo"));
4291QFSAttributeRetry:
4292 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4293 (void **) &pSMBr);
4294 if (rc)
4295 return rc;
4296
4297 params = 2; /* level */
4298 pSMB->TotalDataCount = 0;
4299 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004300 /* BB find exact max SMB PDU from sess structure BB */
4301 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 pSMB->MaxSetupCount = 0;
4303 pSMB->Reserved = 0;
4304 pSMB->Flags = 0;
4305 pSMB->Timeout = 0;
4306 pSMB->Reserved2 = 0;
4307 byte_count = params + 1 /* pad */ ;
4308 pSMB->TotalParameterCount = cpu_to_le16(params);
4309 pSMB->ParameterCount = pSMB->TotalParameterCount;
4310 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004311 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 pSMB->DataCount = 0;
4313 pSMB->DataOffset = 0;
4314 pSMB->SetupCount = 1;
4315 pSMB->Reserved3 = 0;
4316 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4317 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4318 pSMB->hdr.smb_buf_length += byte_count;
4319 pSMB->ByteCount = cpu_to_le16(byte_count);
4320
4321 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4322 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4323 if (rc) {
4324 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4325 } else { /* decode response */
4326 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4327
Steve French50c2f752007-07-13 00:33:32 +00004328 if (rc || (pSMBr->ByteCount < 13)) {
4329 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 rc = -EIO; /* bad smb */
4331 } else {
4332 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4333 response_data =
4334 (FILE_SYSTEM_ATTRIBUTE_INFO
4335 *) (((char *) &pSMBr->hdr.Protocol) +
4336 data_offset);
4337 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004338 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 }
4340 }
4341 cifs_buf_release(pSMB);
4342
4343 if (rc == -EAGAIN)
4344 goto QFSAttributeRetry;
4345
4346 return rc;
4347}
4348
4349int
Steve French737b7582005-04-28 22:41:06 -07004350CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351{
4352/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4353 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4354 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4355 FILE_SYSTEM_DEVICE_INFO *response_data;
4356 int rc = 0;
4357 int bytes_returned = 0;
4358 __u16 params, byte_count;
4359
4360 cFYI(1, ("In QFSDeviceInfo"));
4361QFSDeviceRetry:
4362 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4363 (void **) &pSMBr);
4364 if (rc)
4365 return rc;
4366
4367 params = 2; /* level */
4368 pSMB->TotalDataCount = 0;
4369 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004370 /* BB find exact max SMB PDU from sess structure BB */
4371 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 pSMB->MaxSetupCount = 0;
4373 pSMB->Reserved = 0;
4374 pSMB->Flags = 0;
4375 pSMB->Timeout = 0;
4376 pSMB->Reserved2 = 0;
4377 byte_count = params + 1 /* pad */ ;
4378 pSMB->TotalParameterCount = cpu_to_le16(params);
4379 pSMB->ParameterCount = pSMB->TotalParameterCount;
4380 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004381 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382
4383 pSMB->DataCount = 0;
4384 pSMB->DataOffset = 0;
4385 pSMB->SetupCount = 1;
4386 pSMB->Reserved3 = 0;
4387 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4388 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4389 pSMB->hdr.smb_buf_length += byte_count;
4390 pSMB->ByteCount = cpu_to_le16(byte_count);
4391
4392 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4393 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4394 if (rc) {
4395 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4396 } else { /* decode response */
4397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4398
Steve French630f3f02007-10-25 21:17:17 +00004399 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 rc = -EIO; /* bad smb */
4401 else {
4402 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4403 response_data =
Steve French737b7582005-04-28 22:41:06 -07004404 (FILE_SYSTEM_DEVICE_INFO *)
4405 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 data_offset);
4407 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004408 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 }
4410 }
4411 cifs_buf_release(pSMB);
4412
4413 if (rc == -EAGAIN)
4414 goto QFSDeviceRetry;
4415
4416 return rc;
4417}
4418
4419int
Steve French737b7582005-04-28 22:41:06 -07004420CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421{
4422/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4423 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4424 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4425 FILE_SYSTEM_UNIX_INFO *response_data;
4426 int rc = 0;
4427 int bytes_returned = 0;
4428 __u16 params, byte_count;
4429
4430 cFYI(1, ("In QFSUnixInfo"));
4431QFSUnixRetry:
4432 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4433 (void **) &pSMBr);
4434 if (rc)
4435 return rc;
4436
4437 params = 2; /* level */
4438 pSMB->TotalDataCount = 0;
4439 pSMB->DataCount = 0;
4440 pSMB->DataOffset = 0;
4441 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004442 /* BB find exact max SMB PDU from sess structure BB */
4443 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 pSMB->MaxSetupCount = 0;
4445 pSMB->Reserved = 0;
4446 pSMB->Flags = 0;
4447 pSMB->Timeout = 0;
4448 pSMB->Reserved2 = 0;
4449 byte_count = params + 1 /* pad */ ;
4450 pSMB->ParameterCount = cpu_to_le16(params);
4451 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004452 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4453 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 pSMB->SetupCount = 1;
4455 pSMB->Reserved3 = 0;
4456 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4457 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4458 pSMB->hdr.smb_buf_length += byte_count;
4459 pSMB->ByteCount = cpu_to_le16(byte_count);
4460
4461 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4462 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4463 if (rc) {
4464 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4465 } else { /* decode response */
4466 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4467
4468 if (rc || (pSMBr->ByteCount < 13)) {
4469 rc = -EIO; /* bad smb */
4470 } else {
4471 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4472 response_data =
4473 (FILE_SYSTEM_UNIX_INFO
4474 *) (((char *) &pSMBr->hdr.Protocol) +
4475 data_offset);
4476 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004477 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 }
4479 }
4480 cifs_buf_release(pSMB);
4481
4482 if (rc == -EAGAIN)
4483 goto QFSUnixRetry;
4484
4485
4486 return rc;
4487}
4488
Jeremy Allisonac670552005-06-22 17:26:35 -07004489int
Steve French45abc6e2005-06-23 13:42:03 -05004490CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004491{
4492/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4493 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4494 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4495 int rc = 0;
4496 int bytes_returned = 0;
4497 __u16 params, param_offset, offset, byte_count;
4498
4499 cFYI(1, ("In SETFSUnixInfo"));
4500SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004501 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004502 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4503 (void **) &pSMBr);
4504 if (rc)
4505 return rc;
4506
4507 params = 4; /* 2 bytes zero followed by info level. */
4508 pSMB->MaxSetupCount = 0;
4509 pSMB->Reserved = 0;
4510 pSMB->Flags = 0;
4511 pSMB->Timeout = 0;
4512 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004513 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4514 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004515 offset = param_offset + params;
4516
4517 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004518 /* BB find exact max SMB PDU from sess structure BB */
4519 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004520 pSMB->SetupCount = 1;
4521 pSMB->Reserved3 = 0;
4522 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4523 byte_count = 1 /* pad */ + params + 12;
4524
4525 pSMB->DataCount = cpu_to_le16(12);
4526 pSMB->ParameterCount = cpu_to_le16(params);
4527 pSMB->TotalDataCount = pSMB->DataCount;
4528 pSMB->TotalParameterCount = pSMB->ParameterCount;
4529 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4530 pSMB->DataOffset = cpu_to_le16(offset);
4531
4532 /* Params. */
4533 pSMB->FileNum = 0;
4534 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4535
4536 /* Data. */
4537 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4538 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4539 pSMB->ClientUnixCap = cpu_to_le64(cap);
4540
4541 pSMB->hdr.smb_buf_length += byte_count;
4542 pSMB->ByteCount = cpu_to_le16(byte_count);
4543
4544 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4545 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4546 if (rc) {
4547 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4548 } else { /* decode response */
4549 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004550 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004551 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004552 }
4553 cifs_buf_release(pSMB);
4554
4555 if (rc == -EAGAIN)
4556 goto SETFSUnixRetry;
4557
4558 return rc;
4559}
4560
4561
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562
4563int
4564CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004565 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566{
4567/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4568 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4569 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4570 FILE_SYSTEM_POSIX_INFO *response_data;
4571 int rc = 0;
4572 int bytes_returned = 0;
4573 __u16 params, byte_count;
4574
4575 cFYI(1, ("In QFSPosixInfo"));
4576QFSPosixRetry:
4577 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4578 (void **) &pSMBr);
4579 if (rc)
4580 return rc;
4581
4582 params = 2; /* level */
4583 pSMB->TotalDataCount = 0;
4584 pSMB->DataCount = 0;
4585 pSMB->DataOffset = 0;
4586 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004587 /* BB find exact max SMB PDU from sess structure BB */
4588 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 pSMB->MaxSetupCount = 0;
4590 pSMB->Reserved = 0;
4591 pSMB->Flags = 0;
4592 pSMB->Timeout = 0;
4593 pSMB->Reserved2 = 0;
4594 byte_count = params + 1 /* pad */ ;
4595 pSMB->ParameterCount = cpu_to_le16(params);
4596 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004597 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4598 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004599 pSMB->SetupCount = 1;
4600 pSMB->Reserved3 = 0;
4601 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4602 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4603 pSMB->hdr.smb_buf_length += byte_count;
4604 pSMB->ByteCount = cpu_to_le16(byte_count);
4605
4606 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4607 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4608 if (rc) {
4609 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4610 } else { /* decode response */
4611 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4612
4613 if (rc || (pSMBr->ByteCount < 13)) {
4614 rc = -EIO; /* bad smb */
4615 } else {
4616 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4617 response_data =
4618 (FILE_SYSTEM_POSIX_INFO
4619 *) (((char *) &pSMBr->hdr.Protocol) +
4620 data_offset);
4621 FSData->f_bsize =
4622 le32_to_cpu(response_data->BlockSize);
4623 FSData->f_blocks =
4624 le64_to_cpu(response_data->TotalBlocks);
4625 FSData->f_bfree =
4626 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004627 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 FSData->f_bavail = FSData->f_bfree;
4629 } else {
4630 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004631 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 }
Steve French790fe572007-07-07 19:25:05 +00004633 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004635 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004636 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004638 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 }
4640 }
4641 cifs_buf_release(pSMB);
4642
4643 if (rc == -EAGAIN)
4644 goto QFSPosixRetry;
4645
4646 return rc;
4647}
4648
4649
Steve French50c2f752007-07-13 00:33:32 +00004650/* We can not use write of zero bytes trick to
4651 set file size due to need for large file support. Also note that
4652 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 routine which is only needed to work around a sharing violation bug
4654 in Samba which this routine can run into */
4655
4656int
4657CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004658 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004659 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660{
4661 struct smb_com_transaction2_spi_req *pSMB = NULL;
4662 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4663 struct file_end_of_file_info *parm_data;
4664 int name_len;
4665 int rc = 0;
4666 int bytes_returned = 0;
4667 __u16 params, byte_count, data_count, param_offset, offset;
4668
4669 cFYI(1, ("In SetEOF"));
4670SetEOFRetry:
4671 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4672 (void **) &pSMBr);
4673 if (rc)
4674 return rc;
4675
4676 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4677 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004678 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004679 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 name_len++; /* trailing null */
4681 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004682 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 name_len = strnlen(fileName, PATH_MAX);
4684 name_len++; /* trailing null */
4685 strncpy(pSMB->FileName, fileName, name_len);
4686 }
4687 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004688 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004689 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004690 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 pSMB->MaxSetupCount = 0;
4692 pSMB->Reserved = 0;
4693 pSMB->Flags = 0;
4694 pSMB->Timeout = 0;
4695 pSMB->Reserved2 = 0;
4696 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004697 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004699 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004700 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4701 pSMB->InformationLevel =
4702 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4703 else
4704 pSMB->InformationLevel =
4705 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4706 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4708 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004709 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 else
4711 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004712 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 }
4714
4715 parm_data =
4716 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4717 offset);
4718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4719 pSMB->DataOffset = cpu_to_le16(offset);
4720 pSMB->SetupCount = 1;
4721 pSMB->Reserved3 = 0;
4722 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4723 byte_count = 3 /* pad */ + params + data_count;
4724 pSMB->DataCount = cpu_to_le16(data_count);
4725 pSMB->TotalDataCount = pSMB->DataCount;
4726 pSMB->ParameterCount = cpu_to_le16(params);
4727 pSMB->TotalParameterCount = pSMB->ParameterCount;
4728 pSMB->Reserved4 = 0;
4729 pSMB->hdr.smb_buf_length += byte_count;
4730 parm_data->FileSize = cpu_to_le64(size);
4731 pSMB->ByteCount = cpu_to_le16(byte_count);
4732 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4733 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004734 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736
4737 cifs_buf_release(pSMB);
4738
4739 if (rc == -EAGAIN)
4740 goto SetEOFRetry;
4741
4742 return rc;
4743}
4744
4745int
Steve French50c2f752007-07-13 00:33:32 +00004746CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004747 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748{
4749 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 char *data_offset;
4751 struct file_end_of_file_info *parm_data;
4752 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 __u16 params, param_offset, offset, byte_count, count;
4754
4755 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4756 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004757 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4758
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 if (rc)
4760 return rc;
4761
4762 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4763 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004764
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 params = 6;
4766 pSMB->MaxSetupCount = 0;
4767 pSMB->Reserved = 0;
4768 pSMB->Flags = 0;
4769 pSMB->Timeout = 0;
4770 pSMB->Reserved2 = 0;
4771 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4772 offset = param_offset + params;
4773
Steve French50c2f752007-07-13 00:33:32 +00004774 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
4776 count = sizeof(struct file_end_of_file_info);
4777 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004778 /* BB find exact max SMB PDU from sess structure BB */
4779 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780 pSMB->SetupCount = 1;
4781 pSMB->Reserved3 = 0;
4782 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4783 byte_count = 3 /* pad */ + params + count;
4784 pSMB->DataCount = cpu_to_le16(count);
4785 pSMB->ParameterCount = cpu_to_le16(params);
4786 pSMB->TotalDataCount = pSMB->DataCount;
4787 pSMB->TotalParameterCount = pSMB->ParameterCount;
4788 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4789 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004790 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4791 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 pSMB->DataOffset = cpu_to_le16(offset);
4793 parm_data->FileSize = cpu_to_le64(size);
4794 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004795 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4797 pSMB->InformationLevel =
4798 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4799 else
4800 pSMB->InformationLevel =
4801 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004802 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4804 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004805 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 else
4807 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004808 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 }
4810 pSMB->Reserved4 = 0;
4811 pSMB->hdr.smb_buf_length += byte_count;
4812 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004813 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 if (rc) {
4815 cFYI(1,
4816 ("Send error in SetFileInfo (SetFileSize) = %d",
4817 rc));
4818 }
4819
Steve French50c2f752007-07-13 00:33:32 +00004820 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 since file handle passed in no longer valid */
4822
4823 return rc;
4824}
4825
Steve French50c2f752007-07-13 00:33:32 +00004826/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 an open handle, rather than by pathname - this is awkward due to
4828 potential access conflicts on the open, but it is unavoidable for these
4829 old servers since the only other choice is to go from 100 nanosecond DCE
4830 time and resort to the original setpathinfo level which takes the ancient
4831 DOS time format with 2 second granularity */
4832int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004833CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4834 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835{
4836 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 char *data_offset;
4838 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 __u16 params, param_offset, offset, byte_count, count;
4840
4841 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004842 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4843
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 if (rc)
4845 return rc;
4846
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004847 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4848 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004849
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 params = 6;
4851 pSMB->MaxSetupCount = 0;
4852 pSMB->Reserved = 0;
4853 pSMB->Flags = 0;
4854 pSMB->Timeout = 0;
4855 pSMB->Reserved2 = 0;
4856 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4857 offset = param_offset + params;
4858
Steve French50c2f752007-07-13 00:33:32 +00004859 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860
Steve French26f57362007-08-30 22:09:15 +00004861 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004863 /* BB find max SMB PDU from sess */
4864 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 pSMB->SetupCount = 1;
4866 pSMB->Reserved3 = 0;
4867 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4868 byte_count = 3 /* pad */ + params + count;
4869 pSMB->DataCount = cpu_to_le16(count);
4870 pSMB->ParameterCount = cpu_to_le16(params);
4871 pSMB->TotalDataCount = pSMB->DataCount;
4872 pSMB->TotalParameterCount = pSMB->ParameterCount;
4873 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4874 pSMB->DataOffset = cpu_to_le16(offset);
4875 pSMB->Fid = fid;
4876 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4877 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4878 else
4879 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4880 pSMB->Reserved4 = 0;
4881 pSMB->hdr.smb_buf_length += byte_count;
4882 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004883 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004884 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004885 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004886 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887
Steve French50c2f752007-07-13 00:33:32 +00004888 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889 since file handle passed in no longer valid */
4890
4891 return rc;
4892}
4893
Jeff Layton6d22f092008-09-23 11:48:35 -04004894int
4895CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4896 bool delete_file, __u16 fid, __u32 pid_of_opener)
4897{
4898 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4899 char *data_offset;
4900 int rc = 0;
4901 __u16 params, param_offset, offset, byte_count, count;
4902
4903 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4904 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4905
4906 if (rc)
4907 return rc;
4908
4909 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4910 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4911
4912 params = 6;
4913 pSMB->MaxSetupCount = 0;
4914 pSMB->Reserved = 0;
4915 pSMB->Flags = 0;
4916 pSMB->Timeout = 0;
4917 pSMB->Reserved2 = 0;
4918 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4919 offset = param_offset + params;
4920
4921 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4922
4923 count = 1;
4924 pSMB->MaxParameterCount = cpu_to_le16(2);
4925 /* BB find max SMB PDU from sess */
4926 pSMB->MaxDataCount = cpu_to_le16(1000);
4927 pSMB->SetupCount = 1;
4928 pSMB->Reserved3 = 0;
4929 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4930 byte_count = 3 /* pad */ + params + count;
4931 pSMB->DataCount = cpu_to_le16(count);
4932 pSMB->ParameterCount = cpu_to_le16(params);
4933 pSMB->TotalDataCount = pSMB->DataCount;
4934 pSMB->TotalParameterCount = pSMB->ParameterCount;
4935 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4936 pSMB->DataOffset = cpu_to_le16(offset);
4937 pSMB->Fid = fid;
4938 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4939 pSMB->Reserved4 = 0;
4940 pSMB->hdr.smb_buf_length += byte_count;
4941 pSMB->ByteCount = cpu_to_le16(byte_count);
4942 *data_offset = delete_file ? 1 : 0;
4943 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4944 if (rc)
4945 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4946
4947 return rc;
4948}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949
4950int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004951CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4952 const char *fileName, const FILE_BASIC_INFO *data,
4953 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954{
4955 TRANSACTION2_SPI_REQ *pSMB = NULL;
4956 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4957 int name_len;
4958 int rc = 0;
4959 int bytes_returned = 0;
4960 char *data_offset;
4961 __u16 params, param_offset, offset, byte_count, count;
4962
4963 cFYI(1, ("In SetTimes"));
4964
4965SetTimesRetry:
4966 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4967 (void **) &pSMBr);
4968 if (rc)
4969 return rc;
4970
4971 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4972 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004973 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004974 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 name_len++; /* trailing null */
4976 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004977 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 name_len = strnlen(fileName, PATH_MAX);
4979 name_len++; /* trailing null */
4980 strncpy(pSMB->FileName, fileName, name_len);
4981 }
4982
4983 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004984 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004986 /* BB find max SMB PDU from sess structure BB */
4987 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 pSMB->MaxSetupCount = 0;
4989 pSMB->Reserved = 0;
4990 pSMB->Flags = 0;
4991 pSMB->Timeout = 0;
4992 pSMB->Reserved2 = 0;
4993 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004994 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 offset = param_offset + params;
4996 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4997 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4998 pSMB->DataOffset = cpu_to_le16(offset);
4999 pSMB->SetupCount = 1;
5000 pSMB->Reserved3 = 0;
5001 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5002 byte_count = 3 /* pad */ + params + count;
5003
5004 pSMB->DataCount = cpu_to_le16(count);
5005 pSMB->ParameterCount = cpu_to_le16(params);
5006 pSMB->TotalDataCount = pSMB->DataCount;
5007 pSMB->TotalParameterCount = pSMB->ParameterCount;
5008 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5009 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5010 else
5011 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5012 pSMB->Reserved4 = 0;
5013 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005014 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 pSMB->ByteCount = cpu_to_le16(byte_count);
5016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005018 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020
5021 cifs_buf_release(pSMB);
5022
5023 if (rc == -EAGAIN)
5024 goto SetTimesRetry;
5025
5026 return rc;
5027}
5028
5029/* Can not be used to set time stamps yet (due to old DOS time format) */
5030/* Can be used to set attributes */
5031#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5032 handling it anyway and NT4 was what we thought it would be needed for
5033 Do not delete it until we prove whether needed for Win9x though */
5034int
5035CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5036 __u16 dos_attrs, const struct nls_table *nls_codepage)
5037{
5038 SETATTR_REQ *pSMB = NULL;
5039 SETATTR_RSP *pSMBr = NULL;
5040 int rc = 0;
5041 int bytes_returned;
5042 int name_len;
5043
5044 cFYI(1, ("In SetAttrLegacy"));
5045
5046SetAttrLgcyRetry:
5047 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5048 (void **) &pSMBr);
5049 if (rc)
5050 return rc;
5051
5052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5053 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005054 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 PATH_MAX, nls_codepage);
5056 name_len++; /* trailing null */
5057 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005058 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 name_len = strnlen(fileName, PATH_MAX);
5060 name_len++; /* trailing null */
5061 strncpy(pSMB->fileName, fileName, name_len);
5062 }
5063 pSMB->attr = cpu_to_le16(dos_attrs);
5064 pSMB->BufferFormat = 0x04;
5065 pSMB->hdr.smb_buf_length += name_len + 1;
5066 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005069 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071
5072 cifs_buf_release(pSMB);
5073
5074 if (rc == -EAGAIN)
5075 goto SetAttrLgcyRetry;
5076
5077 return rc;
5078}
5079#endif /* temporarily unneeded SetAttr legacy function */
5080
5081int
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005082CIFSSMBUnixSetInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
Steve French063ea272008-08-06 04:23:13 +00005083 const struct cifs_unix_set_info_args *args,
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005084 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085{
5086 TRANSACTION2_SPI_REQ *pSMB = NULL;
5087 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5088 int name_len;
5089 int rc = 0;
5090 int bytes_returned = 0;
5091 FILE_UNIX_BASIC_INFO *data_offset;
5092 __u16 params, param_offset, offset, count, byte_count;
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005093 __u64 mode = args->mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094
5095 cFYI(1, ("In SetUID/GID/Mode"));
5096setPermsRetry:
5097 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5098 (void **) &pSMBr);
5099 if (rc)
5100 return rc;
5101
5102 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5103 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005104 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005105 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005106 name_len++; /* trailing null */
5107 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005108 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 name_len = strnlen(fileName, PATH_MAX);
5110 name_len++; /* trailing null */
5111 strncpy(pSMB->FileName, fileName, name_len);
5112 }
5113
5114 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005115 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005117 /* BB find max SMB PDU from sess structure BB */
5118 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 pSMB->MaxSetupCount = 0;
5120 pSMB->Reserved = 0;
5121 pSMB->Flags = 0;
5122 pSMB->Timeout = 0;
5123 pSMB->Reserved2 = 0;
5124 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005125 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 offset = param_offset + params;
5127 data_offset =
5128 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5129 offset);
5130 memset(data_offset, 0, count);
5131 pSMB->DataOffset = cpu_to_le16(offset);
5132 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5133 pSMB->SetupCount = 1;
5134 pSMB->Reserved3 = 0;
5135 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5136 byte_count = 3 /* pad */ + params + count;
5137 pSMB->ParameterCount = cpu_to_le16(params);
5138 pSMB->DataCount = cpu_to_le16(count);
5139 pSMB->TotalParameterCount = pSMB->ParameterCount;
5140 pSMB->TotalDataCount = pSMB->DataCount;
5141 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5142 pSMB->Reserved4 = 0;
5143 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005144 /* Samba server ignores set of file size to zero due to bugs in some
5145 older clients, but we should be precise - we use SetFileSize to
5146 set file size and do not want to truncate file size to zero
5147 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005148 zero instead of -1 here */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005149 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5150 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5151 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5152 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5153 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5154 data_offset->Uid = cpu_to_le64(args->uid);
5155 data_offset->Gid = cpu_to_le64(args->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 /* better to leave device as zero when it is */
Jeff Layton4e1e7fb2008-08-02 07:26:12 -04005157 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5158 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005160
Steve French790fe572007-07-07 19:25:05 +00005161 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005163 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005165 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005167 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005169 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005171 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005173 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5175
5176
5177 pSMB->ByteCount = cpu_to_le16(byte_count);
5178 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5179 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005180 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182
Steve French0d817bc2008-05-22 02:02:03 +00005183 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 if (rc == -EAGAIN)
5185 goto setPermsRetry;
5186 return rc;
5187}
5188
Steve French50c2f752007-07-13 00:33:32 +00005189int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005190 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005191 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005192 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193{
5194 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005195 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5196 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005197 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 int bytes_returned;
5199
Steve French50c2f752007-07-13 00:33:32 +00005200 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005202 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 if (rc)
5204 return rc;
5205
5206 pSMB->TotalParameterCount = 0 ;
5207 pSMB->TotalDataCount = 0;
5208 pSMB->MaxParameterCount = cpu_to_le32(2);
5209 /* BB find exact data count max from sess structure BB */
5210 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005211/* BB VERIFY verify which is correct for above BB */
5212 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5213 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5214
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 pSMB->MaxSetupCount = 4;
5216 pSMB->Reserved = 0;
5217 pSMB->ParameterOffset = 0;
5218 pSMB->DataCount = 0;
5219 pSMB->DataOffset = 0;
5220 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5221 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5222 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005223 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5225 pSMB->Reserved2 = 0;
5226 pSMB->CompletionFilter = cpu_to_le32(filter);
5227 pSMB->Fid = netfid; /* file handle always le */
5228 pSMB->ByteCount = 0;
5229
5230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005231 (struct smb_hdr *)pSMBr, &bytes_returned,
5232 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 if (rc) {
5234 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005235 } else {
5236 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005237 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005238 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005239 sizeof(struct dir_notify_req),
5240 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005241 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005242 dnotify_req->Pid = pSMB->hdr.Pid;
5243 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5244 dnotify_req->Mid = pSMB->hdr.Mid;
5245 dnotify_req->Tid = pSMB->hdr.Tid;
5246 dnotify_req->Uid = pSMB->hdr.Uid;
5247 dnotify_req->netfid = netfid;
5248 dnotify_req->pfile = pfile;
5249 dnotify_req->filter = filter;
5250 dnotify_req->multishot = multishot;
5251 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005252 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005253 &GlobalDnotifyReqList);
5254 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005255 } else
Steve French47c786e2005-10-11 20:03:18 -07005256 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 }
5258 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005259 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260}
5261#ifdef CONFIG_CIFS_XATTR
5262ssize_t
5263CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5264 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005265 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005266 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267{
5268 /* BB assumes one setup word */
5269 TRANSACTION2_QPI_REQ *pSMB = NULL;
5270 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5271 int rc = 0;
5272 int bytes_returned;
5273 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005274 struct fea *temp_fea;
5275 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 __u16 params, byte_count;
5277
5278 cFYI(1, ("In Query All EAs path %s", searchName));
5279QAllEAsRetry:
5280 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5281 (void **) &pSMBr);
5282 if (rc)
5283 return rc;
5284
5285 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5286 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005287 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005288 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 name_len++; /* trailing null */
5290 name_len *= 2;
5291 } else { /* BB improve the check for buffer overruns BB */
5292 name_len = strnlen(searchName, PATH_MAX);
5293 name_len++; /* trailing null */
5294 strncpy(pSMB->FileName, searchName, name_len);
5295 }
5296
Steve French50c2f752007-07-13 00:33:32 +00005297 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 pSMB->TotalDataCount = 0;
5299 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005300 /* BB find exact max SMB PDU from sess structure BB */
5301 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 pSMB->MaxSetupCount = 0;
5303 pSMB->Reserved = 0;
5304 pSMB->Flags = 0;
5305 pSMB->Timeout = 0;
5306 pSMB->Reserved2 = 0;
5307 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005308 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 pSMB->DataCount = 0;
5310 pSMB->DataOffset = 0;
5311 pSMB->SetupCount = 1;
5312 pSMB->Reserved3 = 0;
5313 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5314 byte_count = params + 1 /* pad */ ;
5315 pSMB->TotalParameterCount = cpu_to_le16(params);
5316 pSMB->ParameterCount = pSMB->TotalParameterCount;
5317 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5318 pSMB->Reserved4 = 0;
5319 pSMB->hdr.smb_buf_length += byte_count;
5320 pSMB->ByteCount = cpu_to_le16(byte_count);
5321
5322 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5323 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5324 if (rc) {
5325 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5326 } else { /* decode response */
5327 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5328
5329 /* BB also check enough total bytes returned */
5330 /* BB we need to improve the validity checking
5331 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005332 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 rc = -EIO; /* bad smb */
5334 /* else if (pFindData){
5335 memcpy((char *) pFindData,
5336 (char *) &pSMBr->hdr.Protocol +
5337 data_offset, kl);
5338 }*/ else {
5339 /* check that length of list is not more than bcc */
5340 /* check that each entry does not go beyond length
5341 of list */
5342 /* check that each element of each entry does not
5343 go beyond end of list */
5344 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005345 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 rc = 0;
5347 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005348 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349 ea_response_data = (struct fealist *)
5350 (((char *) &pSMBr->hdr.Protocol) +
5351 data_offset);
5352 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005353 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005354 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005356 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357 } else {
5358 /* account for ea list len */
5359 name_len -= 4;
5360 temp_fea = ea_response_data->list;
5361 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005362 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 __u16 value_len;
5364 name_len -= 4;
5365 temp_ptr += 4;
5366 rc += temp_fea->name_len;
5367 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005368 rc = rc + 5 + 1;
5369 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005370 memcpy(EAData, "user.", 5);
5371 EAData += 5;
5372 memcpy(EAData, temp_ptr,
5373 temp_fea->name_len);
5374 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 /* null terminate name */
5376 *EAData = 0;
5377 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005378 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 /* skip copy - calc size only */
5380 } else {
5381 /* stop before overrun buffer */
5382 rc = -ERANGE;
5383 break;
5384 }
5385 name_len -= temp_fea->name_len;
5386 temp_ptr += temp_fea->name_len;
5387 /* account for trailing null */
5388 name_len--;
5389 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005390 value_len =
5391 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 name_len -= value_len;
5393 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005394 /* BB check that temp_ptr is still
5395 within the SMB BB*/
5396
5397 /* no trailing null to account for
5398 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 /* go on to next EA */
5400 temp_fea = (struct fea *)temp_ptr;
5401 }
5402 }
5403 }
5404 }
Steve French0d817bc2008-05-22 02:02:03 +00005405 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406 if (rc == -EAGAIN)
5407 goto QAllEAsRetry;
5408
5409 return (ssize_t)rc;
5410}
5411
Steve French50c2f752007-07-13 00:33:32 +00005412ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5413 const unsigned char *searchName, const unsigned char *ea_name,
5414 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005415 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416{
5417 TRANSACTION2_QPI_REQ *pSMB = NULL;
5418 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5419 int rc = 0;
5420 int bytes_returned;
5421 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005422 struct fea *temp_fea;
5423 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 __u16 params, byte_count;
5425
5426 cFYI(1, ("In Query EA path %s", searchName));
5427QEARetry:
5428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5429 (void **) &pSMBr);
5430 if (rc)
5431 return rc;
5432
5433 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5434 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005435 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005436 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 name_len++; /* trailing null */
5438 name_len *= 2;
5439 } else { /* BB improve the check for buffer overruns BB */
5440 name_len = strnlen(searchName, PATH_MAX);
5441 name_len++; /* trailing null */
5442 strncpy(pSMB->FileName, searchName, name_len);
5443 }
5444
Steve French50c2f752007-07-13 00:33:32 +00005445 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 pSMB->TotalDataCount = 0;
5447 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005448 /* BB find exact max SMB PDU from sess structure BB */
5449 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 pSMB->MaxSetupCount = 0;
5451 pSMB->Reserved = 0;
5452 pSMB->Flags = 0;
5453 pSMB->Timeout = 0;
5454 pSMB->Reserved2 = 0;
5455 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005456 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457 pSMB->DataCount = 0;
5458 pSMB->DataOffset = 0;
5459 pSMB->SetupCount = 1;
5460 pSMB->Reserved3 = 0;
5461 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5462 byte_count = params + 1 /* pad */ ;
5463 pSMB->TotalParameterCount = cpu_to_le16(params);
5464 pSMB->ParameterCount = pSMB->TotalParameterCount;
5465 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5466 pSMB->Reserved4 = 0;
5467 pSMB->hdr.smb_buf_length += byte_count;
5468 pSMB->ByteCount = cpu_to_le16(byte_count);
5469
5470 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5472 if (rc) {
5473 cFYI(1, ("Send error in Query EA = %d", rc));
5474 } else { /* decode response */
5475 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5476
5477 /* BB also check enough total bytes returned */
5478 /* BB we need to improve the validity checking
5479 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005480 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 rc = -EIO; /* bad smb */
5482 /* else if (pFindData){
5483 memcpy((char *) pFindData,
5484 (char *) &pSMBr->hdr.Protocol +
5485 data_offset, kl);
5486 }*/ else {
5487 /* check that length of list is not more than bcc */
5488 /* check that each entry does not go beyond length
5489 of list */
5490 /* check that each element of each entry does not
5491 go beyond end of list */
5492 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005493 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 rc = -ENODATA;
5495 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005496 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 ea_response_data = (struct fealist *)
5498 (((char *) &pSMBr->hdr.Protocol) +
5499 data_offset);
5500 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005501 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005502 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005504 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 } else {
5506 /* account for ea list len */
5507 name_len -= 4;
5508 temp_fea = ea_response_data->list;
5509 temp_ptr = (char *)temp_fea;
5510 /* loop through checking if we have a matching
5511 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005512 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 __u16 value_len;
5514 name_len -= 4;
5515 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005516 value_len =
5517 le16_to_cpu(temp_fea->value_len);
5518 /* BB validate that value_len falls within SMB,
5519 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005520 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 temp_fea->name_len) == 0) {
5522 /* found a match */
5523 rc = value_len;
5524 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005525 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 memcpy(ea_value,
5527 temp_fea->name+temp_fea->name_len+1,
5528 rc);
Steve French50c2f752007-07-13 00:33:32 +00005529 /* ea values, unlike ea
5530 names, are not null
5531 terminated */
Steve French790fe572007-07-07 19:25:05 +00005532 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 /* skip copy - calc size only */
5534 } else {
Steve French50c2f752007-07-13 00:33:32 +00005535 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 rc = -ERANGE;
5537 }
5538 break;
5539 }
5540 name_len -= temp_fea->name_len;
5541 temp_ptr += temp_fea->name_len;
5542 /* account for trailing null */
5543 name_len--;
5544 temp_ptr++;
5545 name_len -= value_len;
5546 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005547 /* No trailing null to account for in
5548 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 temp_fea = (struct fea *)temp_ptr;
5550 }
Steve French50c2f752007-07-13 00:33:32 +00005551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 }
5553 }
Steve French0d817bc2008-05-22 02:02:03 +00005554 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005555 if (rc == -EAGAIN)
5556 goto QEARetry;
5557
5558 return (ssize_t)rc;
5559}
5560
5561int
5562CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005563 const char *ea_name, const void *ea_value,
5564 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5565 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566{
5567 struct smb_com_transaction2_spi_req *pSMB = NULL;
5568 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5569 struct fealist *parm_data;
5570 int name_len;
5571 int rc = 0;
5572 int bytes_returned = 0;
5573 __u16 params, param_offset, byte_count, offset, count;
5574
5575 cFYI(1, ("In SetEA"));
5576SetEARetry:
5577 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5578 (void **) &pSMBr);
5579 if (rc)
5580 return rc;
5581
5582 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5583 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005584 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005585 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 name_len++; /* trailing null */
5587 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005588 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 name_len = strnlen(fileName, PATH_MAX);
5590 name_len++; /* trailing null */
5591 strncpy(pSMB->FileName, fileName, name_len);
5592 }
5593
5594 params = 6 + name_len;
5595
5596 /* done calculating parms using name_len of file name,
5597 now use name_len to calculate length of ea name
5598 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005599 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 name_len = 0;
5601 else
Steve French50c2f752007-07-13 00:33:32 +00005602 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005604 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005605 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005606 /* BB find max SMB PDU from sess */
5607 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 pSMB->MaxSetupCount = 0;
5609 pSMB->Reserved = 0;
5610 pSMB->Flags = 0;
5611 pSMB->Timeout = 0;
5612 pSMB->Reserved2 = 0;
5613 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005614 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 offset = param_offset + params;
5616 pSMB->InformationLevel =
5617 cpu_to_le16(SMB_SET_FILE_EA);
5618
5619 parm_data =
5620 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5621 offset);
5622 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5623 pSMB->DataOffset = cpu_to_le16(offset);
5624 pSMB->SetupCount = 1;
5625 pSMB->Reserved3 = 0;
5626 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5627 byte_count = 3 /* pad */ + params + count;
5628 pSMB->DataCount = cpu_to_le16(count);
5629 parm_data->list_len = cpu_to_le32(count);
5630 parm_data->list[0].EA_flags = 0;
5631 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005632 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005634 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005635 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 parm_data->list[0].name[name_len] = 0;
5637 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5638 /* caller ensures that ea_value_len is less than 64K but
5639 we need to ensure that it fits within the smb */
5640
Steve French50c2f752007-07-13 00:33:32 +00005641 /*BB add length check to see if it would fit in
5642 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005643 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5644 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005645 memcpy(parm_data->list[0].name+name_len+1,
5646 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647
5648 pSMB->TotalDataCount = pSMB->DataCount;
5649 pSMB->ParameterCount = cpu_to_le16(params);
5650 pSMB->TotalParameterCount = pSMB->ParameterCount;
5651 pSMB->Reserved4 = 0;
5652 pSMB->hdr.smb_buf_length += byte_count;
5653 pSMB->ByteCount = cpu_to_le16(byte_count);
5654 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5655 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005656 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658
5659 cifs_buf_release(pSMB);
5660
5661 if (rc == -EAGAIN)
5662 goto SetEARetry;
5663
5664 return rc;
5665}
5666
5667#endif