blob: 5f0b80d39923d0236b8a4b42b0377db02e27680a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchd185cda2009-04-30 17:45:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000086static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000089 struct list_head *tmp;
90 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92/* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000095 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000096 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 }
98 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070099 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101}
102
Steve Frenchad7a2922008-02-07 23:25:02 +0000103/* Allocate and return pointer to an SMB request buffer, and set basic
104 SMB information in the SMB header. If the return code is zero, this
105 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000108 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000142 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000158 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000161 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700166 /* BB FIXME add code to check if wsize needs
167 update due to negotiated smb buffer size
168 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000169 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000171 /* tell server Unix caps we support */
172 if (tcon->ses->capabilities & CAP_UNIX)
173 reset_cifs_unix_caps(
174 0 /* no xid */,
175 tcon,
176 NULL /* we do not know sb */,
177 NULL /* no vol info */);
178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
180 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000181 /* Removed call to reopen open files here.
182 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700183 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Steve French50c2f752007-07-13 00:33:32 +0000185 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700186 know whether we can continue or not without
187 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000188 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 case SMB_COM_READ_ANDX:
190 case SMB_COM_WRITE_ANDX:
191 case SMB_COM_CLOSE:
192 case SMB_COM_FIND_CLOSE2:
193 case SMB_COM_LOCKING_ANDX: {
194 unload_nls(nls_codepage);
195 return -EAGAIN;
196 }
197 }
198 } else {
199 up(&tcon->ses->sesSem);
200 }
201 unload_nls(nls_codepage);
202
203 } else {
204 return -EIO;
205 }
206 }
Steve French790fe572007-07-07 19:25:05 +0000207 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 return rc;
209
210 *request_buf = cifs_small_buf_get();
211 if (*request_buf == NULL) {
212 /* BB should we add a retry in here if not a writepage? */
213 return -ENOMEM;
214 }
215
Steve French63135e02007-07-17 17:34:02 +0000216 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000217 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Steve French790fe572007-07-07 19:25:05 +0000219 if (tcon != NULL)
220 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000223}
224
Steve French12b3b8f2006-02-09 21:12:47 +0000225int
Steve French50c2f752007-07-13 00:33:32 +0000226small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000227 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000228{
229 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000230 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000231
Steve French5815449d2006-02-14 01:36:20 +0000232 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000233 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000234 return rc;
235
Steve French04fdabe2006-02-10 05:52:50 +0000236 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000237 buffer->Mid = GetNextMid(ses->server);
238 if (ses->capabilities & CAP_UNICODE)
239 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000240 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000241 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
242
243 /* uid, tid can stay at zero as set in header assemble */
244
Steve French50c2f752007-07-13 00:33:32 +0000245 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000246 this function is used after 1st of session setup requests */
247
248 return rc;
249}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250
251/* If the return code is zero, this function must fill in request_buf pointer */
252static int
253smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
254 void **request_buf /* returned */ ,
255 void **response_buf /* returned */ )
256{
257 int rc = 0;
258
259 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
260 check for tcp and smb session status done differently
261 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000262 if (tcon) {
Steve Frenchbfb598202008-11-18 16:33:48 +0000263 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800264 /* only tree disconnect, open, and write,
265 (and ulogoff which does not have tcon)
266 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000267 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800268 (smb_command != SMB_COM_OPEN_ANDX) &&
269 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000270 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800271 smb_command));
272 return -ENODEV;
273 }
274 }
275
Steve French790fe572007-07-07 19:25:05 +0000276 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000277 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700279 /* Give Demultiplex thread up to 10 seconds to
280 reconnect, should be greater than cifs socket
281 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000282 while (tcon->ses->server->tcpStatus ==
283 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000285 (tcon->ses->server->tcpStatus ==
286 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000287 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700288 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 /* on "soft" mounts we wait once */
Steve French4b18f2a2008-04-29 00:06:05 +0000290 if (!tcon->retry ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000292 cFYI(1, ("gave up waiting on "
293 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700295 } /* else "hard" mount - keep retrying
296 until process is killed or server
297 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 } else /* TCP session is reestablished now */
299 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 nls_codepage = load_nls_default();
302 /* need to prevent multiple threads trying to
303 simultaneously reconnect the same SMB session */
304 down(&tcon->ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000305 if (tcon->ses->need_reconnect)
Steve French50c2f752007-07-13 00:33:32 +0000306 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700307 nls_codepage);
Steve French3b795212008-11-13 19:45:32 +0000308 if (!rc && (tcon->need_reconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700310 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
311 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
Steve French35028d72008-04-09 20:32:42 +0000316 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 atomic_inc(&tconInfoReconnectCount);
Steve French35028d72008-04-09 20:32:42 +0000318 /* tell server Unix caps we support */
319 if (tcon->ses->capabilities & CAP_UNIX)
320 reset_cifs_unix_caps(
321 0 /* no xid */,
322 tcon,
323 NULL /* do not know sb */,
324 NULL /* no vol info */);
325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
327 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Removed call to reopen open files here.
329 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700330 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Steve French50c2f752007-07-13 00:33:32 +0000332 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700333 know whether we can continue or not without
334 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000335 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 case SMB_COM_READ_ANDX:
337 case SMB_COM_WRITE_ANDX:
338 case SMB_COM_CLOSE:
339 case SMB_COM_FIND_CLOSE2:
340 case SMB_COM_LOCKING_ANDX: {
341 unload_nls(nls_codepage);
342 return -EAGAIN;
343 }
344 }
345 } else {
346 up(&tcon->ses->sesSem);
347 }
348 unload_nls(nls_codepage);
349
350 } else {
351 return -EIO;
352 }
353 }
Steve French790fe572007-07-07 19:25:05 +0000354 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356
357 *request_buf = cifs_buf_get();
358 if (*request_buf == NULL) {
359 /* BB should we add a retry in here if not a writepage? */
360 return -ENOMEM;
361 }
362 /* Although the original thought was we needed the response buf for */
363 /* potential retries of smb operations it turns out we can determine */
364 /* from the mid flags when the request buffer can be resent without */
365 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000366 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000367 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000370 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Steve French790fe572007-07-07 19:25:05 +0000372 if (tcon != NULL)
373 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 return rc;
376}
377
Steve French50c2f752007-07-13 00:33:32 +0000378static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
380 int rc = -EINVAL;
381 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000382 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 /* check for plausible wct, bcc and t2 data and parm sizes */
385 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000386 if (pSMB->hdr.WordCount >= 10) {
387 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
389 /* check that bcc is at least as big as parms + data */
390 /* check that bcc is less than negotiated smb buffer */
391 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000392 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000393 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000394 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000396 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700397 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000399 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000400 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
402 return 0;
403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 }
405 }
406 }
Steve French50c2f752007-07-13 00:33:32 +0000407 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 sizeof(struct smb_t2_rsp) + 16);
409 return rc;
410}
411int
412CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
413{
414 NEGOTIATE_REQ *pSMB;
415 NEGOTIATE_RSP *pSMBr;
416 int rc = 0;
417 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000418 int i;
Steve French50c2f752007-07-13 00:33:32 +0000419 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000421 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100422 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Steve French790fe572007-07-07 19:25:05 +0000424 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 server = ses->server;
426 else {
427 rc = -EIO;
428 return rc;
429 }
430 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
431 (void **) &pSMB, (void **) &pSMBr);
432 if (rc)
433 return rc;
Steve French750d1152006-06-27 06:28:30 +0000434
435 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000436 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000437 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000438 else /* if override flags set only sign/seal OR them with global auth */
439 secFlags = extended_security | ses->overrideSecFlg;
440
Steve French762e5ab2007-06-28 18:41:42 +0000441 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000442
Steve French1982c342005-08-17 12:38:22 -0700443 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000444 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000445
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000446 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000447 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000448 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
449 cFYI(1, ("Kerberos only mechanism, enable extended security"));
450 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
451 }
Steve Frenchac683922009-05-06 04:16:04 +0000452#ifdef CONFIG_CIFS_EXPERIMENTAL
453 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
454 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
455 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
456 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
457 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
458 }
459#endif
Steve French50c2f752007-07-13 00:33:32 +0000460
Steve French39798772006-05-31 22:40:51 +0000461 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000462 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000463 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
464 count += strlen(protocols[i].name) + 1;
465 /* null at end of source and target buffers anyway */
466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 pSMB->hdr.smb_buf_length += count;
468 pSMB->ByteCount = cpu_to_le16(count);
469
470 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
471 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000472 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000473 goto neg_err_exit;
474
Al Viro733f99a2006-10-14 16:48:26 +0100475 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000476 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000477 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000478 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000479 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000480 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000481 could not negotiate a common dialect */
482 rc = -EOPNOTSUPP;
483 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000484#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000485 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100486 && ((dialect == LANMAN_PROT)
487 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000489 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000490
Steve French790fe572007-07-07 19:25:05 +0000491 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000492 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000493 server->secType = LANMAN;
494 else {
495 cERROR(1, ("mount failed weak security disabled"
496 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000497 rc = -EOPNOTSUPP;
498 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000499 }
Steve French254e55e2006-06-04 05:53:15 +0000500 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
501 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
502 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000503 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000504 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000505 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
506 /* even though we do not use raw we might as well set this
507 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000508 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000509 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000510 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
511 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000512 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000513 server->capabilities = CAP_MPX_MODE;
514 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000515 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000516 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000517 /* OS/2 often does not set timezone therefore
518 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000519 * Could deviate slightly from the right zone.
520 * Smallest defined timezone difference is 15 minutes
521 * (i.e. Nepal). Rounding up/down is done to match
522 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000523 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000524 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000525 struct timespec ts, utc;
526 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400527 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
528 rsp->SrvTime.Time, 0);
Steve French50c2f752007-07-13 00:33:32 +0000529 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
530 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000531 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000532 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000533 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000534 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000535 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000536 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000537 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000538 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000539 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000540 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000541 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000542 server->timeAdj = (int)tmp;
543 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000544 }
Steve French790fe572007-07-07 19:25:05 +0000545 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000546
Steve French39798772006-05-31 22:40:51 +0000547
Steve French254e55e2006-06-04 05:53:15 +0000548 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000549 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000550
Steve French50c2f752007-07-13 00:33:32 +0000551 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000552 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000553 memcpy(server->cryptKey, rsp->EncryptionKey,
554 CIFS_CRYPTO_KEY_SIZE);
555 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
556 rc = -EIO; /* need cryptkey unless plain text */
557 goto neg_err_exit;
558 }
Steve French39798772006-05-31 22:40:51 +0000559
Steve French790fe572007-07-07 19:25:05 +0000560 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000561 /* we will not end up setting signing flags - as no signing
562 was in LANMAN and server did not return the flags on */
563 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000564#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000565 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000566 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000567 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000568 rc = -EOPNOTSUPP;
569#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000570 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000571 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000572 /* unknown wct */
573 rc = -EOPNOTSUPP;
574 goto neg_err_exit;
575 }
576 /* else wct == 17 NTLM */
577 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000578 if ((server->secMode & SECMODE_USER) == 0)
579 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000580
Steve French790fe572007-07-07 19:25:05 +0000581 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000582#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000583 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000584#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000585 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000586 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000587
Steve French790fe572007-07-07 19:25:05 +0000588 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000589 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000590 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000591 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000592 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000593 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000594 else if (secFlags & CIFSSEC_MAY_KRB5)
595 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000596 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000597 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000598 else if (secFlags & CIFSSEC_MAY_LANMAN)
599 server->secType = LANMAN;
600/* #ifdef CONFIG_CIFS_EXPERIMENTAL
601 else if (secFlags & CIFSSEC_MAY_PLNTXT)
602 server->secType = ??
603#endif */
604 else {
605 rc = -EOPNOTSUPP;
606 cERROR(1, ("Invalid security type"));
607 goto neg_err_exit;
608 }
609 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000610
Steve French254e55e2006-06-04 05:53:15 +0000611 /* one byte, so no need to convert this or EncryptionKeyLen from
612 little endian */
613 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
614 /* probably no need to store and check maxvcs */
615 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000617 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000618 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000619 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
620 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000621 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
622 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000623 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
624 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
625 CIFS_CRYPTO_KEY_SIZE);
626 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
627 && (pSMBr->EncryptionKeyLength == 0)) {
628 /* decode security blob */
629 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
630 rc = -EIO; /* no crypt key only if plain text pwd */
631 goto neg_err_exit;
632 }
633
634 /* BB might be helpful to save off the domain of server here */
635
Steve French50c2f752007-07-13 00:33:32 +0000636 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000637 (server->capabilities & CAP_EXTENDED_SECURITY)) {
638 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000639 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000641 goto neg_err_exit;
642 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500643 read_lock(&cifs_tcp_ses_lock);
644 if (server->srv_count > 1) {
645 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000646 if (memcmp(server->server_GUID,
647 pSMBr->u.extended_response.
648 GUID, 16) != 0) {
649 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000650 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000651 pSMBr->u.extended_response.GUID,
652 16);
653 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500654 } else {
655 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000656 memcpy(server->server_GUID,
657 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500658 }
Jeff Laytone187e442007-10-16 17:10:44 +0000659
660 if (count == 16) {
661 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000662 } else {
663 rc = decode_negTokenInit(pSMBr->u.extended_response.
664 SecurityBlob,
665 count - 16,
666 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000667 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000668 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000669 else
Steve French254e55e2006-06-04 05:53:15 +0000670 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
Steve French254e55e2006-06-04 05:53:15 +0000672 } else
673 server->capabilities &= ~CAP_EXTENDED_SECURITY;
674
Steve French6344a422006-06-12 04:18:35 +0000675#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000676signing_check:
Steve French6344a422006-06-12 04:18:35 +0000677#endif
Steve French762e5ab2007-06-28 18:41:42 +0000678 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
679 /* MUST_SIGN already includes the MAY_SIGN FLAG
680 so if this is zero it means that signing is disabled */
681 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000682 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000683 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000684 "packet signing to be enabled in "
685 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000686 rc = -EOPNOTSUPP;
687 }
Steve French50c2f752007-07-13 00:33:32 +0000688 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000689 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000690 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
691 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000692 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000693 if ((server->secMode &
694 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
695 cERROR(1,
696 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000697 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000698 } else
699 server->secMode |= SECMODE_SIGN_REQUIRED;
700 } else {
701 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000702 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000703 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000704 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 }
Steve French50c2f752007-07-13 00:33:32 +0000706
707neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700708 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000709
Steve French790fe572007-07-07 19:25:05 +0000710 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return rc;
712}
713
714int
715CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
716{
717 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500721
722 /* BB: do we need to check this? These should never be NULL. */
723 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
724 return -EIO;
725
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500727 * No need to return error on this operation if tid invalidated and
728 * closed on server already e.g. due to tcp session crashing. Also,
729 * the tcon is no longer on the list, so no need to take lock before
730 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 */
Steve French268875b2009-06-25 00:29:21 +0000732 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000733 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Steve French50c2f752007-07-13 00:33:32 +0000735 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700736 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500737 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 return rc;
Steve French133672e2007-11-13 22:41:37 +0000739
740 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700742 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Steve French50c2f752007-07-13 00:33:32 +0000744 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500745 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (rc == -EAGAIN)
747 rc = 0;
748
749 return rc;
750}
751
752int
753CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
754{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 LOGOFF_ANDX_REQ *pSMB;
756 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757
758 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500759
760 /*
761 * BB: do we need to check validity of ses and server? They should
762 * always be valid since we have an active reference. If not, that
763 * should probably be a BUG()
764 */
765 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 return -EIO;
767
Jeff Layton14fbf502008-11-14 13:53:46 -0500768 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000769 if (ses->need_reconnect)
770 goto session_already_dead; /* no need to send SMBlogoff if uid
771 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
773 if (rc) {
774 up(&ses->sesSem);
775 return rc;
776 }
777
Steve French3b795212008-11-13 19:45:32 +0000778 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700779
Steve French3b795212008-11-13 19:45:32 +0000780 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
782 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 pSMB->hdr.Uid = ses->Suid;
785
786 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000787 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000788session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700789 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
791 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000792 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 error */
794 if (rc == -EAGAIN)
795 rc = 0;
796 return rc;
797}
798
799int
Steve French2d785a52007-07-15 01:48:57 +0000800CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
801 __u16 type, const struct nls_table *nls_codepage, int remap)
802{
803 TRANSACTION2_SPI_REQ *pSMB = NULL;
804 TRANSACTION2_SPI_RSP *pSMBr = NULL;
805 struct unlink_psx_rq *pRqD;
806 int name_len;
807 int rc = 0;
808 int bytes_returned = 0;
809 __u16 params, param_offset, offset, byte_count;
810
811 cFYI(1, ("In POSIX delete"));
812PsxDelete:
813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
814 (void **) &pSMBr);
815 if (rc)
816 return rc;
817
818 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
819 name_len =
820 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
821 PATH_MAX, nls_codepage, remap);
822 name_len++; /* trailing null */
823 name_len *= 2;
824 } else { /* BB add path length overrun check */
825 name_len = strnlen(fileName, PATH_MAX);
826 name_len++; /* trailing null */
827 strncpy(pSMB->FileName, fileName, name_len);
828 }
829
830 params = 6 + name_len;
831 pSMB->MaxParameterCount = cpu_to_le16(2);
832 pSMB->MaxDataCount = 0; /* BB double check this with jra */
833 pSMB->MaxSetupCount = 0;
834 pSMB->Reserved = 0;
835 pSMB->Flags = 0;
836 pSMB->Timeout = 0;
837 pSMB->Reserved2 = 0;
838 param_offset = offsetof(struct smb_com_transaction2_spi_req,
839 InformationLevel) - 4;
840 offset = param_offset + params;
841
842 /* Setup pointer to Request Data (inode type) */
843 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
844 pRqD->type = cpu_to_le16(type);
845 pSMB->ParameterOffset = cpu_to_le16(param_offset);
846 pSMB->DataOffset = cpu_to_le16(offset);
847 pSMB->SetupCount = 1;
848 pSMB->Reserved3 = 0;
849 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
850 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
851
852 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
853 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
854 pSMB->ParameterCount = cpu_to_le16(params);
855 pSMB->TotalParameterCount = pSMB->ParameterCount;
856 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
857 pSMB->Reserved4 = 0;
858 pSMB->hdr.smb_buf_length += byte_count;
859 pSMB->ByteCount = cpu_to_le16(byte_count);
860 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
861 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000862 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000863 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000864 cifs_buf_release(pSMB);
865
866 cifs_stats_inc(&tcon->num_deletes);
867
868 if (rc == -EAGAIN)
869 goto PsxDelete;
870
871 return rc;
872}
873
874int
Steve French737b7582005-04-28 22:41:06 -0700875CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
876 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877{
878 DELETE_FILE_REQ *pSMB = NULL;
879 DELETE_FILE_RSP *pSMBr = NULL;
880 int rc = 0;
881 int bytes_returned;
882 int name_len;
883
884DelFileRetry:
885 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
886 (void **) &pSMBr);
887 if (rc)
888 return rc;
889
890 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
891 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000892 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700893 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 name_len++; /* trailing null */
895 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700896 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 name_len = strnlen(fileName, PATH_MAX);
898 name_len++; /* trailing null */
899 strncpy(pSMB->fileName, fileName, name_len);
900 }
901 pSMB->SearchAttributes =
902 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
903 pSMB->BufferFormat = 0x04;
904 pSMB->hdr.smb_buf_length += name_len + 1;
905 pSMB->ByteCount = cpu_to_le16(name_len + 1);
906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700908 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000909 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 cifs_buf_release(pSMB);
913 if (rc == -EAGAIN)
914 goto DelFileRetry;
915
916 return rc;
917}
918
919int
Steve French50c2f752007-07-13 00:33:32 +0000920CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700921 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
923 DELETE_DIRECTORY_REQ *pSMB = NULL;
924 DELETE_DIRECTORY_RSP *pSMBr = NULL;
925 int rc = 0;
926 int bytes_returned;
927 int name_len;
928
929 cFYI(1, ("In CIFSSMBRmDir"));
930RmDirRetry:
931 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
932 (void **) &pSMBr);
933 if (rc)
934 return rc;
935
936 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700937 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
938 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 name_len++; /* trailing null */
940 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700941 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 name_len = strnlen(dirName, PATH_MAX);
943 name_len++; /* trailing null */
944 strncpy(pSMB->DirName, dirName, name_len);
945 }
946
947 pSMB->BufferFormat = 0x04;
948 pSMB->hdr.smb_buf_length += name_len + 1;
949 pSMB->ByteCount = cpu_to_le16(name_len + 1);
950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700952 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000953 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
956 cifs_buf_release(pSMB);
957 if (rc == -EAGAIN)
958 goto RmDirRetry;
959 return rc;
960}
961
962int
963CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700964 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965{
966 int rc = 0;
967 CREATE_DIRECTORY_REQ *pSMB = NULL;
968 CREATE_DIRECTORY_RSP *pSMBr = NULL;
969 int bytes_returned;
970 int name_len;
971
972 cFYI(1, ("In CIFSSMBMkDir"));
973MkDirRetry:
974 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
975 (void **) &pSMBr);
976 if (rc)
977 return rc;
978
979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000980 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700981 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 name_len++; /* trailing null */
983 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700984 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 name_len = strnlen(name, PATH_MAX);
986 name_len++; /* trailing null */
987 strncpy(pSMB->DirName, name, name_len);
988 }
989
990 pSMB->BufferFormat = 0x04;
991 pSMB->hdr.smb_buf_length += name_len + 1;
992 pSMB->ByteCount = cpu_to_le16(name_len + 1);
993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700995 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000996 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -0700998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 cifs_buf_release(pSMB);
1000 if (rc == -EAGAIN)
1001 goto MkDirRetry;
1002 return rc;
1003}
1004
Steve French2dd29d32007-04-23 22:07:35 +00001005int
1006CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001007 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001008 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001009 const struct nls_table *nls_codepage, int remap)
1010{
1011 TRANSACTION2_SPI_REQ *pSMB = NULL;
1012 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1013 int name_len;
1014 int rc = 0;
1015 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001016 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001017 OPEN_PSX_REQ *pdata;
1018 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001019
1020 cFYI(1, ("In POSIX Create"));
1021PsxCreat:
1022 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1023 (void **) &pSMBr);
1024 if (rc)
1025 return rc;
1026
1027 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1028 name_len =
1029 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1030 PATH_MAX, nls_codepage, remap);
1031 name_len++; /* trailing null */
1032 name_len *= 2;
1033 } else { /* BB improve the check for buffer overruns BB */
1034 name_len = strnlen(name, PATH_MAX);
1035 name_len++; /* trailing null */
1036 strncpy(pSMB->FileName, name, name_len);
1037 }
1038
1039 params = 6 + name_len;
1040 count = sizeof(OPEN_PSX_REQ);
1041 pSMB->MaxParameterCount = cpu_to_le16(2);
1042 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1043 pSMB->MaxSetupCount = 0;
1044 pSMB->Reserved = 0;
1045 pSMB->Flags = 0;
1046 pSMB->Timeout = 0;
1047 pSMB->Reserved2 = 0;
1048 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001049 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001050 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001051 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001052 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001053 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001054 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001055 pdata->OpenFlags = cpu_to_le32(*pOplock);
1056 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1057 pSMB->DataOffset = cpu_to_le16(offset);
1058 pSMB->SetupCount = 1;
1059 pSMB->Reserved3 = 0;
1060 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1061 byte_count = 3 /* pad */ + params + count;
1062
1063 pSMB->DataCount = cpu_to_le16(count);
1064 pSMB->ParameterCount = cpu_to_le16(params);
1065 pSMB->TotalDataCount = pSMB->DataCount;
1066 pSMB->TotalParameterCount = pSMB->ParameterCount;
1067 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1068 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001069 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001070 pSMB->ByteCount = cpu_to_le16(byte_count);
1071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1073 if (rc) {
1074 cFYI(1, ("Posix create returned %d", rc));
1075 goto psx_create_err;
1076 }
1077
Steve French790fe572007-07-07 19:25:05 +00001078 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001079 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1080
1081 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1082 rc = -EIO; /* bad smb */
1083 goto psx_create_err;
1084 }
1085
1086 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001087 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001088 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001089
Steve French2dd29d32007-04-23 22:07:35 +00001090 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001091 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001092 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1093 /* Let caller know file was created so we can set the mode. */
1094 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001095 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001096 *pOplock |= CIFS_CREATE_ACTION;
1097 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001098 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1099 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001100 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001101 } else {
Steve French790fe572007-07-07 19:25:05 +00001102 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001103 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001104 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001105 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001106 goto psx_create_err;
1107 }
Steve French50c2f752007-07-13 00:33:32 +00001108 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001109 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001110 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001111 }
Steve French2dd29d32007-04-23 22:07:35 +00001112
1113psx_create_err:
1114 cifs_buf_release(pSMB);
1115
Steve French65bc98b2009-07-10 15:27:25 +00001116 if (posix_flags & SMB_O_DIRECTORY)
1117 cifs_stats_inc(&tcon->num_posixmkdirs);
1118 else
1119 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001120
1121 if (rc == -EAGAIN)
1122 goto PsxCreat;
1123
Steve French50c2f752007-07-13 00:33:32 +00001124 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001125}
1126
Steve Frencha9d02ad2005-08-24 23:06:05 -07001127static __u16 convert_disposition(int disposition)
1128{
1129 __u16 ofun = 0;
1130
1131 switch (disposition) {
1132 case FILE_SUPERSEDE:
1133 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1134 break;
1135 case FILE_OPEN:
1136 ofun = SMBOPEN_OAPPEND;
1137 break;
1138 case FILE_CREATE:
1139 ofun = SMBOPEN_OCREATE;
1140 break;
1141 case FILE_OPEN_IF:
1142 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1143 break;
1144 case FILE_OVERWRITE:
1145 ofun = SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OVERWRITE_IF:
1148 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1149 break;
1150 default:
Steve French790fe572007-07-07 19:25:05 +00001151 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001152 ofun = SMBOPEN_OAPPEND; /* regular open */
1153 }
1154 return ofun;
1155}
1156
Jeff Layton35fc37d2008-05-14 10:22:03 -07001157static int
1158access_flags_to_smbopen_mode(const int access_flags)
1159{
1160 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1161
1162 if (masked_flags == GENERIC_READ)
1163 return SMBOPEN_READ;
1164 else if (masked_flags == GENERIC_WRITE)
1165 return SMBOPEN_WRITE;
1166
1167 /* just go for read/write */
1168 return SMBOPEN_READWRITE;
1169}
1170
Steve Frencha9d02ad2005-08-24 23:06:05 -07001171int
1172SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1173 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001174 const int access_flags, const int create_options, __u16 *netfid,
1175 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001176 const struct nls_table *nls_codepage, int remap)
1177{
1178 int rc = -EACCES;
1179 OPENX_REQ *pSMB = NULL;
1180 OPENX_RSP *pSMBr = NULL;
1181 int bytes_returned;
1182 int name_len;
1183 __u16 count;
1184
1185OldOpenRetry:
1186 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1187 (void **) &pSMBr);
1188 if (rc)
1189 return rc;
1190
1191 pSMB->AndXCommand = 0xFF; /* none */
1192
1193 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1194 count = 1; /* account for one byte pad to word boundary */
1195 name_len =
1196 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1197 fileName, PATH_MAX, nls_codepage, remap);
1198 name_len++; /* trailing null */
1199 name_len *= 2;
1200 } else { /* BB improve check for buffer overruns BB */
1201 count = 0; /* no pad */
1202 name_len = strnlen(fileName, PATH_MAX);
1203 name_len++; /* trailing null */
1204 strncpy(pSMB->fileName, fileName, name_len);
1205 }
1206 if (*pOplock & REQ_OPLOCK)
1207 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001208 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001210
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001212 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1214 /* set file as system file if special file such
1215 as fifo and server expecting SFU style and
1216 no Unix extensions */
1217
Steve French790fe572007-07-07 19:25:05 +00001218 if (create_options & CREATE_OPTION_SPECIAL)
1219 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001220 else /* BB FIXME BB */
1221 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222
Jeff Layton67750fb2008-05-09 22:28:02 +00001223 if (create_options & CREATE_OPTION_READONLY)
1224 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001225
1226 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001227/* pSMB->CreateOptions = cpu_to_le32(create_options &
1228 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001230
1231 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001232 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 count += name_len;
1234 pSMB->hdr.smb_buf_length += count;
1235
1236 pSMB->ByteCount = cpu_to_le16(count);
1237 /* long_op set to 1 to allow for oplock break timeouts */
1238 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001239 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 cifs_stats_inc(&tcon->num_opens);
1241 if (rc) {
1242 cFYI(1, ("Error in Open = %d", rc));
1243 } else {
1244 /* BB verify if wct == 15 */
1245
Steve French582d21e2008-05-13 04:54:12 +00001246/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247
1248 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1249 /* Let caller know file was created so we can set the mode. */
1250 /* Do we care about the CreateAction in any other cases? */
1251 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001252/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 *pOplock |= CIFS_CREATE_ACTION; */
1254 /* BB FIXME END */
1255
Steve French790fe572007-07-07 19:25:05 +00001256 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1258 pfile_info->LastAccessTime = 0; /* BB fixme */
1259 pfile_info->LastWriteTime = 0; /* BB fixme */
1260 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001261 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001262 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001263 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001264 pfile_info->AllocationSize =
1265 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1266 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001268 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001269 }
1270 }
1271
1272 cifs_buf_release(pSMB);
1273 if (rc == -EAGAIN)
1274 goto OldOpenRetry;
1275 return rc;
1276}
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278int
1279CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1280 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001281 const int access_flags, const int create_options, __u16 *netfid,
1282 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001283 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284{
1285 int rc = -EACCES;
1286 OPEN_REQ *pSMB = NULL;
1287 OPEN_RSP *pSMBr = NULL;
1288 int bytes_returned;
1289 int name_len;
1290 __u16 count;
1291
1292openRetry:
1293 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1294 (void **) &pSMBr);
1295 if (rc)
1296 return rc;
1297
1298 pSMB->AndXCommand = 0xFF; /* none */
1299
1300 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1301 count = 1; /* account for one byte pad to word boundary */
1302 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001303 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001304 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 name_len++; /* trailing null */
1306 name_len *= 2;
1307 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001308 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 count = 0; /* no pad */
1310 name_len = strnlen(fileName, PATH_MAX);
1311 name_len++; /* trailing null */
1312 pSMB->NameLength = cpu_to_le16(name_len);
1313 strncpy(pSMB->fileName, fileName, name_len);
1314 }
1315 if (*pOplock & REQ_OPLOCK)
1316 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001317 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1320 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001321 /* set file as system file if special file such
1322 as fifo and server expecting SFU style and
1323 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001324 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001325 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1326 else
1327 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001328
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 /* XP does not handle ATTR_POSIX_SEMANTICS */
1330 /* but it helps speed up case sensitive checks for other
1331 servers such as Samba */
1332 if (tcon->ses->capabilities & CAP_UNIX)
1333 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1334
Jeff Layton67750fb2008-05-09 22:28:02 +00001335 if (create_options & CREATE_OPTION_READONLY)
1336 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1337
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1339 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001340 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001341 /* BB Expirement with various impersonation levels and verify */
1342 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 pSMB->SecurityFlags =
1344 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1345
1346 count += name_len;
1347 pSMB->hdr.smb_buf_length += count;
1348
1349 pSMB->ByteCount = cpu_to_le16(count);
1350 /* long_op set to 1 to allow for oplock break timeouts */
1351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001352 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha45443472005-08-24 13:59:35 -07001353 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 if (rc) {
1355 cFYI(1, ("Error in Open = %d", rc));
1356 } else {
Steve French09d1db52005-04-28 22:41:08 -07001357 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1359 /* Let caller know file was created so we can set the mode. */
1360 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001361 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001362 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001363 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001364 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1365 36 /* CreationTime to Attributes */);
1366 /* the file_info buf is endian converted by caller */
1367 pfile_info->AllocationSize = pSMBr->AllocationSize;
1368 pfile_info->EndOfFile = pSMBr->EndOfFile;
1369 pfile_info->NumberOfLinks = cpu_to_le32(1);
1370 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 cifs_buf_release(pSMB);
1375 if (rc == -EAGAIN)
1376 goto openRetry;
1377 return rc;
1378}
1379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380int
Steve French50c2f752007-07-13 00:33:32 +00001381CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1382 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1383 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384{
1385 int rc = -EACCES;
1386 READ_REQ *pSMB = NULL;
1387 READ_RSP *pSMBr = NULL;
1388 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001389 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001390 int resp_buf_type = 0;
1391 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
Steve French790fe572007-07-07 19:25:05 +00001393 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1394 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001395 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001396 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001397 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001398 if ((lseek >> 32) > 0) {
1399 /* can not handle this big offset for old */
1400 return -EIO;
1401 }
1402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403
1404 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001405 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406 if (rc)
1407 return rc;
1408
1409 /* tcon and ses pointer are checked in smb_init */
1410 if (tcon->ses->server == NULL)
1411 return -ECONNABORTED;
1412
Steve Frenchec637e32005-12-12 20:53:18 -08001413 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 pSMB->Fid = netfid;
1415 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001416 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001417 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001418
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 pSMB->Remaining = 0;
1420 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1421 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001422 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001423 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1424 else {
1425 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001426 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001427 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001428 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001429 }
Steve Frenchec637e32005-12-12 20:53:18 -08001430
1431 iov[0].iov_base = (char *)pSMB;
1432 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001433 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001434 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha45443472005-08-24 13:59:35 -07001435 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001436 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 if (rc) {
1438 cERROR(1, ("Send error in read = %d", rc));
1439 } else {
1440 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1441 data_length = data_length << 16;
1442 data_length += le16_to_cpu(pSMBr->DataLength);
1443 *nbytes = data_length;
1444
1445 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001446 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001448 cFYI(1, ("bad length %d for count %d",
1449 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 rc = -EIO;
1451 *nbytes = 0;
1452 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001453 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001454 le16_to_cpu(pSMBr->DataOffset);
1455/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001456 cERROR(1,("Faulting on read rc = %d",rc));
1457 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001458 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001459 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001460 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 }
1462 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463
Steve French4b8f9302006-02-26 16:41:18 +00001464/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001465 if (*buf) {
1466 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001467 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001468 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001469 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001470 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001471 /* return buffer to caller to free */
1472 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001473 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001474 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001475 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001476 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001477 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001478
1479 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 since file handle passed in no longer valid */
1481 return rc;
1482}
1483
Steve Frenchec637e32005-12-12 20:53:18 -08001484
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485int
1486CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1487 const int netfid, const unsigned int count,
1488 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001489 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490{
1491 int rc = -EACCES;
1492 WRITE_REQ *pSMB = NULL;
1493 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001494 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 __u32 bytes_sent;
1496 __u16 byte_count;
1497
Steve French61de8002008-10-30 20:15:22 +00001498 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001499 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001500 return -ECONNABORTED;
1501
Steve French790fe572007-07-07 19:25:05 +00001502 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001503 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001504 else {
Steve French1c955182005-08-30 20:58:07 -07001505 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001506 if ((offset >> 32) > 0) {
1507 /* can not handle big offset for old srv */
1508 return -EIO;
1509 }
1510 }
Steve French1c955182005-08-30 20:58:07 -07001511
1512 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 (void **) &pSMBr);
1514 if (rc)
1515 return rc;
1516 /* tcon and ses pointer are checked in smb_init */
1517 if (tcon->ses->server == NULL)
1518 return -ECONNABORTED;
1519
1520 pSMB->AndXCommand = 0xFF; /* none */
1521 pSMB->Fid = netfid;
1522 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001523 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001524 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 pSMB->Reserved = 0xFFFFFFFF;
1527 pSMB->WriteMode = 0;
1528 pSMB->Remaining = 0;
1529
Steve French50c2f752007-07-13 00:33:32 +00001530 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 can send more if LARGE_WRITE_X capability returned by the server and if
1532 our buffer is big enough or if we convert to iovecs on socket writes
1533 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001534 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1536 } else {
1537 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1538 & ~0xFF;
1539 }
1540
1541 if (bytes_sent > count)
1542 bytes_sent = count;
1543 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001544 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001545 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001546 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001547 else if (ubuf) {
1548 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 cifs_buf_release(pSMB);
1550 return -EFAULT;
1551 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001552 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 /* No buffer */
1554 cifs_buf_release(pSMB);
1555 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001557 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001558 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001559 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001561
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1563 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001565
Steve French790fe572007-07-07 19:25:05 +00001566 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001567 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001568 else { /* old style write has byte count 4 bytes earlier
1569 so 4 bytes pad */
1570 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001571 (struct smb_com_writex_req *)pSMB;
1572 pSMBW->ByteCount = cpu_to_le16(byte_count);
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1576 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001577 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (rc) {
1579 cFYI(1, ("Send error in write = %d", rc));
1580 *nbytes = 0;
1581 } else {
1582 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1583 *nbytes = (*nbytes) << 16;
1584 *nbytes += le16_to_cpu(pSMBr->Count);
1585 }
1586
1587 cifs_buf_release(pSMB);
1588
Steve French50c2f752007-07-13 00:33:32 +00001589 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 since file handle passed in no longer valid */
1591
1592 return rc;
1593}
1594
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001595int
1596CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001598 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1599 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600{
1601 int rc = -EACCES;
1602 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001603 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001604 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001605 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001607 *nbytes = 0;
1608
Steve French790fe572007-07-07 19:25:05 +00001609 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001610
Steve French4c3130e2008-12-09 00:28:16 +00001611 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001612 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001613 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001614 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001615 if ((offset >> 32) > 0) {
1616 /* can not handle big offset for old srv */
1617 return -EIO;
1618 }
1619 }
Steve French8cc64c62005-10-03 13:49:43 -07001620 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 if (rc)
1622 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 /* tcon and ses pointer are checked in smb_init */
1624 if (tcon->ses->server == NULL)
1625 return -ECONNABORTED;
1626
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001627 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 pSMB->Fid = netfid;
1629 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001630 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001631 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 pSMB->Reserved = 0xFFFFFFFF;
1633 pSMB->WriteMode = 0;
1634 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001635
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001637 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638
Steve French3e844692005-10-03 13:37:24 -07001639 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1640 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001641 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001642 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001643 pSMB->hdr.smb_buf_length += count+1;
1644 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001645 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1646 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001647 pSMB->ByteCount = cpu_to_le16(count + 1);
1648 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001649 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001650 (struct smb_com_writex_req *)pSMB;
1651 pSMBW->ByteCount = cpu_to_le16(count + 5);
1652 }
Steve French3e844692005-10-03 13:37:24 -07001653 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001654 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001655 iov[0].iov_len = smb_hdr_len + 4;
1656 else /* wct == 12 pad bigger by four bytes */
1657 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001658
Steve French3e844692005-10-03 13:37:24 -07001659
Steve Frenchec637e32005-12-12 20:53:18 -08001660 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001661 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001662 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001664 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001665 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001666 /* presumably this can not happen, but best to be safe */
1667 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001668 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001669 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001670 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1671 *nbytes = (*nbytes) << 16;
1672 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
Steve French4b8f9302006-02-26 16:41:18 +00001675/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001676 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001677 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001678 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001679 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680
Steve French50c2f752007-07-13 00:33:32 +00001681 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 since file handle passed in no longer valid */
1683
1684 return rc;
1685}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001686
1687
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688int
1689CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1690 const __u16 smb_file_id, const __u64 len,
1691 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001692 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693{
1694 int rc = 0;
1695 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001696/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 int bytes_returned;
1698 int timeout = 0;
1699 __u16 count;
1700
Steve French4b18f2a2008-04-29 00:06:05 +00001701 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001702 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 if (rc)
1705 return rc;
1706
Steve French790fe572007-07-07 19:25:05 +00001707 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001708 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001710 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001711 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1713 } else {
1714 pSMB->Timeout = 0;
1715 }
1716
1717 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1718 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1719 pSMB->LockType = lockType;
1720 pSMB->AndXCommand = 0xFF; /* none */
1721 pSMB->Fid = smb_file_id; /* netfid stays le */
1722
Steve French790fe572007-07-07 19:25:05 +00001723 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1725 /* BB where to store pid high? */
1726 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1727 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1728 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1729 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1730 count = sizeof(LOCKING_ANDX_RANGE);
1731 } else {
1732 /* oplock break */
1733 count = 0;
1734 }
1735 pSMB->hdr.smb_buf_length += count;
1736 pSMB->ByteCount = cpu_to_le16(count);
1737
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001738 if (waitFlag) {
1739 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001740 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001741 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001742 } else {
Steve French133672e2007-11-13 22:41:37 +00001743 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1744 timeout);
1745 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001746 }
Steve Frencha45443472005-08-24 13:59:35 -07001747 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001748 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
Steve French50c2f752007-07-13 00:33:32 +00001751 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 since file handle passed in no longer valid */
1753 return rc;
1754}
1755
1756int
Steve French08547b02006-02-28 22:39:25 +00001757CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1758 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001759 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001760 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001761{
1762 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1763 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001764 struct cifs_posix_lock *parm_data;
1765 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001766 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001767 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001768 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001769 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001770 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001771
1772 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001773
Steve French790fe572007-07-07 19:25:05 +00001774 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001775 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001776
Steve French08547b02006-02-28 22:39:25 +00001777 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1778
1779 if (rc)
1780 return rc;
1781
1782 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1783
Steve French50c2f752007-07-13 00:33:32 +00001784 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001785 pSMB->MaxSetupCount = 0;
1786 pSMB->Reserved = 0;
1787 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001788 pSMB->Reserved2 = 0;
1789 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1790 offset = param_offset + params;
1791
Steve French08547b02006-02-28 22:39:25 +00001792 count = sizeof(struct cifs_posix_lock);
1793 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001794 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001795 pSMB->SetupCount = 1;
1796 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001797 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001798 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1799 else
1800 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1801 byte_count = 3 /* pad */ + params + count;
1802 pSMB->DataCount = cpu_to_le16(count);
1803 pSMB->ParameterCount = cpu_to_le16(params);
1804 pSMB->TotalDataCount = pSMB->DataCount;
1805 pSMB->TotalParameterCount = pSMB->ParameterCount;
1806 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001807 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001808 (((char *) &pSMB->hdr.Protocol) + offset);
1809
1810 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001811 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001812 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001813 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001814 pSMB->Timeout = cpu_to_le32(-1);
1815 } else
1816 pSMB->Timeout = 0;
1817
Steve French08547b02006-02-28 22:39:25 +00001818 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001819 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001820 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001821
1822 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001823 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001824 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1825 pSMB->Reserved4 = 0;
1826 pSMB->hdr.smb_buf_length += byte_count;
1827 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001828 if (waitFlag) {
1829 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1830 (struct smb_hdr *) pSMBr, &bytes_returned);
1831 } else {
Steve French133672e2007-11-13 22:41:37 +00001832 iov[0].iov_base = (char *)pSMB;
1833 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1834 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1835 &resp_buf_type, timeout);
1836 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1837 not try to free it twice below on exit */
1838 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001839 }
1840
Steve French08547b02006-02-28 22:39:25 +00001841 if (rc) {
1842 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001843 } else if (get_flag) {
1844 /* lock structure can be returned on get */
1845 __u16 data_offset;
1846 __u16 data_count;
1847 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001848
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001849 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1850 rc = -EIO; /* bad smb */
1851 goto plk_err_exit;
1852 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001853 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1854 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001855 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001856 rc = -EIO;
1857 goto plk_err_exit;
1858 }
1859 parm_data = (struct cifs_posix_lock *)
1860 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001861 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001862 pLockData->fl_type = F_UNLCK;
1863 }
Steve French50c2f752007-07-13 00:33:32 +00001864
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001865plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001866 if (pSMB)
1867 cifs_small_buf_release(pSMB);
1868
Steve French133672e2007-11-13 22:41:37 +00001869 if (resp_buf_type == CIFS_SMALL_BUFFER)
1870 cifs_small_buf_release(iov[0].iov_base);
1871 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1872 cifs_buf_release(iov[0].iov_base);
1873
Steve French08547b02006-02-28 22:39:25 +00001874 /* Note: On -EAGAIN error only caller can retry on handle based calls
1875 since file handle passed in no longer valid */
1876
1877 return rc;
1878}
1879
1880
1881int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1883{
1884 int rc = 0;
1885 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 cFYI(1, ("In CIFSSMBClose"));
1887
1888/* do not retry on dead session on close */
1889 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001890 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 return 0;
1892 if (rc)
1893 return rc;
1894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001896 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001898 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001899 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001901 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 /* EINTR is expected when user ctl-c to kill app */
1903 cERROR(1, ("Send error in Close = %d", rc));
1904 }
1905 }
1906
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001908 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 rc = 0;
1910
1911 return rc;
1912}
1913
1914int
Steve Frenchb298f222009-02-21 21:17:43 +00001915CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1916{
1917 int rc = 0;
1918 FLUSH_REQ *pSMB = NULL;
1919 cFYI(1, ("In CIFSSMBFlush"));
1920
1921 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1922 if (rc)
1923 return rc;
1924
1925 pSMB->FileID = (__u16) smb_file_id;
1926 pSMB->ByteCount = 0;
1927 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1928 cifs_stats_inc(&tcon->num_flushes);
1929 if (rc)
1930 cERROR(1, ("Send error in Flush = %d", rc));
1931
1932 return rc;
1933}
1934
1935int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1937 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001938 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939{
1940 int rc = 0;
1941 RENAME_REQ *pSMB = NULL;
1942 RENAME_RSP *pSMBr = NULL;
1943 int bytes_returned;
1944 int name_len, name_len2;
1945 __u16 count;
1946
1947 cFYI(1, ("In CIFSSMBRename"));
1948renameRetry:
1949 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1950 (void **) &pSMBr);
1951 if (rc)
1952 return rc;
1953
1954 pSMB->BufferFormat = 0x04;
1955 pSMB->SearchAttributes =
1956 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1957 ATTR_DIRECTORY);
1958
1959 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1960 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001961 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 name_len++; /* trailing null */
1964 name_len *= 2;
1965 pSMB->OldFileName[name_len] = 0x04; /* pad */
1966 /* protocol requires ASCII signature byte on Unicode string */
1967 pSMB->OldFileName[name_len + 1] = 0x00;
1968 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001969 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001970 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1972 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001973 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 name_len = strnlen(fromName, PATH_MAX);
1975 name_len++; /* trailing null */
1976 strncpy(pSMB->OldFileName, fromName, name_len);
1977 name_len2 = strnlen(toName, PATH_MAX);
1978 name_len2++; /* trailing null */
1979 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1980 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1981 name_len2++; /* trailing null */
1982 name_len2++; /* signature byte */
1983 }
1984
1985 count = 1 /* 1st signature byte */ + name_len + name_len2;
1986 pSMB->hdr.smb_buf_length += count;
1987 pSMB->ByteCount = cpu_to_le16(count);
1988
1989 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1990 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001991 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001992 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 cifs_buf_release(pSMB);
1996
1997 if (rc == -EAGAIN)
1998 goto renameRetry;
1999
2000 return rc;
2001}
2002
Steve French50c2f752007-07-13 00:33:32 +00002003int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002004 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002005 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006{
2007 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2008 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002009 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 char *data_offset;
2011 char dummy_string[30];
2012 int rc = 0;
2013 int bytes_returned = 0;
2014 int len_of_str;
2015 __u16 params, param_offset, offset, count, byte_count;
2016
2017 cFYI(1, ("Rename to File by handle"));
2018 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2019 (void **) &pSMBr);
2020 if (rc)
2021 return rc;
2022
2023 params = 6;
2024 pSMB->MaxSetupCount = 0;
2025 pSMB->Reserved = 0;
2026 pSMB->Flags = 0;
2027 pSMB->Timeout = 0;
2028 pSMB->Reserved2 = 0;
2029 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2030 offset = param_offset + params;
2031
2032 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2033 rename_info = (struct set_file_rename *) data_offset;
2034 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002035 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 pSMB->SetupCount = 1;
2037 pSMB->Reserved3 = 0;
2038 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2039 byte_count = 3 /* pad */ + params;
2040 pSMB->ParameterCount = cpu_to_le16(params);
2041 pSMB->TotalParameterCount = pSMB->ParameterCount;
2042 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2043 pSMB->DataOffset = cpu_to_le16(offset);
2044 /* construct random name ".cifs_tmp<inodenum><mid>" */
2045 rename_info->overwrite = cpu_to_le32(1);
2046 rename_info->root_fid = 0;
2047 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002048 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002049 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2050 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002051 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002053 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002054 target_name, PATH_MAX, nls_codepage,
2055 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 }
2057 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002058 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 byte_count += count;
2060 pSMB->DataCount = cpu_to_le16(count);
2061 pSMB->TotalDataCount = pSMB->DataCount;
2062 pSMB->Fid = netfid;
2063 pSMB->InformationLevel =
2064 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2065 pSMB->Reserved4 = 0;
2066 pSMB->hdr.smb_buf_length += byte_count;
2067 pSMB->ByteCount = cpu_to_le16(byte_count);
2068 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002070 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002071 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002072 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002073
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 cifs_buf_release(pSMB);
2075
2076 /* Note: On -EAGAIN error only caller can retry on handle based calls
2077 since file handle passed in no longer valid */
2078
2079 return rc;
2080}
2081
2082int
Steve French50c2f752007-07-13 00:33:32 +00002083CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2084 const __u16 target_tid, const char *toName, const int flags,
2085 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086{
2087 int rc = 0;
2088 COPY_REQ *pSMB = NULL;
2089 COPY_RSP *pSMBr = NULL;
2090 int bytes_returned;
2091 int name_len, name_len2;
2092 __u16 count;
2093
2094 cFYI(1, ("In CIFSSMBCopy"));
2095copyRetry:
2096 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2097 (void **) &pSMBr);
2098 if (rc)
2099 return rc;
2100
2101 pSMB->BufferFormat = 0x04;
2102 pSMB->Tid2 = target_tid;
2103
2104 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2105
2106 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002107 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002108 fromName, PATH_MAX, nls_codepage,
2109 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 name_len++; /* trailing null */
2111 name_len *= 2;
2112 pSMB->OldFileName[name_len] = 0x04; /* pad */
2113 /* protocol requires ASCII signature byte on Unicode string */
2114 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002115 name_len2 =
2116 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002117 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2119 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002120 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 name_len = strnlen(fromName, PATH_MAX);
2122 name_len++; /* trailing null */
2123 strncpy(pSMB->OldFileName, fromName, name_len);
2124 name_len2 = strnlen(toName, PATH_MAX);
2125 name_len2++; /* trailing null */
2126 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2127 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2128 name_len2++; /* trailing null */
2129 name_len2++; /* signature byte */
2130 }
2131
2132 count = 1 /* 1st signature byte */ + name_len + name_len2;
2133 pSMB->hdr.smb_buf_length += count;
2134 pSMB->ByteCount = cpu_to_le16(count);
2135
2136 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2138 if (rc) {
2139 cFYI(1, ("Send error in copy = %d with %d files copied",
2140 rc, le16_to_cpu(pSMBr->CopyCount)));
2141 }
Steve French0d817bc2008-05-22 02:02:03 +00002142 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143
2144 if (rc == -EAGAIN)
2145 goto copyRetry;
2146
2147 return rc;
2148}
2149
2150int
2151CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2152 const char *fromName, const char *toName,
2153 const struct nls_table *nls_codepage)
2154{
2155 TRANSACTION2_SPI_REQ *pSMB = NULL;
2156 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2157 char *data_offset;
2158 int name_len;
2159 int name_len_target;
2160 int rc = 0;
2161 int bytes_returned = 0;
2162 __u16 params, param_offset, offset, byte_count;
2163
2164 cFYI(1, ("In Symlink Unix style"));
2165createSymLinkRetry:
2166 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2167 (void **) &pSMBr);
2168 if (rc)
2169 return rc;
2170
2171 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2172 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002173 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* find define for this maxpathcomponent */
2175 , nls_codepage);
2176 name_len++; /* trailing null */
2177 name_len *= 2;
2178
Steve French50c2f752007-07-13 00:33:32 +00002179 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 name_len = strnlen(fromName, PATH_MAX);
2181 name_len++; /* trailing null */
2182 strncpy(pSMB->FileName, fromName, name_len);
2183 }
2184 params = 6 + name_len;
2185 pSMB->MaxSetupCount = 0;
2186 pSMB->Reserved = 0;
2187 pSMB->Flags = 0;
2188 pSMB->Timeout = 0;
2189 pSMB->Reserved2 = 0;
2190 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002191 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 offset = param_offset + params;
2193
2194 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2195 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2196 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002197 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 /* find define for this maxpathcomponent */
2199 , nls_codepage);
2200 name_len_target++; /* trailing null */
2201 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002202 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 name_len_target = strnlen(toName, PATH_MAX);
2204 name_len_target++; /* trailing null */
2205 strncpy(data_offset, toName, name_len_target);
2206 }
2207
2208 pSMB->MaxParameterCount = cpu_to_le16(2);
2209 /* BB find exact max on data count below from sess */
2210 pSMB->MaxDataCount = cpu_to_le16(1000);
2211 pSMB->SetupCount = 1;
2212 pSMB->Reserved3 = 0;
2213 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2214 byte_count = 3 /* pad */ + params + name_len_target;
2215 pSMB->DataCount = cpu_to_le16(name_len_target);
2216 pSMB->ParameterCount = cpu_to_le16(params);
2217 pSMB->TotalDataCount = pSMB->DataCount;
2218 pSMB->TotalParameterCount = pSMB->ParameterCount;
2219 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2220 pSMB->DataOffset = cpu_to_le16(offset);
2221 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2222 pSMB->Reserved4 = 0;
2223 pSMB->hdr.smb_buf_length += byte_count;
2224 pSMB->ByteCount = cpu_to_le16(byte_count);
2225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002227 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002228 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002229 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Steve French0d817bc2008-05-22 02:02:03 +00002231 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
2233 if (rc == -EAGAIN)
2234 goto createSymLinkRetry;
2235
2236 return rc;
2237}
2238
2239int
2240CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2241 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002242 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243{
2244 TRANSACTION2_SPI_REQ *pSMB = NULL;
2245 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2246 char *data_offset;
2247 int name_len;
2248 int name_len_target;
2249 int rc = 0;
2250 int bytes_returned = 0;
2251 __u16 params, param_offset, offset, byte_count;
2252
2253 cFYI(1, ("In Create Hard link Unix style"));
2254createHardLinkRetry:
2255 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2256 (void **) &pSMBr);
2257 if (rc)
2258 return rc;
2259
2260 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002261 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002262 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 name_len++; /* trailing null */
2264 name_len *= 2;
2265
Steve French50c2f752007-07-13 00:33:32 +00002266 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 name_len = strnlen(toName, PATH_MAX);
2268 name_len++; /* trailing null */
2269 strncpy(pSMB->FileName, toName, name_len);
2270 }
2271 params = 6 + name_len;
2272 pSMB->MaxSetupCount = 0;
2273 pSMB->Reserved = 0;
2274 pSMB->Flags = 0;
2275 pSMB->Timeout = 0;
2276 pSMB->Reserved2 = 0;
2277 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002278 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 offset = param_offset + params;
2280
2281 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2282 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2283 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002284 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002285 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 name_len_target++; /* trailing null */
2287 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002288 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 name_len_target = strnlen(fromName, PATH_MAX);
2290 name_len_target++; /* trailing null */
2291 strncpy(data_offset, fromName, name_len_target);
2292 }
2293
2294 pSMB->MaxParameterCount = cpu_to_le16(2);
2295 /* BB find exact max on data count below from sess*/
2296 pSMB->MaxDataCount = cpu_to_le16(1000);
2297 pSMB->SetupCount = 1;
2298 pSMB->Reserved3 = 0;
2299 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2300 byte_count = 3 /* pad */ + params + name_len_target;
2301 pSMB->ParameterCount = cpu_to_le16(params);
2302 pSMB->TotalParameterCount = pSMB->ParameterCount;
2303 pSMB->DataCount = cpu_to_le16(name_len_target);
2304 pSMB->TotalDataCount = pSMB->DataCount;
2305 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2306 pSMB->DataOffset = cpu_to_le16(offset);
2307 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2308 pSMB->Reserved4 = 0;
2309 pSMB->hdr.smb_buf_length += byte_count;
2310 pSMB->ByteCount = cpu_to_le16(byte_count);
2311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002313 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002314 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316
2317 cifs_buf_release(pSMB);
2318 if (rc == -EAGAIN)
2319 goto createHardLinkRetry;
2320
2321 return rc;
2322}
2323
2324int
2325CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2326 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002327 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328{
2329 int rc = 0;
2330 NT_RENAME_REQ *pSMB = NULL;
2331 RENAME_RSP *pSMBr = NULL;
2332 int bytes_returned;
2333 int name_len, name_len2;
2334 __u16 count;
2335
2336 cFYI(1, ("In CIFSCreateHardLink"));
2337winCreateHardLinkRetry:
2338
2339 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2340 (void **) &pSMBr);
2341 if (rc)
2342 return rc;
2343
2344 pSMB->SearchAttributes =
2345 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2346 ATTR_DIRECTORY);
2347 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2348 pSMB->ClusterCount = 0;
2349
2350 pSMB->BufferFormat = 0x04;
2351
2352 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2353 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002354 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002355 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 name_len++; /* trailing null */
2357 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002358
2359 /* protocol specifies ASCII buffer format (0x04) for unicode */
2360 pSMB->OldFileName[name_len] = 0x04;
2361 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002363 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002364 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2366 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002367 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 name_len = strnlen(fromName, PATH_MAX);
2369 name_len++; /* trailing null */
2370 strncpy(pSMB->OldFileName, fromName, name_len);
2371 name_len2 = strnlen(toName, PATH_MAX);
2372 name_len2++; /* trailing null */
2373 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2374 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2375 name_len2++; /* trailing null */
2376 name_len2++; /* signature byte */
2377 }
2378
2379 count = 1 /* string type byte */ + name_len + name_len2;
2380 pSMB->hdr.smb_buf_length += count;
2381 pSMB->ByteCount = cpu_to_le16(count);
2382
2383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002385 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002386 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002388
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 cifs_buf_release(pSMB);
2390 if (rc == -EAGAIN)
2391 goto winCreateHardLinkRetry;
2392
2393 return rc;
2394}
2395
2396int
2397CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002398 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 const struct nls_table *nls_codepage)
2400{
2401/* SMB_QUERY_FILE_UNIX_LINK */
2402 TRANSACTION2_QPI_REQ *pSMB = NULL;
2403 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2404 int rc = 0;
2405 int bytes_returned;
2406 int name_len;
2407 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002408 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2411
2412querySymLinkRetry:
2413 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2414 (void **) &pSMBr);
2415 if (rc)
2416 return rc;
2417
2418 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2419 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002420 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2421 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 name_len++; /* trailing null */
2423 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002424 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 name_len = strnlen(searchName, PATH_MAX);
2426 name_len++; /* trailing null */
2427 strncpy(pSMB->FileName, searchName, name_len);
2428 }
2429
2430 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2431 pSMB->TotalDataCount = 0;
2432 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002433 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 pSMB->MaxSetupCount = 0;
2435 pSMB->Reserved = 0;
2436 pSMB->Flags = 0;
2437 pSMB->Timeout = 0;
2438 pSMB->Reserved2 = 0;
2439 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002440 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 pSMB->DataCount = 0;
2442 pSMB->DataOffset = 0;
2443 pSMB->SetupCount = 1;
2444 pSMB->Reserved3 = 0;
2445 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2446 byte_count = params + 1 /* pad */ ;
2447 pSMB->TotalParameterCount = cpu_to_le16(params);
2448 pSMB->ParameterCount = pSMB->TotalParameterCount;
2449 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2450 pSMB->Reserved4 = 0;
2451 pSMB->hdr.smb_buf_length += byte_count;
2452 pSMB->ByteCount = cpu_to_le16(byte_count);
2453
2454 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2455 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2456 if (rc) {
2457 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2458 } else {
2459 /* decode response */
2460
2461 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002463 if (rc || (pSMBr->ByteCount < 2))
2464 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002466 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002467 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468
Jeff Layton460b9692009-04-30 07:17:56 -04002469 data_start = ((char *) &pSMBr->hdr.Protocol) +
2470 le16_to_cpu(pSMBr->t2.DataOffset);
2471
Steve French0e0d2cf2009-05-01 05:27:32 +00002472 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2473 is_unicode = true;
2474 else
2475 is_unicode = false;
2476
Steve French737b7582005-04-28 22:41:06 -07002477 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002478 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002479 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002480 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002481 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002482 }
2483 }
2484 cifs_buf_release(pSMB);
2485 if (rc == -EAGAIN)
2486 goto querySymLinkRetry;
2487 return rc;
2488}
2489
Parag Warudkarc9489772007-10-23 18:09:48 +00002490#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002491/* Initialize NT TRANSACT SMB into small smb request buffer.
2492 This assumes that all NT TRANSACTS that we init here have
2493 total parm and data under about 400 bytes (to fit in small cifs
2494 buffer size), which is the case so far, it easily fits. NB:
2495 Setup words themselves and ByteCount
2496 MaxSetupCount (size of returned setup area) and
2497 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002498static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002499smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002500 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002501 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002502{
2503 int rc;
2504 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002505 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002506
2507 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2508 (void **)&pSMB);
2509 if (rc)
2510 return rc;
2511 *ret_buf = (void *)pSMB;
2512 pSMB->Reserved = 0;
2513 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2514 pSMB->TotalDataCount = 0;
2515 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2516 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2517 pSMB->ParameterCount = pSMB->TotalParameterCount;
2518 pSMB->DataCount = pSMB->TotalDataCount;
2519 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2520 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2521 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2522 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2523 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2524 pSMB->SubCommand = cpu_to_le16(sub_command);
2525 return 0;
2526}
2527
2528static int
Steve French50c2f752007-07-13 00:33:32 +00002529validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002530 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002531{
Steve French50c2f752007-07-13 00:33:32 +00002532 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002533 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002534 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002535
Steve French630f3f0c2007-10-25 21:17:17 +00002536 *pdatalen = 0;
2537 *pparmlen = 0;
2538
Steve French790fe572007-07-07 19:25:05 +00002539 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002540 return -EINVAL;
2541
2542 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2543
2544 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002545 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002546 (char *)&pSMBr->ByteCount;
2547
Steve French0a4b92c2006-01-12 15:44:21 -08002548 data_offset = le32_to_cpu(pSMBr->DataOffset);
2549 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002550 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002551 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2552
2553 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2554 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2555
2556 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002557 if (*ppparm > end_of_smb) {
2558 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002559 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002560 } else if (parm_count + *ppparm > end_of_smb) {
2561 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002562 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002563 } else if (*ppdata > end_of_smb) {
2564 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002565 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002566 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002567 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002568 *ppdata, data_count, (data_count + *ppdata),
2569 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002570 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002571 } else if (parm_count + data_count > pSMBr->ByteCount) {
2572 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002573 return -EINVAL;
2574 }
Steve French630f3f0c2007-10-25 21:17:17 +00002575 *pdatalen = data_count;
2576 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002577 return 0;
2578}
2579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580int
2581CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2582 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002583 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 const struct nls_table *nls_codepage)
2585{
2586 int rc = 0;
2587 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002588 struct smb_com_transaction_ioctl_req *pSMB;
2589 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590
2591 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2592 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2593 (void **) &pSMBr);
2594 if (rc)
2595 return rc;
2596
2597 pSMB->TotalParameterCount = 0 ;
2598 pSMB->TotalDataCount = 0;
2599 pSMB->MaxParameterCount = cpu_to_le32(2);
2600 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002601 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2602 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 pSMB->MaxSetupCount = 4;
2604 pSMB->Reserved = 0;
2605 pSMB->ParameterOffset = 0;
2606 pSMB->DataCount = 0;
2607 pSMB->DataOffset = 0;
2608 pSMB->SetupCount = 4;
2609 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2610 pSMB->ParameterCount = pSMB->TotalParameterCount;
2611 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2612 pSMB->IsFsctl = 1; /* FSCTL */
2613 pSMB->IsRootFlag = 0;
2614 pSMB->Fid = fid; /* file handle always le */
2615 pSMB->ByteCount = 0;
2616
2617 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2618 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2619 if (rc) {
2620 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2621 } else { /* decode response */
2622 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2623 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002624 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 /* BB also check enough total bytes returned */
2626 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002627 goto qreparse_out;
2628 }
2629 if (data_count && (data_count < 2048)) {
2630 char *end_of_smb = 2 /* sizeof byte count */ +
2631 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
Steve Frenchafe48c32009-05-02 05:25:46 +00002633 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002634 (struct reparse_data *)
2635 ((char *)&pSMBr->hdr.Protocol
2636 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002637 if ((char *)reparse_buf >= end_of_smb) {
2638 rc = -EIO;
2639 goto qreparse_out;
2640 }
2641 if ((reparse_buf->LinkNamesBuf +
2642 reparse_buf->TargetNameOffset +
2643 reparse_buf->TargetNameLen) > end_of_smb) {
2644 cFYI(1, ("reparse buf beyond SMB"));
2645 rc = -EIO;
2646 goto qreparse_out;
2647 }
Steve French50c2f752007-07-13 00:33:32 +00002648
Steve Frenchafe48c32009-05-02 05:25:46 +00002649 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2650 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002651 (reparse_buf->LinkNamesBuf +
2652 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002653 buflen,
2654 reparse_buf->TargetNameLen,
2655 nls_codepage, 0);
2656 } else { /* ASCII names */
2657 strncpy(symlinkinfo,
2658 reparse_buf->LinkNamesBuf +
2659 reparse_buf->TargetNameOffset,
2660 min_t(const int, buflen,
2661 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002663 } else {
2664 rc = -EIO;
2665 cFYI(1, ("Invalid return data count on "
2666 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002668 symlinkinfo[buflen] = 0; /* just in case so the caller
2669 does not go off the end of the buffer */
2670 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 }
Steve French989c7e52009-05-02 05:32:20 +00002672
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002674 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
2676 /* Note: On -EAGAIN error only caller can retry on handle based calls
2677 since file handle passed in no longer valid */
2678
2679 return rc;
2680}
Steve Frenchafe48c32009-05-02 05:25:46 +00002681#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682
2683#ifdef CONFIG_CIFS_POSIX
2684
2685/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002686static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2687 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688{
2689 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002690 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2691 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2692 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2694
2695 return;
2696}
2697
2698/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002699static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2700 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701{
2702 int size = 0;
2703 int i;
2704 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002705 struct cifs_posix_ace *pACE;
2706 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2707 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708
2709 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2710 return -EOPNOTSUPP;
2711
Steve French790fe572007-07-07 19:25:05 +00002712 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 count = le16_to_cpu(cifs_acl->access_entry_count);
2714 pACE = &cifs_acl->ace_array[0];
2715 size = sizeof(struct cifs_posix_acl);
2716 size += sizeof(struct cifs_posix_ace) * count;
2717 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002718 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002719 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2720 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 return -EINVAL;
2722 }
Steve French790fe572007-07-07 19:25:05 +00002723 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 count = le16_to_cpu(cifs_acl->access_entry_count);
2725 size = sizeof(struct cifs_posix_acl);
2726 size += sizeof(struct cifs_posix_ace) * count;
2727/* skip past access ACEs to get to default ACEs */
2728 pACE = &cifs_acl->ace_array[count];
2729 count = le16_to_cpu(cifs_acl->default_entry_count);
2730 size += sizeof(struct cifs_posix_ace) * count;
2731 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002732 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 return -EINVAL;
2734 } else {
2735 /* illegal type */
2736 return -EINVAL;
2737 }
2738
2739 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002740 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002741 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002742 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 return -ERANGE;
2744 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002745 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002746 for (i = 0; i < count ; i++) {
2747 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2748 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 }
2750 }
2751 return size;
2752}
2753
Steve French50c2f752007-07-13 00:33:32 +00002754static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2755 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756{
2757 __u16 rc = 0; /* 0 = ACL converted ok */
2758
Steve Frenchff7feac2005-11-15 16:45:16 -08002759 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2760 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002762 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 /* Probably no need to le convert -1 on any arch but can not hurt */
2764 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002765 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002766 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002767 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 return rc;
2769}
2770
2771/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002772static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2773 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774{
2775 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002776 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2777 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 int count;
2779 int i;
2780
Steve French790fe572007-07-07 19:25:05 +00002781 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 return 0;
2783
2784 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002785 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002786 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002787 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002788 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002789 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002790 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 return 0;
2792 }
2793 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002794 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002795 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002796 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002797 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 else {
Steve French50c2f752007-07-13 00:33:32 +00002799 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 return 0;
2801 }
Steve French50c2f752007-07-13 00:33:32 +00002802 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2804 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002805 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 /* ACE not converted */
2807 break;
2808 }
2809 }
Steve French790fe572007-07-07 19:25:05 +00002810 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2812 rc += sizeof(struct cifs_posix_acl);
2813 /* BB add check to make sure ACL does not overflow SMB */
2814 }
2815 return rc;
2816}
2817
2818int
2819CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002820 const unsigned char *searchName,
2821 char *acl_inf, const int buflen, const int acl_type,
2822 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823{
2824/* SMB_QUERY_POSIX_ACL */
2825 TRANSACTION2_QPI_REQ *pSMB = NULL;
2826 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2827 int rc = 0;
2828 int bytes_returned;
2829 int name_len;
2830 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002831
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2833
2834queryAclRetry:
2835 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2836 (void **) &pSMBr);
2837 if (rc)
2838 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002839
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2841 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002842 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002843 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 name_len++; /* trailing null */
2845 name_len *= 2;
2846 pSMB->FileName[name_len] = 0;
2847 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002848 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 name_len = strnlen(searchName, PATH_MAX);
2850 name_len++; /* trailing null */
2851 strncpy(pSMB->FileName, searchName, name_len);
2852 }
2853
2854 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2855 pSMB->TotalDataCount = 0;
2856 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002857 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 pSMB->MaxDataCount = cpu_to_le16(4000);
2859 pSMB->MaxSetupCount = 0;
2860 pSMB->Reserved = 0;
2861 pSMB->Flags = 0;
2862 pSMB->Timeout = 0;
2863 pSMB->Reserved2 = 0;
2864 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002865 offsetof(struct smb_com_transaction2_qpi_req,
2866 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 pSMB->DataCount = 0;
2868 pSMB->DataOffset = 0;
2869 pSMB->SetupCount = 1;
2870 pSMB->Reserved3 = 0;
2871 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2872 byte_count = params + 1 /* pad */ ;
2873 pSMB->TotalParameterCount = cpu_to_le16(params);
2874 pSMB->ParameterCount = pSMB->TotalParameterCount;
2875 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2876 pSMB->Reserved4 = 0;
2877 pSMB->hdr.smb_buf_length += byte_count;
2878 pSMB->ByteCount = cpu_to_le16(byte_count);
2879
2880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2881 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002882 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 if (rc) {
2884 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2885 } else {
2886 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002887
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2889 if (rc || (pSMBr->ByteCount < 2))
2890 /* BB also check enough total bytes returned */
2891 rc = -EIO; /* bad smb */
2892 else {
2893 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2894 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2895 rc = cifs_copy_posix_acl(acl_inf,
2896 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002897 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 }
2899 }
2900 cifs_buf_release(pSMB);
2901 if (rc == -EAGAIN)
2902 goto queryAclRetry;
2903 return rc;
2904}
2905
2906int
2907CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002908 const unsigned char *fileName,
2909 const char *local_acl, const int buflen,
2910 const int acl_type,
2911 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912{
2913 struct smb_com_transaction2_spi_req *pSMB = NULL;
2914 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2915 char *parm_data;
2916 int name_len;
2917 int rc = 0;
2918 int bytes_returned = 0;
2919 __u16 params, byte_count, data_count, param_offset, offset;
2920
2921 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2922setAclRetry:
2923 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002924 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 if (rc)
2926 return rc;
2927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2928 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002929 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002930 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 name_len++; /* trailing null */
2932 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002933 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 name_len = strnlen(fileName, PATH_MAX);
2935 name_len++; /* trailing null */
2936 strncpy(pSMB->FileName, fileName, name_len);
2937 }
2938 params = 6 + name_len;
2939 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002940 /* BB find max SMB size from sess */
2941 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 pSMB->MaxSetupCount = 0;
2943 pSMB->Reserved = 0;
2944 pSMB->Flags = 0;
2945 pSMB->Timeout = 0;
2946 pSMB->Reserved2 = 0;
2947 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002948 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 offset = param_offset + params;
2950 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2951 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2952
2953 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002954 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955
Steve French790fe572007-07-07 19:25:05 +00002956 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 rc = -EOPNOTSUPP;
2958 goto setACLerrorExit;
2959 }
2960 pSMB->DataOffset = cpu_to_le16(offset);
2961 pSMB->SetupCount = 1;
2962 pSMB->Reserved3 = 0;
2963 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2964 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2965 byte_count = 3 /* pad */ + params + data_count;
2966 pSMB->DataCount = cpu_to_le16(data_count);
2967 pSMB->TotalDataCount = pSMB->DataCount;
2968 pSMB->ParameterCount = cpu_to_le16(params);
2969 pSMB->TotalParameterCount = pSMB->ParameterCount;
2970 pSMB->Reserved4 = 0;
2971 pSMB->hdr.smb_buf_length += byte_count;
2972 pSMB->ByteCount = cpu_to_le16(byte_count);
2973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002975 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
2978setACLerrorExit:
2979 cifs_buf_release(pSMB);
2980 if (rc == -EAGAIN)
2981 goto setAclRetry;
2982 return rc;
2983}
2984
Steve Frenchf654bac2005-04-28 22:41:04 -07002985/* BB fix tabs in this function FIXME BB */
2986int
2987CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002988 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002989{
Steve French50c2f752007-07-13 00:33:32 +00002990 int rc = 0;
2991 struct smb_t2_qfi_req *pSMB = NULL;
2992 struct smb_t2_qfi_rsp *pSMBr = NULL;
2993 int bytes_returned;
2994 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002995
Steve French790fe572007-07-07 19:25:05 +00002996 cFYI(1, ("In GetExtAttr"));
2997 if (tcon == NULL)
2998 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002999
3000GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003001 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3002 (void **) &pSMBr);
3003 if (rc)
3004 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003005
Steve Frenchad7a2922008-02-07 23:25:02 +00003006 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003007 pSMB->t2.TotalDataCount = 0;
3008 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3009 /* BB find exact max data count below from sess structure BB */
3010 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3011 pSMB->t2.MaxSetupCount = 0;
3012 pSMB->t2.Reserved = 0;
3013 pSMB->t2.Flags = 0;
3014 pSMB->t2.Timeout = 0;
3015 pSMB->t2.Reserved2 = 0;
3016 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3017 Fid) - 4);
3018 pSMB->t2.DataCount = 0;
3019 pSMB->t2.DataOffset = 0;
3020 pSMB->t2.SetupCount = 1;
3021 pSMB->t2.Reserved3 = 0;
3022 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3023 byte_count = params + 1 /* pad */ ;
3024 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3025 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3026 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3027 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003028 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003029 pSMB->hdr.smb_buf_length += byte_count;
3030 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003031
Steve French790fe572007-07-07 19:25:05 +00003032 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3033 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3034 if (rc) {
3035 cFYI(1, ("error %d in GetExtAttr", rc));
3036 } else {
3037 /* decode response */
3038 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3039 if (rc || (pSMBr->ByteCount < 2))
3040 /* BB also check enough total bytes returned */
3041 /* If rc should we check for EOPNOSUPP and
3042 disable the srvino flag? or in caller? */
3043 rc = -EIO; /* bad smb */
3044 else {
3045 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3046 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3047 struct file_chattr_info *pfinfo;
3048 /* BB Do we need a cast or hash here ? */
3049 if (count != 16) {
3050 cFYI(1, ("Illegal size ret in GetExtAttr"));
3051 rc = -EIO;
3052 goto GetExtAttrOut;
3053 }
3054 pfinfo = (struct file_chattr_info *)
3055 (data_offset + (char *) &pSMBr->hdr.Protocol);
3056 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003057 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003058 }
3059 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003060GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003061 cifs_buf_release(pSMB);
3062 if (rc == -EAGAIN)
3063 goto GetExtAttrRetry;
3064 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003065}
3066
Steve Frenchf654bac2005-04-28 22:41:04 -07003067#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Steve French297647c2007-10-12 04:11:59 +00003069#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003070/* Get Security Descriptor (by handle) from remote server for a file or dir */
3071int
3072CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003073 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003074{
3075 int rc = 0;
3076 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003077 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003078 struct kvec iov[1];
3079
3080 cFYI(1, ("GetCifsACL"));
3081
Steve French630f3f0c2007-10-25 21:17:17 +00003082 *pbuflen = 0;
3083 *acl_inf = NULL;
3084
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003085 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003086 8 /* parm len */, tcon, (void **) &pSMB);
3087 if (rc)
3088 return rc;
3089
3090 pSMB->MaxParameterCount = cpu_to_le32(4);
3091 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3092 pSMB->MaxSetupCount = 0;
3093 pSMB->Fid = fid; /* file handle always le */
3094 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3095 CIFS_ACL_DACL);
3096 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3097 pSMB->hdr.smb_buf_length += 11;
3098 iov[0].iov_base = (char *)pSMB;
3099 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3100
Steve Frencha761ac52007-10-18 21:45:27 +00003101 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003102 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003103 cifs_stats_inc(&tcon->num_acl_get);
3104 if (rc) {
3105 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3106 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003107 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003108 __u32 parm_len;
3109 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003110 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003111 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003112
3113/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003114 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003115 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003116 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003117 goto qsec_out;
3118 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3119
Steve French630f3f0c2007-10-25 21:17:17 +00003120 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003121
3122 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3123 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003124 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003125 goto qsec_out;
3126 }
3127
3128/* BB check that data area is minimum length and as big as acl_len */
3129
Steve Frenchaf6f4612007-10-16 18:40:37 +00003130 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003131 if (acl_len != *pbuflen) {
3132 cERROR(1, ("acl length %d does not match %d",
3133 acl_len, *pbuflen));
3134 if (*pbuflen > acl_len)
3135 *pbuflen = acl_len;
3136 }
Steve French0a4b92c2006-01-12 15:44:21 -08003137
Steve French630f3f0c2007-10-25 21:17:17 +00003138 /* check if buffer is big enough for the acl
3139 header followed by the smallest SID */
3140 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3141 (*pbuflen >= 64 * 1024)) {
3142 cERROR(1, ("bad acl length %d", *pbuflen));
3143 rc = -EINVAL;
3144 *pbuflen = 0;
3145 } else {
3146 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3147 if (*acl_inf == NULL) {
3148 *pbuflen = 0;
3149 rc = -ENOMEM;
3150 }
3151 memcpy(*acl_inf, pdata, *pbuflen);
3152 }
Steve French0a4b92c2006-01-12 15:44:21 -08003153 }
3154qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003155 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003156 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003157 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003158 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003159/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003160 return rc;
3161}
Steve French97837582007-12-31 07:47:21 +00003162
3163int
3164CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3165 struct cifs_ntsd *pntsd, __u32 acllen)
3166{
3167 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3168 int rc = 0;
3169 int bytes_returned = 0;
3170 SET_SEC_DESC_REQ *pSMB = NULL;
3171 NTRANSACT_RSP *pSMBr = NULL;
3172
3173setCifsAclRetry:
3174 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3175 (void **) &pSMBr);
3176 if (rc)
3177 return (rc);
3178
3179 pSMB->MaxSetupCount = 0;
3180 pSMB->Reserved = 0;
3181
3182 param_count = 8;
3183 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3184 data_count = acllen;
3185 data_offset = param_offset + param_count;
3186 byte_count = 3 /* pad */ + param_count;
3187
3188 pSMB->DataCount = cpu_to_le32(data_count);
3189 pSMB->TotalDataCount = pSMB->DataCount;
3190 pSMB->MaxParameterCount = cpu_to_le32(4);
3191 pSMB->MaxDataCount = cpu_to_le32(16384);
3192 pSMB->ParameterCount = cpu_to_le32(param_count);
3193 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3194 pSMB->TotalParameterCount = pSMB->ParameterCount;
3195 pSMB->DataOffset = cpu_to_le32(data_offset);
3196 pSMB->SetupCount = 0;
3197 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3198 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3199
3200 pSMB->Fid = fid; /* file handle always le */
3201 pSMB->Reserved2 = 0;
3202 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3203
3204 if (pntsd && acllen) {
3205 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3206 (char *) pntsd,
3207 acllen);
3208 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3209
3210 } else
3211 pSMB->hdr.smb_buf_length += byte_count;
3212
3213 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3214 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3215
3216 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3217 if (rc)
3218 cFYI(1, ("Set CIFS ACL returned %d", rc));
3219 cifs_buf_release(pSMB);
3220
3221 if (rc == -EAGAIN)
3222 goto setCifsAclRetry;
3223
3224 return (rc);
3225}
3226
Steve French297647c2007-10-12 04:11:59 +00003227#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003228
Steve French6b8edfe2005-08-23 20:26:03 -07003229/* Legacy Query Path Information call for lookup to old servers such
3230 as Win9x/WinME */
3231int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003232 const unsigned char *searchName,
3233 FILE_ALL_INFO *pFinfo,
3234 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003235{
Steve Frenchad7a2922008-02-07 23:25:02 +00003236 QUERY_INFORMATION_REQ *pSMB;
3237 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003238 int rc = 0;
3239 int bytes_returned;
3240 int name_len;
3241
Steve French50c2f752007-07-13 00:33:32 +00003242 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003243QInfRetry:
3244 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003245 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003246 if (rc)
3247 return rc;
3248
3249 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3250 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003251 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3252 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003253 name_len++; /* trailing null */
3254 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003255 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003256 name_len = strnlen(searchName, PATH_MAX);
3257 name_len++; /* trailing null */
3258 strncpy(pSMB->FileName, searchName, name_len);
3259 }
3260 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003261 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003262 pSMB->hdr.smb_buf_length += (__u16) name_len;
3263 pSMB->ByteCount = cpu_to_le16(name_len);
3264
3265 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003266 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003267 if (rc) {
3268 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003269 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003270 struct timespec ts;
3271 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003272
3273 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003274 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003275 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003276 ts.tv_nsec = 0;
3277 ts.tv_sec = time;
3278 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003279 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003280 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3281 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003282 pFinfo->AllocationSize =
3283 cpu_to_le64(le32_to_cpu(pSMBr->size));
3284 pFinfo->EndOfFile = pFinfo->AllocationSize;
3285 pFinfo->Attributes =
3286 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003287 } else
3288 rc = -EIO; /* bad buffer passed in */
3289
3290 cifs_buf_release(pSMB);
3291
3292 if (rc == -EAGAIN)
3293 goto QInfRetry;
3294
3295 return rc;
3296}
3297
3298
3299
3300
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301int
3302CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3303 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003304 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003305 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003306 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307{
3308/* level 263 SMB_QUERY_FILE_ALL_INFO */
3309 TRANSACTION2_QPI_REQ *pSMB = NULL;
3310 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3311 int rc = 0;
3312 int bytes_returned;
3313 int name_len;
3314 __u16 params, byte_count;
3315
3316/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3317QPathInfoRetry:
3318 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3319 (void **) &pSMBr);
3320 if (rc)
3321 return rc;
3322
3323 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3324 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003325 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003326 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 name_len++; /* trailing null */
3328 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003329 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 name_len = strnlen(searchName, PATH_MAX);
3331 name_len++; /* trailing null */
3332 strncpy(pSMB->FileName, searchName, name_len);
3333 }
3334
Steve French50c2f752007-07-13 00:33:32 +00003335 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 pSMB->TotalDataCount = 0;
3337 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003338 /* BB find exact max SMB PDU from sess structure BB */
3339 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 pSMB->MaxSetupCount = 0;
3341 pSMB->Reserved = 0;
3342 pSMB->Flags = 0;
3343 pSMB->Timeout = 0;
3344 pSMB->Reserved2 = 0;
3345 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003346 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 pSMB->DataCount = 0;
3348 pSMB->DataOffset = 0;
3349 pSMB->SetupCount = 1;
3350 pSMB->Reserved3 = 0;
3351 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3352 byte_count = params + 1 /* pad */ ;
3353 pSMB->TotalParameterCount = cpu_to_le16(params);
3354 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003355 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003356 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3357 else
3358 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 pSMB->Reserved4 = 0;
3360 pSMB->hdr.smb_buf_length += byte_count;
3361 pSMB->ByteCount = cpu_to_le16(byte_count);
3362
3363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3365 if (rc) {
3366 cFYI(1, ("Send error in QPathInfo = %d", rc));
3367 } else { /* decode response */
3368 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3369
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003370 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3371 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003372 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003374 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003375 rc = -EIO; /* 24 or 26 expected but we do not read
3376 last field */
3377 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003378 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003380
3381 /* On legacy responses we do not read the last field,
3382 EAsize, fortunately since it varies by subdialect and
3383 also note it differs on Set vs. Get, ie two bytes or 4
3384 bytes depending but we don't care here */
3385 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003386 size = sizeof(FILE_INFO_STANDARD);
3387 else
3388 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 memcpy((char *) pFindData,
3390 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003391 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 } else
3393 rc = -ENOMEM;
3394 }
3395 cifs_buf_release(pSMB);
3396 if (rc == -EAGAIN)
3397 goto QPathInfoRetry;
3398
3399 return rc;
3400}
3401
3402int
3403CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3404 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003405 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003406 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407{
3408/* SMB_QUERY_FILE_UNIX_BASIC */
3409 TRANSACTION2_QPI_REQ *pSMB = NULL;
3410 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3411 int rc = 0;
3412 int bytes_returned = 0;
3413 int name_len;
3414 __u16 params, byte_count;
3415
3416 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3417UnixQPathInfoRetry:
3418 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3419 (void **) &pSMBr);
3420 if (rc)
3421 return rc;
3422
3423 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3424 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003425 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003426 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 name_len++; /* trailing null */
3428 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003429 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 name_len = strnlen(searchName, PATH_MAX);
3431 name_len++; /* trailing null */
3432 strncpy(pSMB->FileName, searchName, name_len);
3433 }
3434
Steve French50c2f752007-07-13 00:33:32 +00003435 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003436 pSMB->TotalDataCount = 0;
3437 pSMB->MaxParameterCount = cpu_to_le16(2);
3438 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003439 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 pSMB->MaxSetupCount = 0;
3441 pSMB->Reserved = 0;
3442 pSMB->Flags = 0;
3443 pSMB->Timeout = 0;
3444 pSMB->Reserved2 = 0;
3445 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003446 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447 pSMB->DataCount = 0;
3448 pSMB->DataOffset = 0;
3449 pSMB->SetupCount = 1;
3450 pSMB->Reserved3 = 0;
3451 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3452 byte_count = params + 1 /* pad */ ;
3453 pSMB->TotalParameterCount = cpu_to_le16(params);
3454 pSMB->ParameterCount = pSMB->TotalParameterCount;
3455 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3456 pSMB->Reserved4 = 0;
3457 pSMB->hdr.smb_buf_length += byte_count;
3458 pSMB->ByteCount = cpu_to_le16(byte_count);
3459
3460 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3461 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3462 if (rc) {
3463 cFYI(1, ("Send error in QPathInfo = %d", rc));
3464 } else { /* decode response */
3465 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3466
3467 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003468 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3469 "Unix Extensions can be disabled on mount "
3470 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 rc = -EIO; /* bad smb */
3472 } else {
3473 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3474 memcpy((char *) pFindData,
3475 (char *) &pSMBr->hdr.Protocol +
3476 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003477 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 }
3479 }
3480 cifs_buf_release(pSMB);
3481 if (rc == -EAGAIN)
3482 goto UnixQPathInfoRetry;
3483
3484 return rc;
3485}
3486
Linus Torvalds1da177e2005-04-16 15:20:36 -07003487/* xid, tcon, searchName and codepage are input parms, rest are returned */
3488int
3489CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003490 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003492 __u16 *pnetfid,
3493 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494{
3495/* level 257 SMB_ */
3496 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3497 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003498 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 int rc = 0;
3500 int bytes_returned = 0;
3501 int name_len;
3502 __u16 params, byte_count;
3503
Steve French50c2f752007-07-13 00:33:32 +00003504 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
3506findFirstRetry:
3507 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3508 (void **) &pSMBr);
3509 if (rc)
3510 return rc;
3511
3512 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3513 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003514 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003515 PATH_MAX, nls_codepage, remap);
3516 /* We can not add the asterik earlier in case
3517 it got remapped to 0xF03A as if it were part of the
3518 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003520 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003521 pSMB->FileName[name_len+1] = 0;
3522 pSMB->FileName[name_len+2] = '*';
3523 pSMB->FileName[name_len+3] = 0;
3524 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3526 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003527 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528 } else { /* BB add check for overrun of SMB buf BB */
3529 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003531 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 free buffer exit; BB */
3533 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003534 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003535 pSMB->FileName[name_len+1] = '*';
3536 pSMB->FileName[name_len+2] = 0;
3537 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 }
3539
3540 params = 12 + name_len /* includes null */ ;
3541 pSMB->TotalDataCount = 0; /* no EAs */
3542 pSMB->MaxParameterCount = cpu_to_le16(10);
3543 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3544 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3545 pSMB->MaxSetupCount = 0;
3546 pSMB->Reserved = 0;
3547 pSMB->Flags = 0;
3548 pSMB->Timeout = 0;
3549 pSMB->Reserved2 = 0;
3550 byte_count = params + 1 /* pad */ ;
3551 pSMB->TotalParameterCount = cpu_to_le16(params);
3552 pSMB->ParameterCount = pSMB->TotalParameterCount;
3553 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003554 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3555 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 pSMB->DataCount = 0;
3557 pSMB->DataOffset = 0;
3558 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3559 pSMB->Reserved3 = 0;
3560 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3561 pSMB->SearchAttributes =
3562 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3563 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003564 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3565 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 CIFS_SEARCH_RETURN_RESUME);
3567 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3568
3569 /* BB what should we set StorageType to? Does it matter? BB */
3570 pSMB->SearchStorageType = 0;
3571 pSMB->hdr.smb_buf_length += byte_count;
3572 pSMB->ByteCount = cpu_to_le16(byte_count);
3573
3574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003576 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
Steve French88274812006-03-09 22:21:45 +00003578 if (rc) {/* BB add logic to retry regular search if Unix search
3579 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 /* BB Add code to handle unsupported level rc */
3581 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003582
Steve French88274812006-03-09 22:21:45 +00003583 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
3585 /* BB eventually could optimize out free and realloc of buf */
3586 /* for this case */
3587 if (rc == -EAGAIN)
3588 goto findFirstRetry;
3589 } else { /* decode response */
3590 /* BB remember to free buffer if error BB */
3591 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003592 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003593 unsigned int lnoff;
3594
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003596 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 else
Steve French4b18f2a2008-04-29 00:06:05 +00003598 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003601 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003602 psrch_inf->srch_entries_start =
3603 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3606 le16_to_cpu(pSMBr->t2.ParameterOffset));
3607
Steve French790fe572007-07-07 19:25:05 +00003608 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003609 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 else
Steve French4b18f2a2008-04-29 00:06:05 +00003611 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
Steve French50c2f752007-07-13 00:33:32 +00003613 psrch_inf->entries_in_buffer =
3614 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003615 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003617 lnoff = le16_to_cpu(parms->LastNameOffset);
3618 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3619 lnoff) {
3620 cERROR(1, ("ignoring corrupt resume name"));
3621 psrch_inf->last_entry = NULL;
3622 return rc;
3623 }
3624
Steve French0752f152008-10-07 20:03:33 +00003625 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003626 lnoff;
3627
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 *pnetfid = parms->SearchHandle;
3629 } else {
3630 cifs_buf_release(pSMB);
3631 }
3632 }
3633
3634 return rc;
3635}
3636
3637int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003638 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639{
3640 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3641 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003642 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643 char *response_data;
3644 int rc = 0;
3645 int bytes_returned, name_len;
3646 __u16 params, byte_count;
3647
3648 cFYI(1, ("In FindNext"));
3649
Steve French4b18f2a2008-04-29 00:06:05 +00003650 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 return -ENOENT;
3652
3653 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3654 (void **) &pSMBr);
3655 if (rc)
3656 return rc;
3657
Steve French50c2f752007-07-13 00:33:32 +00003658 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 byte_count = 0;
3660 pSMB->TotalDataCount = 0; /* no EAs */
3661 pSMB->MaxParameterCount = cpu_to_le16(8);
3662 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003663 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3664 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 pSMB->MaxSetupCount = 0;
3666 pSMB->Reserved = 0;
3667 pSMB->Flags = 0;
3668 pSMB->Timeout = 0;
3669 pSMB->Reserved2 = 0;
3670 pSMB->ParameterOffset = cpu_to_le16(
3671 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3672 pSMB->DataCount = 0;
3673 pSMB->DataOffset = 0;
3674 pSMB->SetupCount = 1;
3675 pSMB->Reserved3 = 0;
3676 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3677 pSMB->SearchHandle = searchHandle; /* always kept as le */
3678 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003679 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3681 pSMB->ResumeKey = psrch_inf->resume_key;
3682 pSMB->SearchFlags =
3683 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3684
3685 name_len = psrch_inf->resume_name_len;
3686 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003687 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3689 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003690 /* 14 byte parm len above enough for 2 byte null terminator */
3691 pSMB->ResumeFileName[name_len] = 0;
3692 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 } else {
3694 rc = -EINVAL;
3695 goto FNext2_err_exit;
3696 }
3697 byte_count = params + 1 /* pad */ ;
3698 pSMB->TotalParameterCount = cpu_to_le16(params);
3699 pSMB->ParameterCount = pSMB->TotalParameterCount;
3700 pSMB->hdr.smb_buf_length += byte_count;
3701 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003702
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003705 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 if (rc) {
3707 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003708 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003709 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003710 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 } else
3712 cFYI(1, ("FindNext returned = %d", rc));
3713 } else { /* decode response */
3714 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003715
Steve French790fe572007-07-07 19:25:05 +00003716 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003717 unsigned int lnoff;
3718
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719 /* BB fixme add lock for file (srch_info) struct here */
3720 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003721 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 else
Steve French4b18f2a2008-04-29 00:06:05 +00003723 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 response_data = (char *) &pSMBr->hdr.Protocol +
3725 le16_to_cpu(pSMBr->t2.ParameterOffset);
3726 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3727 response_data = (char *)&pSMBr->hdr.Protocol +
3728 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003729 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003730 cifs_small_buf_release(
3731 psrch_inf->ntwrk_buf_start);
3732 else
3733 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 psrch_inf->srch_entries_start = response_data;
3735 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003736 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003737 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003738 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 else
Steve French4b18f2a2008-04-29 00:06:05 +00003740 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003741 psrch_inf->entries_in_buffer =
3742 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 psrch_inf->index_of_last_entry +=
3744 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003745 lnoff = le16_to_cpu(parms->LastNameOffset);
3746 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3747 lnoff) {
3748 cERROR(1, ("ignoring corrupt resume name"));
3749 psrch_inf->last_entry = NULL;
3750 return rc;
3751 } else
3752 psrch_inf->last_entry =
3753 psrch_inf->srch_entries_start + lnoff;
3754
Steve French50c2f752007-07-13 00:33:32 +00003755/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3756 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
3758 /* BB fixme add unlock here */
3759 }
3760
3761 }
3762
3763 /* BB On error, should we leave previous search buf (and count and
3764 last entry fields) intact or free the previous one? */
3765
3766 /* Note: On -EAGAIN error only caller can retry on handle based calls
3767 since file handle passed in no longer valid */
3768FNext2_err_exit:
3769 if (rc != 0)
3770 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 return rc;
3772}
3773
3774int
Steve French50c2f752007-07-13 00:33:32 +00003775CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3776 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777{
3778 int rc = 0;
3779 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780
3781 cFYI(1, ("In CIFSSMBFindClose"));
3782 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3783
3784 /* no sense returning error if session restarted
3785 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003786 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 return 0;
3788 if (rc)
3789 return rc;
3790
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 pSMB->FileID = searchHandle;
3792 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003793 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003794 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003796
Steve Frencha45443472005-08-24 13:59:35 -07003797 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798
3799 /* Since session is dead, search handle closed on server already */
3800 if (rc == -EAGAIN)
3801 rc = 0;
3802
3803 return rc;
3804}
3805
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806int
3807CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003808 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003809 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003810 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003811{
3812 int rc = 0;
3813 TRANSACTION2_QPI_REQ *pSMB = NULL;
3814 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3815 int name_len, bytes_returned;
3816 __u16 params, byte_count;
3817
Steve French50c2f752007-07-13 00:33:32 +00003818 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003819 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003820 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821
3822GetInodeNumberRetry:
3823 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003824 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 if (rc)
3826 return rc;
3827
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3829 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003830 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003831 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 name_len++; /* trailing null */
3833 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003834 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 name_len = strnlen(searchName, PATH_MAX);
3836 name_len++; /* trailing null */
3837 strncpy(pSMB->FileName, searchName, name_len);
3838 }
3839
3840 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3841 pSMB->TotalDataCount = 0;
3842 pSMB->MaxParameterCount = cpu_to_le16(2);
3843 /* BB find exact max data count below from sess structure BB */
3844 pSMB->MaxDataCount = cpu_to_le16(4000);
3845 pSMB->MaxSetupCount = 0;
3846 pSMB->Reserved = 0;
3847 pSMB->Flags = 0;
3848 pSMB->Timeout = 0;
3849 pSMB->Reserved2 = 0;
3850 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003851 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 pSMB->DataCount = 0;
3853 pSMB->DataOffset = 0;
3854 pSMB->SetupCount = 1;
3855 pSMB->Reserved3 = 0;
3856 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3857 byte_count = params + 1 /* pad */ ;
3858 pSMB->TotalParameterCount = cpu_to_le16(params);
3859 pSMB->ParameterCount = pSMB->TotalParameterCount;
3860 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3861 pSMB->Reserved4 = 0;
3862 pSMB->hdr.smb_buf_length += byte_count;
3863 pSMB->ByteCount = cpu_to_le16(byte_count);
3864
3865 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3866 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3867 if (rc) {
3868 cFYI(1, ("error %d in QueryInternalInfo", rc));
3869 } else {
3870 /* decode response */
3871 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3872 if (rc || (pSMBr->ByteCount < 2))
3873 /* BB also check enough total bytes returned */
3874 /* If rc should we check for EOPNOSUPP and
3875 disable the srvino flag? or in caller? */
3876 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003877 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3879 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003880 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003882 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3884 rc = -EIO;
3885 goto GetInodeNumOut;
3886 }
3887 pfinfo = (struct file_internal_info *)
3888 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003889 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 }
3891 }
3892GetInodeNumOut:
3893 cifs_buf_release(pSMB);
3894 if (rc == -EAGAIN)
3895 goto GetInodeNumberRetry;
3896 return rc;
3897}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898
Igor Mammedovfec45852008-05-16 13:06:30 +04003899/* parses DFS refferal V3 structure
3900 * caller is responsible for freeing target_nodes
3901 * returns:
3902 * on success - 0
3903 * on failure - errno
3904 */
3905static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003906parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003907 unsigned int *num_of_nodes,
3908 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003909 const struct nls_table *nls_codepage, int remap,
3910 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003911{
3912 int i, rc = 0;
3913 char *data_end;
3914 bool is_unicode;
3915 struct dfs_referral_level_3 *ref;
3916
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003917 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3918 is_unicode = true;
3919 else
3920 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003921 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3922
3923 if (*num_of_nodes < 1) {
3924 cERROR(1, ("num_referrals: must be at least > 0,"
3925 "but we get num_referrals = %d\n", *num_of_nodes));
3926 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003927 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003928 }
3929
3930 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003931 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003932 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003933 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003934 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003935 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003936 }
3937
3938 /* get the upper boundary of the resp buffer */
3939 data_end = (char *)(&(pSMBr->PathConsumed)) +
3940 le16_to_cpu(pSMBr->t2.DataCount);
3941
3942 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3943 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00003944 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003945
3946 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3947 *num_of_nodes, GFP_KERNEL);
3948 if (*target_nodes == NULL) {
3949 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3950 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003951 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003952 }
3953
3954 /* collect neccessary data from referrals */
3955 for (i = 0; i < *num_of_nodes; i++) {
3956 char *temp;
3957 int max_len;
3958 struct dfs_info3_param *node = (*target_nodes)+i;
3959
Steve French0e0d2cf2009-05-01 05:27:32 +00003960 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003961 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003962 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3963 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00003964 if (tmp == NULL) {
3965 rc = -ENOMEM;
3966 goto parse_DFS_referrals_exit;
3967 }
Igor Mammedov2c556082008-10-23 13:58:42 +04003968 cifsConvertToUCS((__le16 *) tmp, searchName,
3969 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003970 node->path_consumed = cifs_ucs2_bytes(tmp,
3971 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04003972 nls_codepage);
3973 kfree(tmp);
3974 } else
3975 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3976
Igor Mammedovfec45852008-05-16 13:06:30 +04003977 node->server_type = le16_to_cpu(ref->ServerType);
3978 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3979
3980 /* copy DfsPath */
3981 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3982 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003983 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3984 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003985 if (!node->path_name) {
3986 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003987 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003988 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003989
3990 /* copy link target UNC */
3991 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3992 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003993 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3994 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003995 if (!node->node_name)
3996 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04003997 }
3998
Steve Frencha1fe78f2008-05-16 18:48:38 +00003999parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004000 if (rc) {
4001 free_dfs_info_array(*target_nodes, *num_of_nodes);
4002 *target_nodes = NULL;
4003 *num_of_nodes = 0;
4004 }
4005 return rc;
4006}
4007
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008int
4009CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4010 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004011 struct dfs_info3_param **target_nodes,
4012 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004013 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014{
4015/* TRANS2_GET_DFS_REFERRAL */
4016 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4017 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 int rc = 0;
4019 int bytes_returned;
4020 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004022 *num_of_nodes = 0;
4023 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024
4025 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4026 if (ses == NULL)
4027 return -ENODEV;
4028getDFSRetry:
4029 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4030 (void **) &pSMBr);
4031 if (rc)
4032 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004033
4034 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004035 but should never be null here anyway */
4036 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 pSMB->hdr.Tid = ses->ipc_tid;
4038 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004039 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004041 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
4044 if (ses->capabilities & CAP_UNICODE) {
4045 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4046 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004047 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004048 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 name_len++; /* trailing null */
4050 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004051 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 name_len = strnlen(searchName, PATH_MAX);
4053 name_len++; /* trailing null */
4054 strncpy(pSMB->RequestFileName, searchName, name_len);
4055 }
4056
Steve French790fe572007-07-07 19:25:05 +00004057 if (ses->server) {
4058 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004059 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4060 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4061 }
4062
Steve French50c2f752007-07-13 00:33:32 +00004063 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004064
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 params = 2 /* level */ + name_len /*includes null */ ;
4066 pSMB->TotalDataCount = 0;
4067 pSMB->DataCount = 0;
4068 pSMB->DataOffset = 0;
4069 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004070 /* BB find exact max SMB PDU from sess structure BB */
4071 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 pSMB->MaxSetupCount = 0;
4073 pSMB->Reserved = 0;
4074 pSMB->Flags = 0;
4075 pSMB->Timeout = 0;
4076 pSMB->Reserved2 = 0;
4077 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004078 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 pSMB->SetupCount = 1;
4080 pSMB->Reserved3 = 0;
4081 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4082 byte_count = params + 3 /* pad */ ;
4083 pSMB->ParameterCount = cpu_to_le16(params);
4084 pSMB->TotalParameterCount = pSMB->ParameterCount;
4085 pSMB->MaxReferralLevel = cpu_to_le16(3);
4086 pSMB->hdr.smb_buf_length += byte_count;
4087 pSMB->ByteCount = cpu_to_le16(byte_count);
4088
4089 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091 if (rc) {
4092 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004093 goto GetDFSRefExit;
4094 }
4095 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004097 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004098 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004099 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004100 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004102
4103 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4104 pSMBr->ByteCount,
4105 le16_to_cpu(pSMBr->t2.DataOffset)));
4106
4107 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004108 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004109 target_nodes, nls_codepage, remap,
4110 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004111
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004113 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114
4115 if (rc == -EAGAIN)
4116 goto getDFSRetry;
4117
4118 return rc;
4119}
4120
Steve French20962432005-09-21 22:05:57 -07004121/* Query File System Info such as free space to old servers such as Win 9x */
4122int
4123SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4124{
4125/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4126 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4127 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4128 FILE_SYSTEM_ALLOC_INFO *response_data;
4129 int rc = 0;
4130 int bytes_returned = 0;
4131 __u16 params, byte_count;
4132
4133 cFYI(1, ("OldQFSInfo"));
4134oldQFSInfoRetry:
4135 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4136 (void **) &pSMBr);
4137 if (rc)
4138 return rc;
Steve French20962432005-09-21 22:05:57 -07004139
4140 params = 2; /* level */
4141 pSMB->TotalDataCount = 0;
4142 pSMB->MaxParameterCount = cpu_to_le16(2);
4143 pSMB->MaxDataCount = cpu_to_le16(1000);
4144 pSMB->MaxSetupCount = 0;
4145 pSMB->Reserved = 0;
4146 pSMB->Flags = 0;
4147 pSMB->Timeout = 0;
4148 pSMB->Reserved2 = 0;
4149 byte_count = params + 1 /* pad */ ;
4150 pSMB->TotalParameterCount = cpu_to_le16(params);
4151 pSMB->ParameterCount = pSMB->TotalParameterCount;
4152 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4153 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4154 pSMB->DataCount = 0;
4155 pSMB->DataOffset = 0;
4156 pSMB->SetupCount = 1;
4157 pSMB->Reserved3 = 0;
4158 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4159 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4160 pSMB->hdr.smb_buf_length += byte_count;
4161 pSMB->ByteCount = cpu_to_le16(byte_count);
4162
4163 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4164 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4165 if (rc) {
4166 cFYI(1, ("Send error in QFSInfo = %d", rc));
4167 } else { /* decode response */
4168 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4169
4170 if (rc || (pSMBr->ByteCount < 18))
4171 rc = -EIO; /* bad smb */
4172 else {
4173 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004174 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004175 pSMBr->ByteCount, data_offset));
4176
Steve French50c2f752007-07-13 00:33:32 +00004177 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004178 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4179 FSData->f_bsize =
4180 le16_to_cpu(response_data->BytesPerSector) *
4181 le32_to_cpu(response_data->
4182 SectorsPerAllocationUnit);
4183 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004184 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004185 FSData->f_bfree = FSData->f_bavail =
4186 le32_to_cpu(response_data->FreeAllocationUnits);
4187 cFYI(1,
4188 ("Blocks: %lld Free: %lld Block size %ld",
4189 (unsigned long long)FSData->f_blocks,
4190 (unsigned long long)FSData->f_bfree,
4191 FSData->f_bsize));
4192 }
4193 }
4194 cifs_buf_release(pSMB);
4195
4196 if (rc == -EAGAIN)
4197 goto oldQFSInfoRetry;
4198
4199 return rc;
4200}
4201
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202int
Steve French737b7582005-04-28 22:41:06 -07004203CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204{
4205/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4206 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4207 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4208 FILE_SYSTEM_INFO *response_data;
4209 int rc = 0;
4210 int bytes_returned = 0;
4211 __u16 params, byte_count;
4212
4213 cFYI(1, ("In QFSInfo"));
4214QFSInfoRetry:
4215 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4216 (void **) &pSMBr);
4217 if (rc)
4218 return rc;
4219
4220 params = 2; /* level */
4221 pSMB->TotalDataCount = 0;
4222 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004223 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 pSMB->MaxSetupCount = 0;
4225 pSMB->Reserved = 0;
4226 pSMB->Flags = 0;
4227 pSMB->Timeout = 0;
4228 pSMB->Reserved2 = 0;
4229 byte_count = params + 1 /* pad */ ;
4230 pSMB->TotalParameterCount = cpu_to_le16(params);
4231 pSMB->ParameterCount = pSMB->TotalParameterCount;
4232 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004233 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 pSMB->DataCount = 0;
4235 pSMB->DataOffset = 0;
4236 pSMB->SetupCount = 1;
4237 pSMB->Reserved3 = 0;
4238 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4239 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4240 pSMB->hdr.smb_buf_length += byte_count;
4241 pSMB->ByteCount = cpu_to_le16(byte_count);
4242
4243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4245 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004246 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004247 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004248 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249
Steve French20962432005-09-21 22:05:57 -07004250 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 rc = -EIO; /* bad smb */
4252 else {
4253 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254
4255 response_data =
4256 (FILE_SYSTEM_INFO
4257 *) (((char *) &pSMBr->hdr.Protocol) +
4258 data_offset);
4259 FSData->f_bsize =
4260 le32_to_cpu(response_data->BytesPerSector) *
4261 le32_to_cpu(response_data->
4262 SectorsPerAllocationUnit);
4263 FSData->f_blocks =
4264 le64_to_cpu(response_data->TotalAllocationUnits);
4265 FSData->f_bfree = FSData->f_bavail =
4266 le64_to_cpu(response_data->FreeAllocationUnits);
4267 cFYI(1,
4268 ("Blocks: %lld Free: %lld Block size %ld",
4269 (unsigned long long)FSData->f_blocks,
4270 (unsigned long long)FSData->f_bfree,
4271 FSData->f_bsize));
4272 }
4273 }
4274 cifs_buf_release(pSMB);
4275
4276 if (rc == -EAGAIN)
4277 goto QFSInfoRetry;
4278
4279 return rc;
4280}
4281
4282int
Steve French737b7582005-04-28 22:41:06 -07004283CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284{
4285/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4286 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4287 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4288 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4289 int rc = 0;
4290 int bytes_returned = 0;
4291 __u16 params, byte_count;
4292
4293 cFYI(1, ("In QFSAttributeInfo"));
4294QFSAttributeRetry:
4295 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4296 (void **) &pSMBr);
4297 if (rc)
4298 return rc;
4299
4300 params = 2; /* level */
4301 pSMB->TotalDataCount = 0;
4302 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004303 /* BB find exact max SMB PDU from sess structure BB */
4304 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 pSMB->MaxSetupCount = 0;
4306 pSMB->Reserved = 0;
4307 pSMB->Flags = 0;
4308 pSMB->Timeout = 0;
4309 pSMB->Reserved2 = 0;
4310 byte_count = params + 1 /* pad */ ;
4311 pSMB->TotalParameterCount = cpu_to_le16(params);
4312 pSMB->ParameterCount = pSMB->TotalParameterCount;
4313 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004314 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 pSMB->DataCount = 0;
4316 pSMB->DataOffset = 0;
4317 pSMB->SetupCount = 1;
4318 pSMB->Reserved3 = 0;
4319 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4320 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4321 pSMB->hdr.smb_buf_length += byte_count;
4322 pSMB->ByteCount = cpu_to_le16(byte_count);
4323
4324 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4325 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4326 if (rc) {
4327 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4328 } else { /* decode response */
4329 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4330
Steve French50c2f752007-07-13 00:33:32 +00004331 if (rc || (pSMBr->ByteCount < 13)) {
4332 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 rc = -EIO; /* bad smb */
4334 } else {
4335 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4336 response_data =
4337 (FILE_SYSTEM_ATTRIBUTE_INFO
4338 *) (((char *) &pSMBr->hdr.Protocol) +
4339 data_offset);
4340 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004341 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 }
4343 }
4344 cifs_buf_release(pSMB);
4345
4346 if (rc == -EAGAIN)
4347 goto QFSAttributeRetry;
4348
4349 return rc;
4350}
4351
4352int
Steve French737b7582005-04-28 22:41:06 -07004353CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354{
4355/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4356 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4357 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4358 FILE_SYSTEM_DEVICE_INFO *response_data;
4359 int rc = 0;
4360 int bytes_returned = 0;
4361 __u16 params, byte_count;
4362
4363 cFYI(1, ("In QFSDeviceInfo"));
4364QFSDeviceRetry:
4365 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4366 (void **) &pSMBr);
4367 if (rc)
4368 return rc;
4369
4370 params = 2; /* level */
4371 pSMB->TotalDataCount = 0;
4372 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004373 /* BB find exact max SMB PDU from sess structure BB */
4374 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 pSMB->MaxSetupCount = 0;
4376 pSMB->Reserved = 0;
4377 pSMB->Flags = 0;
4378 pSMB->Timeout = 0;
4379 pSMB->Reserved2 = 0;
4380 byte_count = params + 1 /* pad */ ;
4381 pSMB->TotalParameterCount = cpu_to_le16(params);
4382 pSMB->ParameterCount = pSMB->TotalParameterCount;
4383 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004384 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
4386 pSMB->DataCount = 0;
4387 pSMB->DataOffset = 0;
4388 pSMB->SetupCount = 1;
4389 pSMB->Reserved3 = 0;
4390 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4391 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4392 pSMB->hdr.smb_buf_length += byte_count;
4393 pSMB->ByteCount = cpu_to_le16(byte_count);
4394
4395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4396 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4397 if (rc) {
4398 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4399 } else { /* decode response */
4400 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4401
Steve French630f3f0c2007-10-25 21:17:17 +00004402 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 rc = -EIO; /* bad smb */
4404 else {
4405 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4406 response_data =
Steve French737b7582005-04-28 22:41:06 -07004407 (FILE_SYSTEM_DEVICE_INFO *)
4408 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 data_offset);
4410 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004411 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 }
4413 }
4414 cifs_buf_release(pSMB);
4415
4416 if (rc == -EAGAIN)
4417 goto QFSDeviceRetry;
4418
4419 return rc;
4420}
4421
4422int
Steve French737b7582005-04-28 22:41:06 -07004423CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424{
4425/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4426 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4427 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4428 FILE_SYSTEM_UNIX_INFO *response_data;
4429 int rc = 0;
4430 int bytes_returned = 0;
4431 __u16 params, byte_count;
4432
4433 cFYI(1, ("In QFSUnixInfo"));
4434QFSUnixRetry:
4435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4436 (void **) &pSMBr);
4437 if (rc)
4438 return rc;
4439
4440 params = 2; /* level */
4441 pSMB->TotalDataCount = 0;
4442 pSMB->DataCount = 0;
4443 pSMB->DataOffset = 0;
4444 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004445 /* BB find exact max SMB PDU from sess structure BB */
4446 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 pSMB->MaxSetupCount = 0;
4448 pSMB->Reserved = 0;
4449 pSMB->Flags = 0;
4450 pSMB->Timeout = 0;
4451 pSMB->Reserved2 = 0;
4452 byte_count = params + 1 /* pad */ ;
4453 pSMB->ParameterCount = cpu_to_le16(params);
4454 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004455 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4456 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 pSMB->SetupCount = 1;
4458 pSMB->Reserved3 = 0;
4459 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4460 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4461 pSMB->hdr.smb_buf_length += byte_count;
4462 pSMB->ByteCount = cpu_to_le16(byte_count);
4463
4464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4466 if (rc) {
4467 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4468 } else { /* decode response */
4469 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4470
4471 if (rc || (pSMBr->ByteCount < 13)) {
4472 rc = -EIO; /* bad smb */
4473 } else {
4474 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4475 response_data =
4476 (FILE_SYSTEM_UNIX_INFO
4477 *) (((char *) &pSMBr->hdr.Protocol) +
4478 data_offset);
4479 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004480 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 }
4482 }
4483 cifs_buf_release(pSMB);
4484
4485 if (rc == -EAGAIN)
4486 goto QFSUnixRetry;
4487
4488
4489 return rc;
4490}
4491
Jeremy Allisonac670552005-06-22 17:26:35 -07004492int
Steve French45abc6e2005-06-23 13:42:03 -05004493CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004494{
4495/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4496 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4497 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4498 int rc = 0;
4499 int bytes_returned = 0;
4500 __u16 params, param_offset, offset, byte_count;
4501
4502 cFYI(1, ("In SETFSUnixInfo"));
4503SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004504 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004505 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4506 (void **) &pSMBr);
4507 if (rc)
4508 return rc;
4509
4510 params = 4; /* 2 bytes zero followed by info level. */
4511 pSMB->MaxSetupCount = 0;
4512 pSMB->Reserved = 0;
4513 pSMB->Flags = 0;
4514 pSMB->Timeout = 0;
4515 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004516 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4517 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004518 offset = param_offset + params;
4519
4520 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004521 /* BB find exact max SMB PDU from sess structure BB */
4522 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004523 pSMB->SetupCount = 1;
4524 pSMB->Reserved3 = 0;
4525 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4526 byte_count = 1 /* pad */ + params + 12;
4527
4528 pSMB->DataCount = cpu_to_le16(12);
4529 pSMB->ParameterCount = cpu_to_le16(params);
4530 pSMB->TotalDataCount = pSMB->DataCount;
4531 pSMB->TotalParameterCount = pSMB->ParameterCount;
4532 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4533 pSMB->DataOffset = cpu_to_le16(offset);
4534
4535 /* Params. */
4536 pSMB->FileNum = 0;
4537 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4538
4539 /* Data. */
4540 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4541 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4542 pSMB->ClientUnixCap = cpu_to_le64(cap);
4543
4544 pSMB->hdr.smb_buf_length += byte_count;
4545 pSMB->ByteCount = cpu_to_le16(byte_count);
4546
4547 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4548 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4549 if (rc) {
4550 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4551 } else { /* decode response */
4552 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004553 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004554 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004555 }
4556 cifs_buf_release(pSMB);
4557
4558 if (rc == -EAGAIN)
4559 goto SETFSUnixRetry;
4560
4561 return rc;
4562}
4563
4564
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565
4566int
4567CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004568 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569{
4570/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4571 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4572 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4573 FILE_SYSTEM_POSIX_INFO *response_data;
4574 int rc = 0;
4575 int bytes_returned = 0;
4576 __u16 params, byte_count;
4577
4578 cFYI(1, ("In QFSPosixInfo"));
4579QFSPosixRetry:
4580 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4581 (void **) &pSMBr);
4582 if (rc)
4583 return rc;
4584
4585 params = 2; /* level */
4586 pSMB->TotalDataCount = 0;
4587 pSMB->DataCount = 0;
4588 pSMB->DataOffset = 0;
4589 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004590 /* BB find exact max SMB PDU from sess structure BB */
4591 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 pSMB->MaxSetupCount = 0;
4593 pSMB->Reserved = 0;
4594 pSMB->Flags = 0;
4595 pSMB->Timeout = 0;
4596 pSMB->Reserved2 = 0;
4597 byte_count = params + 1 /* pad */ ;
4598 pSMB->ParameterCount = cpu_to_le16(params);
4599 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004600 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4601 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 pSMB->SetupCount = 1;
4603 pSMB->Reserved3 = 0;
4604 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4605 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4606 pSMB->hdr.smb_buf_length += byte_count;
4607 pSMB->ByteCount = cpu_to_le16(byte_count);
4608
4609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4610 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4611 if (rc) {
4612 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4613 } else { /* decode response */
4614 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4615
4616 if (rc || (pSMBr->ByteCount < 13)) {
4617 rc = -EIO; /* bad smb */
4618 } else {
4619 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4620 response_data =
4621 (FILE_SYSTEM_POSIX_INFO
4622 *) (((char *) &pSMBr->hdr.Protocol) +
4623 data_offset);
4624 FSData->f_bsize =
4625 le32_to_cpu(response_data->BlockSize);
4626 FSData->f_blocks =
4627 le64_to_cpu(response_data->TotalBlocks);
4628 FSData->f_bfree =
4629 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004630 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 FSData->f_bavail = FSData->f_bfree;
4632 } else {
4633 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004634 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 }
Steve French790fe572007-07-07 19:25:05 +00004636 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004638 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004639 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004641 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 }
4643 }
4644 cifs_buf_release(pSMB);
4645
4646 if (rc == -EAGAIN)
4647 goto QFSPosixRetry;
4648
4649 return rc;
4650}
4651
4652
Steve French50c2f752007-07-13 00:33:32 +00004653/* We can not use write of zero bytes trick to
4654 set file size due to need for large file support. Also note that
4655 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 routine which is only needed to work around a sharing violation bug
4657 in Samba which this routine can run into */
4658
4659int
4660CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004661 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004662 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663{
4664 struct smb_com_transaction2_spi_req *pSMB = NULL;
4665 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4666 struct file_end_of_file_info *parm_data;
4667 int name_len;
4668 int rc = 0;
4669 int bytes_returned = 0;
4670 __u16 params, byte_count, data_count, param_offset, offset;
4671
4672 cFYI(1, ("In SetEOF"));
4673SetEOFRetry:
4674 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4675 (void **) &pSMBr);
4676 if (rc)
4677 return rc;
4678
4679 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4680 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004681 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004682 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 name_len++; /* trailing null */
4684 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004685 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 name_len = strnlen(fileName, PATH_MAX);
4687 name_len++; /* trailing null */
4688 strncpy(pSMB->FileName, fileName, name_len);
4689 }
4690 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004691 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004693 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 pSMB->MaxSetupCount = 0;
4695 pSMB->Reserved = 0;
4696 pSMB->Flags = 0;
4697 pSMB->Timeout = 0;
4698 pSMB->Reserved2 = 0;
4699 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004700 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004702 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004703 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4704 pSMB->InformationLevel =
4705 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4706 else
4707 pSMB->InformationLevel =
4708 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4709 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4711 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004712 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 else
4714 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004715 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 }
4717
4718 parm_data =
4719 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4720 offset);
4721 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4722 pSMB->DataOffset = cpu_to_le16(offset);
4723 pSMB->SetupCount = 1;
4724 pSMB->Reserved3 = 0;
4725 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4726 byte_count = 3 /* pad */ + params + data_count;
4727 pSMB->DataCount = cpu_to_le16(data_count);
4728 pSMB->TotalDataCount = pSMB->DataCount;
4729 pSMB->ParameterCount = cpu_to_le16(params);
4730 pSMB->TotalParameterCount = pSMB->ParameterCount;
4731 pSMB->Reserved4 = 0;
4732 pSMB->hdr.smb_buf_length += byte_count;
4733 parm_data->FileSize = cpu_to_le64(size);
4734 pSMB->ByteCount = cpu_to_le16(byte_count);
4735 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4736 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004737 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
4740 cifs_buf_release(pSMB);
4741
4742 if (rc == -EAGAIN)
4743 goto SetEOFRetry;
4744
4745 return rc;
4746}
4747
4748int
Steve French50c2f752007-07-13 00:33:32 +00004749CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004750 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751{
4752 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 char *data_offset;
4754 struct file_end_of_file_info *parm_data;
4755 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 __u16 params, param_offset, offset, byte_count, count;
4757
4758 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4759 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004760 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4761
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 if (rc)
4763 return rc;
4764
4765 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4766 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004767
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 params = 6;
4769 pSMB->MaxSetupCount = 0;
4770 pSMB->Reserved = 0;
4771 pSMB->Flags = 0;
4772 pSMB->Timeout = 0;
4773 pSMB->Reserved2 = 0;
4774 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4775 offset = param_offset + params;
4776
Steve French50c2f752007-07-13 00:33:32 +00004777 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
4779 count = sizeof(struct file_end_of_file_info);
4780 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004781 /* BB find exact max SMB PDU from sess structure BB */
4782 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783 pSMB->SetupCount = 1;
4784 pSMB->Reserved3 = 0;
4785 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4786 byte_count = 3 /* pad */ + params + count;
4787 pSMB->DataCount = cpu_to_le16(count);
4788 pSMB->ParameterCount = cpu_to_le16(params);
4789 pSMB->TotalDataCount = pSMB->DataCount;
4790 pSMB->TotalParameterCount = pSMB->ParameterCount;
4791 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4792 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004793 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4794 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 pSMB->DataOffset = cpu_to_le16(offset);
4796 parm_data->FileSize = cpu_to_le64(size);
4797 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004798 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4800 pSMB->InformationLevel =
4801 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4802 else
4803 pSMB->InformationLevel =
4804 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004805 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4807 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004808 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 else
4810 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004811 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 }
4813 pSMB->Reserved4 = 0;
4814 pSMB->hdr.smb_buf_length += byte_count;
4815 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004816 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 if (rc) {
4818 cFYI(1,
4819 ("Send error in SetFileInfo (SetFileSize) = %d",
4820 rc));
4821 }
4822
Steve French50c2f752007-07-13 00:33:32 +00004823 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 since file handle passed in no longer valid */
4825
4826 return rc;
4827}
4828
Steve French50c2f752007-07-13 00:33:32 +00004829/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 an open handle, rather than by pathname - this is awkward due to
4831 potential access conflicts on the open, but it is unavoidable for these
4832 old servers since the only other choice is to go from 100 nanosecond DCE
4833 time and resort to the original setpathinfo level which takes the ancient
4834 DOS time format with 2 second granularity */
4835int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004836CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4837 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838{
4839 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 char *data_offset;
4841 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 __u16 params, param_offset, offset, byte_count, count;
4843
4844 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004845 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4846
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 if (rc)
4848 return rc;
4849
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004850 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4851 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004852
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 params = 6;
4854 pSMB->MaxSetupCount = 0;
4855 pSMB->Reserved = 0;
4856 pSMB->Flags = 0;
4857 pSMB->Timeout = 0;
4858 pSMB->Reserved2 = 0;
4859 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4860 offset = param_offset + params;
4861
Steve French50c2f752007-07-13 00:33:32 +00004862 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863
Steve French26f57362007-08-30 22:09:15 +00004864 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004866 /* BB find max SMB PDU from sess */
4867 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 pSMB->SetupCount = 1;
4869 pSMB->Reserved3 = 0;
4870 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4871 byte_count = 3 /* pad */ + params + count;
4872 pSMB->DataCount = cpu_to_le16(count);
4873 pSMB->ParameterCount = cpu_to_le16(params);
4874 pSMB->TotalDataCount = pSMB->DataCount;
4875 pSMB->TotalParameterCount = pSMB->ParameterCount;
4876 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4877 pSMB->DataOffset = cpu_to_le16(offset);
4878 pSMB->Fid = fid;
4879 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4880 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4881 else
4882 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4883 pSMB->Reserved4 = 0;
4884 pSMB->hdr.smb_buf_length += byte_count;
4885 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004886 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004887 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004888 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004889 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890
Steve French50c2f752007-07-13 00:33:32 +00004891 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 since file handle passed in no longer valid */
4893
4894 return rc;
4895}
4896
Jeff Layton6d22f092008-09-23 11:48:35 -04004897int
4898CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4899 bool delete_file, __u16 fid, __u32 pid_of_opener)
4900{
4901 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4902 char *data_offset;
4903 int rc = 0;
4904 __u16 params, param_offset, offset, byte_count, count;
4905
4906 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4907 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4908
4909 if (rc)
4910 return rc;
4911
4912 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4913 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4914
4915 params = 6;
4916 pSMB->MaxSetupCount = 0;
4917 pSMB->Reserved = 0;
4918 pSMB->Flags = 0;
4919 pSMB->Timeout = 0;
4920 pSMB->Reserved2 = 0;
4921 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4922 offset = param_offset + params;
4923
4924 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4925
4926 count = 1;
4927 pSMB->MaxParameterCount = cpu_to_le16(2);
4928 /* BB find max SMB PDU from sess */
4929 pSMB->MaxDataCount = cpu_to_le16(1000);
4930 pSMB->SetupCount = 1;
4931 pSMB->Reserved3 = 0;
4932 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4933 byte_count = 3 /* pad */ + params + count;
4934 pSMB->DataCount = cpu_to_le16(count);
4935 pSMB->ParameterCount = cpu_to_le16(params);
4936 pSMB->TotalDataCount = pSMB->DataCount;
4937 pSMB->TotalParameterCount = pSMB->ParameterCount;
4938 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4939 pSMB->DataOffset = cpu_to_le16(offset);
4940 pSMB->Fid = fid;
4941 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4942 pSMB->Reserved4 = 0;
4943 pSMB->hdr.smb_buf_length += byte_count;
4944 pSMB->ByteCount = cpu_to_le16(byte_count);
4945 *data_offset = delete_file ? 1 : 0;
4946 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4947 if (rc)
4948 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4949
4950 return rc;
4951}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952
4953int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004954CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4955 const char *fileName, const FILE_BASIC_INFO *data,
4956 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957{
4958 TRANSACTION2_SPI_REQ *pSMB = NULL;
4959 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4960 int name_len;
4961 int rc = 0;
4962 int bytes_returned = 0;
4963 char *data_offset;
4964 __u16 params, param_offset, offset, byte_count, count;
4965
4966 cFYI(1, ("In SetTimes"));
4967
4968SetTimesRetry:
4969 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4970 (void **) &pSMBr);
4971 if (rc)
4972 return rc;
4973
4974 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4975 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004976 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004977 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004978 name_len++; /* trailing null */
4979 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004980 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981 name_len = strnlen(fileName, PATH_MAX);
4982 name_len++; /* trailing null */
4983 strncpy(pSMB->FileName, fileName, name_len);
4984 }
4985
4986 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004987 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004989 /* BB find max SMB PDU from sess structure BB */
4990 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 pSMB->MaxSetupCount = 0;
4992 pSMB->Reserved = 0;
4993 pSMB->Flags = 0;
4994 pSMB->Timeout = 0;
4995 pSMB->Reserved2 = 0;
4996 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004997 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 offset = param_offset + params;
4999 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5000 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5001 pSMB->DataOffset = cpu_to_le16(offset);
5002 pSMB->SetupCount = 1;
5003 pSMB->Reserved3 = 0;
5004 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5005 byte_count = 3 /* pad */ + params + count;
5006
5007 pSMB->DataCount = cpu_to_le16(count);
5008 pSMB->ParameterCount = cpu_to_le16(params);
5009 pSMB->TotalDataCount = pSMB->DataCount;
5010 pSMB->TotalParameterCount = pSMB->ParameterCount;
5011 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5012 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5013 else
5014 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5015 pSMB->Reserved4 = 0;
5016 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005017 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 pSMB->ByteCount = cpu_to_le16(byte_count);
5019 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5020 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005021 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005023
5024 cifs_buf_release(pSMB);
5025
5026 if (rc == -EAGAIN)
5027 goto SetTimesRetry;
5028
5029 return rc;
5030}
5031
5032/* Can not be used to set time stamps yet (due to old DOS time format) */
5033/* Can be used to set attributes */
5034#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5035 handling it anyway and NT4 was what we thought it would be needed for
5036 Do not delete it until we prove whether needed for Win9x though */
5037int
5038CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5039 __u16 dos_attrs, const struct nls_table *nls_codepage)
5040{
5041 SETATTR_REQ *pSMB = NULL;
5042 SETATTR_RSP *pSMBr = NULL;
5043 int rc = 0;
5044 int bytes_returned;
5045 int name_len;
5046
5047 cFYI(1, ("In SetAttrLegacy"));
5048
5049SetAttrLgcyRetry:
5050 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5051 (void **) &pSMBr);
5052 if (rc)
5053 return rc;
5054
5055 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5056 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005057 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 PATH_MAX, nls_codepage);
5059 name_len++; /* trailing null */
5060 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005061 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 name_len = strnlen(fileName, PATH_MAX);
5063 name_len++; /* trailing null */
5064 strncpy(pSMB->fileName, fileName, name_len);
5065 }
5066 pSMB->attr = cpu_to_le16(dos_attrs);
5067 pSMB->BufferFormat = 0x04;
5068 pSMB->hdr.smb_buf_length += name_len + 1;
5069 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005072 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074
5075 cifs_buf_release(pSMB);
5076
5077 if (rc == -EAGAIN)
5078 goto SetAttrLgcyRetry;
5079
5080 return rc;
5081}
5082#endif /* temporarily unneeded SetAttr legacy function */
5083
Jeff Layton654cf142009-07-09 20:02:49 -04005084static void
5085cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5086 const struct cifs_unix_set_info_args *args)
5087{
5088 u64 mode = args->mode;
5089
5090 /*
5091 * Samba server ignores set of file size to zero due to bugs in some
5092 * older clients, but we should be precise - we use SetFileSize to
5093 * set file size and do not want to truncate file size to zero
5094 * accidently as happened on one Samba server beta by putting
5095 * zero instead of -1 here
5096 */
5097 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5098 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5099 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5100 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5101 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5102 data_offset->Uid = cpu_to_le64(args->uid);
5103 data_offset->Gid = cpu_to_le64(args->gid);
5104 /* better to leave device as zero when it is */
5105 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5106 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5107 data_offset->Permissions = cpu_to_le64(mode);
5108
5109 if (S_ISREG(mode))
5110 data_offset->Type = cpu_to_le32(UNIX_FILE);
5111 else if (S_ISDIR(mode))
5112 data_offset->Type = cpu_to_le32(UNIX_DIR);
5113 else if (S_ISLNK(mode))
5114 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5115 else if (S_ISCHR(mode))
5116 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5117 else if (S_ISBLK(mode))
5118 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5119 else if (S_ISFIFO(mode))
5120 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5121 else if (S_ISSOCK(mode))
5122 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5123}
5124
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005126CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5127 const struct cifs_unix_set_info_args *args,
5128 u16 fid, u32 pid_of_opener)
5129{
5130 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5131 FILE_UNIX_BASIC_INFO *data_offset;
5132 int rc = 0;
5133 u16 params, param_offset, offset, byte_count, count;
5134
5135 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5136 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5137
5138 if (rc)
5139 return rc;
5140
5141 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5142 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5143
5144 params = 6;
5145 pSMB->MaxSetupCount = 0;
5146 pSMB->Reserved = 0;
5147 pSMB->Flags = 0;
5148 pSMB->Timeout = 0;
5149 pSMB->Reserved2 = 0;
5150 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5151 offset = param_offset + params;
5152
5153 data_offset = (FILE_UNIX_BASIC_INFO *)
5154 ((char *)(&pSMB->hdr.Protocol) + offset);
5155 count = sizeof(FILE_UNIX_BASIC_INFO);
5156
5157 pSMB->MaxParameterCount = cpu_to_le16(2);
5158 /* BB find max SMB PDU from sess */
5159 pSMB->MaxDataCount = cpu_to_le16(1000);
5160 pSMB->SetupCount = 1;
5161 pSMB->Reserved3 = 0;
5162 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5163 byte_count = 3 /* pad */ + params + count;
5164 pSMB->DataCount = cpu_to_le16(count);
5165 pSMB->ParameterCount = cpu_to_le16(params);
5166 pSMB->TotalDataCount = pSMB->DataCount;
5167 pSMB->TotalParameterCount = pSMB->ParameterCount;
5168 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5169 pSMB->DataOffset = cpu_to_le16(offset);
5170 pSMB->Fid = fid;
5171 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5172 pSMB->Reserved4 = 0;
5173 pSMB->hdr.smb_buf_length += byte_count;
5174 pSMB->ByteCount = cpu_to_le16(byte_count);
5175
5176 cifs_fill_unix_set_info(data_offset, args);
5177
5178 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5179 if (rc)
5180 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5181
5182 /* Note: On -EAGAIN error only caller can retry on handle based calls
5183 since file handle passed in no longer valid */
5184
5185 return rc;
5186}
5187
5188int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005189CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5190 const struct cifs_unix_set_info_args *args,
5191 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192{
5193 TRANSACTION2_SPI_REQ *pSMB = NULL;
5194 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5195 int name_len;
5196 int rc = 0;
5197 int bytes_returned = 0;
5198 FILE_UNIX_BASIC_INFO *data_offset;
5199 __u16 params, param_offset, offset, count, byte_count;
5200
5201 cFYI(1, ("In SetUID/GID/Mode"));
5202setPermsRetry:
5203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5204 (void **) &pSMBr);
5205 if (rc)
5206 return rc;
5207
5208 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5209 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005210 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005211 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 name_len++; /* trailing null */
5213 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005214 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005215 name_len = strnlen(fileName, PATH_MAX);
5216 name_len++; /* trailing null */
5217 strncpy(pSMB->FileName, fileName, name_len);
5218 }
5219
5220 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005221 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005222 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005223 /* BB find max SMB PDU from sess structure BB */
5224 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 pSMB->MaxSetupCount = 0;
5226 pSMB->Reserved = 0;
5227 pSMB->Flags = 0;
5228 pSMB->Timeout = 0;
5229 pSMB->Reserved2 = 0;
5230 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005231 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 offset = param_offset + params;
5233 data_offset =
5234 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5235 offset);
5236 memset(data_offset, 0, count);
5237 pSMB->DataOffset = cpu_to_le16(offset);
5238 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5239 pSMB->SetupCount = 1;
5240 pSMB->Reserved3 = 0;
5241 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5242 byte_count = 3 /* pad */ + params + count;
5243 pSMB->ParameterCount = cpu_to_le16(params);
5244 pSMB->DataCount = cpu_to_le16(count);
5245 pSMB->TotalParameterCount = pSMB->ParameterCount;
5246 pSMB->TotalDataCount = pSMB->DataCount;
5247 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5248 pSMB->Reserved4 = 0;
5249 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005250
Jeff Layton654cf142009-07-09 20:02:49 -04005251 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252
5253 pSMB->ByteCount = cpu_to_le16(byte_count);
5254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005256 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005258
Steve French0d817bc2008-05-22 02:02:03 +00005259 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 if (rc == -EAGAIN)
5261 goto setPermsRetry;
5262 return rc;
5263}
5264
Steve French50c2f752007-07-13 00:33:32 +00005265int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005266 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005267 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005268 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269{
5270 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005271 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5272 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005273 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 int bytes_returned;
5275
Steve French50c2f752007-07-13 00:33:32 +00005276 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005278 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 if (rc)
5280 return rc;
5281
5282 pSMB->TotalParameterCount = 0 ;
5283 pSMB->TotalDataCount = 0;
5284 pSMB->MaxParameterCount = cpu_to_le32(2);
5285 /* BB find exact data count max from sess structure BB */
5286 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005287/* BB VERIFY verify which is correct for above BB */
5288 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5289 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5290
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 pSMB->MaxSetupCount = 4;
5292 pSMB->Reserved = 0;
5293 pSMB->ParameterOffset = 0;
5294 pSMB->DataCount = 0;
5295 pSMB->DataOffset = 0;
5296 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5297 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5298 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005299 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5301 pSMB->Reserved2 = 0;
5302 pSMB->CompletionFilter = cpu_to_le32(filter);
5303 pSMB->Fid = netfid; /* file handle always le */
5304 pSMB->ByteCount = 0;
5305
5306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005307 (struct smb_hdr *)pSMBr, &bytes_returned,
5308 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 if (rc) {
5310 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005311 } else {
5312 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005313 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005314 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005315 sizeof(struct dir_notify_req),
5316 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005317 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005318 dnotify_req->Pid = pSMB->hdr.Pid;
5319 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5320 dnotify_req->Mid = pSMB->hdr.Mid;
5321 dnotify_req->Tid = pSMB->hdr.Tid;
5322 dnotify_req->Uid = pSMB->hdr.Uid;
5323 dnotify_req->netfid = netfid;
5324 dnotify_req->pfile = pfile;
5325 dnotify_req->filter = filter;
5326 dnotify_req->multishot = multishot;
5327 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005328 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005329 &GlobalDnotifyReqList);
5330 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005331 } else
Steve French47c786e2005-10-11 20:03:18 -07005332 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 }
5334 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005335 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336}
5337#ifdef CONFIG_CIFS_XATTR
5338ssize_t
5339CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5340 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005341 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005342 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343{
5344 /* BB assumes one setup word */
5345 TRANSACTION2_QPI_REQ *pSMB = NULL;
5346 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5347 int rc = 0;
5348 int bytes_returned;
5349 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005350 struct fea *temp_fea;
5351 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 __u16 params, byte_count;
5353
5354 cFYI(1, ("In Query All EAs path %s", searchName));
5355QAllEAsRetry:
5356 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5357 (void **) &pSMBr);
5358 if (rc)
5359 return rc;
5360
5361 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5362 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005363 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005364 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 name_len++; /* trailing null */
5366 name_len *= 2;
5367 } else { /* BB improve the check for buffer overruns BB */
5368 name_len = strnlen(searchName, PATH_MAX);
5369 name_len++; /* trailing null */
5370 strncpy(pSMB->FileName, searchName, name_len);
5371 }
5372
Steve French50c2f752007-07-13 00:33:32 +00005373 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005374 pSMB->TotalDataCount = 0;
5375 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005376 /* BB find exact max SMB PDU from sess structure BB */
5377 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 pSMB->MaxSetupCount = 0;
5379 pSMB->Reserved = 0;
5380 pSMB->Flags = 0;
5381 pSMB->Timeout = 0;
5382 pSMB->Reserved2 = 0;
5383 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005384 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 pSMB->DataCount = 0;
5386 pSMB->DataOffset = 0;
5387 pSMB->SetupCount = 1;
5388 pSMB->Reserved3 = 0;
5389 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5390 byte_count = params + 1 /* pad */ ;
5391 pSMB->TotalParameterCount = cpu_to_le16(params);
5392 pSMB->ParameterCount = pSMB->TotalParameterCount;
5393 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5394 pSMB->Reserved4 = 0;
5395 pSMB->hdr.smb_buf_length += byte_count;
5396 pSMB->ByteCount = cpu_to_le16(byte_count);
5397
5398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5400 if (rc) {
5401 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5402 } else { /* decode response */
5403 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5404
5405 /* BB also check enough total bytes returned */
5406 /* BB we need to improve the validity checking
5407 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005408 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 rc = -EIO; /* bad smb */
5410 /* else if (pFindData){
5411 memcpy((char *) pFindData,
5412 (char *) &pSMBr->hdr.Protocol +
5413 data_offset, kl);
5414 }*/ else {
5415 /* check that length of list is not more than bcc */
5416 /* check that each entry does not go beyond length
5417 of list */
5418 /* check that each element of each entry does not
5419 go beyond end of list */
5420 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005421 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 rc = 0;
5423 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005424 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005425 ea_response_data = (struct fealist *)
5426 (((char *) &pSMBr->hdr.Protocol) +
5427 data_offset);
5428 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005429 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005430 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005432 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433 } else {
5434 /* account for ea list len */
5435 name_len -= 4;
5436 temp_fea = ea_response_data->list;
5437 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005438 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439 __u16 value_len;
5440 name_len -= 4;
5441 temp_ptr += 4;
5442 rc += temp_fea->name_len;
5443 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005444 rc = rc + 5 + 1;
5445 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005446 memcpy(EAData, "user.", 5);
5447 EAData += 5;
5448 memcpy(EAData, temp_ptr,
5449 temp_fea->name_len);
5450 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451 /* null terminate name */
5452 *EAData = 0;
5453 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005454 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 /* skip copy - calc size only */
5456 } else {
5457 /* stop before overrun buffer */
5458 rc = -ERANGE;
5459 break;
5460 }
5461 name_len -= temp_fea->name_len;
5462 temp_ptr += temp_fea->name_len;
5463 /* account for trailing null */
5464 name_len--;
5465 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005466 value_len =
5467 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 name_len -= value_len;
5469 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005470 /* BB check that temp_ptr is still
5471 within the SMB BB*/
5472
5473 /* no trailing null to account for
5474 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 /* go on to next EA */
5476 temp_fea = (struct fea *)temp_ptr;
5477 }
5478 }
5479 }
5480 }
Steve French0d817bc2008-05-22 02:02:03 +00005481 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 if (rc == -EAGAIN)
5483 goto QAllEAsRetry;
5484
5485 return (ssize_t)rc;
5486}
5487
Steve French50c2f752007-07-13 00:33:32 +00005488ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5489 const unsigned char *searchName, const unsigned char *ea_name,
5490 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005491 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492{
5493 TRANSACTION2_QPI_REQ *pSMB = NULL;
5494 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5495 int rc = 0;
5496 int bytes_returned;
5497 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005498 struct fea *temp_fea;
5499 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 __u16 params, byte_count;
5501
5502 cFYI(1, ("In Query EA path %s", searchName));
5503QEARetry:
5504 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5505 (void **) &pSMBr);
5506 if (rc)
5507 return rc;
5508
5509 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5510 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005511 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005512 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 name_len++; /* trailing null */
5514 name_len *= 2;
5515 } else { /* BB improve the check for buffer overruns BB */
5516 name_len = strnlen(searchName, PATH_MAX);
5517 name_len++; /* trailing null */
5518 strncpy(pSMB->FileName, searchName, name_len);
5519 }
5520
Steve French50c2f752007-07-13 00:33:32 +00005521 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005522 pSMB->TotalDataCount = 0;
5523 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005524 /* BB find exact max SMB PDU from sess structure BB */
5525 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 pSMB->MaxSetupCount = 0;
5527 pSMB->Reserved = 0;
5528 pSMB->Flags = 0;
5529 pSMB->Timeout = 0;
5530 pSMB->Reserved2 = 0;
5531 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005532 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533 pSMB->DataCount = 0;
5534 pSMB->DataOffset = 0;
5535 pSMB->SetupCount = 1;
5536 pSMB->Reserved3 = 0;
5537 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5538 byte_count = params + 1 /* pad */ ;
5539 pSMB->TotalParameterCount = cpu_to_le16(params);
5540 pSMB->ParameterCount = pSMB->TotalParameterCount;
5541 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5542 pSMB->Reserved4 = 0;
5543 pSMB->hdr.smb_buf_length += byte_count;
5544 pSMB->ByteCount = cpu_to_le16(byte_count);
5545
5546 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5547 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5548 if (rc) {
5549 cFYI(1, ("Send error in Query EA = %d", rc));
5550 } else { /* decode response */
5551 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5552
5553 /* BB also check enough total bytes returned */
5554 /* BB we need to improve the validity checking
5555 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005556 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 rc = -EIO; /* bad smb */
5558 /* else if (pFindData){
5559 memcpy((char *) pFindData,
5560 (char *) &pSMBr->hdr.Protocol +
5561 data_offset, kl);
5562 }*/ else {
5563 /* check that length of list is not more than bcc */
5564 /* check that each entry does not go beyond length
5565 of list */
5566 /* check that each element of each entry does not
5567 go beyond end of list */
5568 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005569 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005570 rc = -ENODATA;
5571 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005572 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005573 ea_response_data = (struct fealist *)
5574 (((char *) &pSMBr->hdr.Protocol) +
5575 data_offset);
5576 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005577 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005578 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005579 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005580 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005581 } else {
5582 /* account for ea list len */
5583 name_len -= 4;
5584 temp_fea = ea_response_data->list;
5585 temp_ptr = (char *)temp_fea;
5586 /* loop through checking if we have a matching
5587 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005588 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589 __u16 value_len;
5590 name_len -= 4;
5591 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005592 value_len =
5593 le16_to_cpu(temp_fea->value_len);
5594 /* BB validate that value_len falls within SMB,
5595 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005596 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005597 temp_fea->name_len) == 0) {
5598 /* found a match */
5599 rc = value_len;
5600 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005601 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 memcpy(ea_value,
5603 temp_fea->name+temp_fea->name_len+1,
5604 rc);
Steve French50c2f752007-07-13 00:33:32 +00005605 /* ea values, unlike ea
5606 names, are not null
5607 terminated */
Steve French790fe572007-07-07 19:25:05 +00005608 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 /* skip copy - calc size only */
5610 } else {
Steve French50c2f752007-07-13 00:33:32 +00005611 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 rc = -ERANGE;
5613 }
5614 break;
5615 }
5616 name_len -= temp_fea->name_len;
5617 temp_ptr += temp_fea->name_len;
5618 /* account for trailing null */
5619 name_len--;
5620 temp_ptr++;
5621 name_len -= value_len;
5622 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005623 /* No trailing null to account for in
5624 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 temp_fea = (struct fea *)temp_ptr;
5626 }
Steve French50c2f752007-07-13 00:33:32 +00005627 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 }
5629 }
Steve French0d817bc2008-05-22 02:02:03 +00005630 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 if (rc == -EAGAIN)
5632 goto QEARetry;
5633
5634 return (ssize_t)rc;
5635}
5636
5637int
5638CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005639 const char *ea_name, const void *ea_value,
5640 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5641 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642{
5643 struct smb_com_transaction2_spi_req *pSMB = NULL;
5644 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5645 struct fealist *parm_data;
5646 int name_len;
5647 int rc = 0;
5648 int bytes_returned = 0;
5649 __u16 params, param_offset, byte_count, offset, count;
5650
5651 cFYI(1, ("In SetEA"));
5652SetEARetry:
5653 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5654 (void **) &pSMBr);
5655 if (rc)
5656 return rc;
5657
5658 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5659 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005660 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005661 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662 name_len++; /* trailing null */
5663 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005664 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005665 name_len = strnlen(fileName, PATH_MAX);
5666 name_len++; /* trailing null */
5667 strncpy(pSMB->FileName, fileName, name_len);
5668 }
5669
5670 params = 6 + name_len;
5671
5672 /* done calculating parms using name_len of file name,
5673 now use name_len to calculate length of ea name
5674 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005675 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 name_len = 0;
5677 else
Steve French50c2f752007-07-13 00:33:32 +00005678 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005680 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005682 /* BB find max SMB PDU from sess */
5683 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 pSMB->MaxSetupCount = 0;
5685 pSMB->Reserved = 0;
5686 pSMB->Flags = 0;
5687 pSMB->Timeout = 0;
5688 pSMB->Reserved2 = 0;
5689 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005690 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 offset = param_offset + params;
5692 pSMB->InformationLevel =
5693 cpu_to_le16(SMB_SET_FILE_EA);
5694
5695 parm_data =
5696 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5697 offset);
5698 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5699 pSMB->DataOffset = cpu_to_le16(offset);
5700 pSMB->SetupCount = 1;
5701 pSMB->Reserved3 = 0;
5702 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5703 byte_count = 3 /* pad */ + params + count;
5704 pSMB->DataCount = cpu_to_le16(count);
5705 parm_data->list_len = cpu_to_le32(count);
5706 parm_data->list[0].EA_flags = 0;
5707 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005708 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005710 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005711 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712 parm_data->list[0].name[name_len] = 0;
5713 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5714 /* caller ensures that ea_value_len is less than 64K but
5715 we need to ensure that it fits within the smb */
5716
Steve French50c2f752007-07-13 00:33:32 +00005717 /*BB add length check to see if it would fit in
5718 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005719 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5720 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005721 memcpy(parm_data->list[0].name+name_len+1,
5722 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
5724 pSMB->TotalDataCount = pSMB->DataCount;
5725 pSMB->ParameterCount = cpu_to_le16(params);
5726 pSMB->TotalParameterCount = pSMB->ParameterCount;
5727 pSMB->Reserved4 = 0;
5728 pSMB->hdr.smb_buf_length += byte_count;
5729 pSMB->ByteCount = cpu_to_le16(byte_count);
5730 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5731 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005732 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005733 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734
5735 cifs_buf_release(pSMB);
5736
5737 if (rc == -EAGAIN)
5738 goto SetEARetry;
5739
5740 return rc;
5741}
5742
5743#endif