blob: 4bda920d1f754548ea705b94b13be9a1db321699 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
35#include <asm/uaccess.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000038#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42
43#ifdef CONFIG_CIFS_POSIX
44static struct {
45 int index;
46 char *name;
47} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000048#ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000050 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000051#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000052 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000053 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 {BAD_PROT, "\2"}
55};
56#else
57static struct {
58 int index;
59 char *name;
60} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000061#ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000063 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000064#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000065 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 {BAD_PROT, "\2"}
67};
68#endif
69
Steve French39798772006-05-31 22:40:51 +000070/* define the number of elements in the cifs dialect array */
71#ifdef CONFIG_CIFS_POSIX
72#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000073#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000074#else
75#define CIFS_NUM_PROT 2
76#endif /* CIFS_WEAK_PW_HASH */
77#else /* not posix */
78#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000079#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000080#else
81#define CIFS_NUM_PROT 1
82#endif /* CONFIG_CIFS_WEAK_PW_HASH */
83#endif /* CIFS_POSIX */
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000097 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040098 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Jeff Layton9162ab22009-09-03 12:07:17 -0400105/* reconnect the socket, tcon, and smb session if needed */
106static int
107cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
108{
109 int rc = 0;
110 struct cifsSesInfo *ses;
111 struct TCP_Server_Info *server;
112 struct nls_table *nls_codepage;
113
114 /*
115 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
116 * tcp and smb session status done differently for those three - in the
117 * calling routine
118 */
119 if (!tcon)
120 return 0;
121
122 ses = tcon->ses;
123 server = ses->server;
124
125 /*
126 * only tree disconnect, open, and write, (and ulogoff which does not
127 * have tcon) are allowed as we start force umount
128 */
129 if (tcon->tidStatus == CifsExiting) {
130 if (smb_command != SMB_COM_WRITE_ANDX &&
131 smb_command != SMB_COM_OPEN_ANDX &&
132 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000133 cFYI(1, "can not send cmd %d while umounting",
134 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400135 return -ENODEV;
136 }
137 }
138
139 if (ses->status == CifsExiting)
140 return -EIO;
141
142 /*
143 * Give demultiplex thread up to 10 seconds to reconnect, should be
144 * greater than cifs socket timeout which is 7 seconds
145 */
146 while (server->tcpStatus == CifsNeedReconnect) {
147 wait_event_interruptible_timeout(server->response_q,
148 (server->tcpStatus == CifsGood), 10 * HZ);
149
150 /* is TCP session is reestablished now ?*/
151 if (server->tcpStatus != CifsNeedReconnect)
152 break;
153
154 /*
155 * on "soft" mounts we wait once. Hard mounts keep
156 * retrying until process is killed or server comes
157 * back on-line
158 */
159 if (!tcon->retry || ses->status == CifsExiting) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000160 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400161 return -EHOSTDOWN;
162 }
163 }
164
165 if (!ses->need_reconnect && !tcon->need_reconnect)
166 return 0;
167
168 nls_codepage = load_nls_default();
169
170 /*
171 * need to prevent multiple threads trying to simultaneously
172 * reconnect the same SMB session
173 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000174 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400175 rc = cifs_negotiate_protocol(0, ses);
176 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400177 rc = cifs_setup_session(0, ses, nls_codepage);
178
179 /* do we need to reconnect tcon? */
180 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000181 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400182 goto out;
183 }
184
185 mark_open_files_invalid(tcon);
186 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000187 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000188 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400189
190 if (rc)
191 goto out;
192
193 /*
194 * FIXME: check if wsize needs updated due to negotiated smb buffer
195 * size shrinking
196 */
197 atomic_inc(&tconInfoReconnectCount);
198
199 /* tell server Unix caps we support */
200 if (ses->capabilities & CAP_UNIX)
201 reset_cifs_unix_caps(0, tcon, NULL, NULL);
202
203 /*
204 * Removed call to reopen open files here. It is safer (and faster) to
205 * reopen files one at a time as needed in read and write.
206 *
207 * FIXME: what about file locks? don't we need to reclaim them ASAP?
208 */
209
210out:
211 /*
212 * Check if handle based operation so we know whether we can continue
213 * or not without returning to caller to reset file handle
214 */
215 switch (smb_command) {
216 case SMB_COM_READ_ANDX:
217 case SMB_COM_WRITE_ANDX:
218 case SMB_COM_CLOSE:
219 case SMB_COM_FIND_CLOSE2:
220 case SMB_COM_LOCKING_ANDX:
221 rc = -EAGAIN;
222 }
223
224 unload_nls(nls_codepage);
225 return rc;
226}
227
Steve Frenchad7a2922008-02-07 23:25:02 +0000228/* Allocate and return pointer to an SMB request buffer, and set basic
229 SMB information in the SMB header. If the return code is zero, this
230 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231static int
232small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000233 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234{
235 int rc = 0;
236
Jeff Layton9162ab22009-09-03 12:07:17 -0400237 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000238 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 return rc;
240
241 *request_buf = cifs_small_buf_get();
242 if (*request_buf == NULL) {
243 /* BB should we add a retry in here if not a writepage? */
244 return -ENOMEM;
245 }
246
Steve French63135e02007-07-17 17:34:02 +0000247 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000248 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
Steve French790fe572007-07-07 19:25:05 +0000250 if (tcon != NULL)
251 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000254}
255
Steve French12b3b8f2006-02-09 21:12:47 +0000256int
Steve French50c2f752007-07-13 00:33:32 +0000257small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000258 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000259{
260 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000261 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000262
Steve French5815449d2006-02-14 01:36:20 +0000263 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000264 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000265 return rc;
266
Steve French04fdabe2006-02-10 05:52:50 +0000267 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000268 buffer->Mid = GetNextMid(ses->server);
269 if (ses->capabilities & CAP_UNICODE)
270 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000271 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000272 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
273
274 /* uid, tid can stay at zero as set in header assemble */
275
Steve French50c2f752007-07-13 00:33:32 +0000276 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000277 this function is used after 1st of session setup requests */
278
279 return rc;
280}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
282/* If the return code is zero, this function must fill in request_buf pointer */
283static int
284smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
285 void **request_buf /* returned */ ,
286 void **response_buf /* returned */ )
287{
288 int rc = 0;
289
Jeff Layton9162ab22009-09-03 12:07:17 -0400290 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000291 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return rc;
293
294 *request_buf = cifs_buf_get();
295 if (*request_buf == NULL) {
296 /* BB should we add a retry in here if not a writepage? */
297 return -ENOMEM;
298 }
299 /* Although the original thought was we needed the response buf for */
300 /* potential retries of smb operations it turns out we can determine */
301 /* from the mid flags when the request buffer can be resent without */
302 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000303 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000304 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
306 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000307 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Steve French790fe572007-07-07 19:25:05 +0000309 if (tcon != NULL)
310 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 return rc;
313}
314
Steve French50c2f752007-07-13 00:33:32 +0000315static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
317 int rc = -EINVAL;
318 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000319 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 /* check for plausible wct, bcc and t2 data and parm sizes */
322 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000323 if (pSMB->hdr.WordCount >= 10) {
324 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
326 /* check that bcc is at least as big as parms + data */
327 /* check that bcc is less than negotiated smb buffer */
328 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000329 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000330 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000331 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000333 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700334 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000336 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000337 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
339 return 0;
340 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342 }
343 }
Steve French50c2f752007-07-13 00:33:32 +0000344 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 sizeof(struct smb_t2_rsp) + 16);
346 return rc;
347}
348int
349CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
350{
351 NEGOTIATE_REQ *pSMB;
352 NEGOTIATE_RSP *pSMBr;
353 int rc = 0;
354 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000355 int i;
Steve French50c2f752007-07-13 00:33:32 +0000356 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000358 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Steve French790fe572007-07-07 19:25:05 +0000360 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 server = ses->server;
362 else {
363 rc = -EIO;
364 return rc;
365 }
366 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
367 (void **) &pSMB, (void **) &pSMBr);
368 if (rc)
369 return rc;
Steve French750d1152006-06-27 06:28:30 +0000370
371 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000372 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000373 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000374 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400375 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000376
Joe Perchesb6b38f72010-04-21 03:50:45 +0000377 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000378
Steve French1982c342005-08-17 12:38:22 -0700379 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000380 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000381
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000382 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000383 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000384 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000385 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000386 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
387 }
Steve Frenchac683922009-05-06 04:16:04 +0000388#ifdef CONFIG_CIFS_EXPERIMENTAL
389 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
390 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
391 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000392 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000393 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
394 }
395#endif
Steve French50c2f752007-07-13 00:33:32 +0000396
Steve French39798772006-05-31 22:40:51 +0000397 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000398 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000399 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
400 count += strlen(protocols[i].name) + 1;
401 /* null at end of source and target buffers anyway */
402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 pSMB->hdr.smb_buf_length += count;
404 pSMB->ByteCount = cpu_to_le16(count);
405
406 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000408 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000409 goto neg_err_exit;
410
Jeff Layton9bf67e52010-04-24 07:57:46 -0400411 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
412 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000413 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400414 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000415 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000416 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000417 could not negotiate a common dialect */
418 rc = -EOPNOTSUPP;
419 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000420#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000421 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400422 && ((server->dialect == LANMAN_PROT)
423 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000424 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000425 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000426
Steve French790fe572007-07-07 19:25:05 +0000427 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000428 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000429 server->secType = LANMAN;
430 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000431 cERROR(1, "mount failed weak security disabled"
432 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000433 rc = -EOPNOTSUPP;
434 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000435 }
Steve French254e55e2006-06-04 05:53:15 +0000436 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
437 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
438 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000439 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000440 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000441 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
442 /* even though we do not use raw we might as well set this
443 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000444 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000445 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000446 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
447 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000448 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000449 server->capabilities = CAP_MPX_MODE;
450 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000451 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000452 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000453 /* OS/2 often does not set timezone therefore
454 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000455 * Could deviate slightly from the right zone.
456 * Smallest defined timezone difference is 15 minutes
457 * (i.e. Nepal). Rounding up/down is done to match
458 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000459 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000460 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000461 struct timespec ts, utc;
462 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400463 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
464 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000465 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000466 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000467 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000468 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000469 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000470 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000472 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000473 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000474 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000475 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000477 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000478 server->timeAdj = (int)tmp;
479 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000480 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000482
Steve French39798772006-05-31 22:40:51 +0000483
Steve French254e55e2006-06-04 05:53:15 +0000484 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000485 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000486
Steve French50c2f752007-07-13 00:33:32 +0000487 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000488 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000489 memcpy(server->cryptKey, rsp->EncryptionKey,
490 CIFS_CRYPTO_KEY_SIZE);
491 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
492 rc = -EIO; /* need cryptkey unless plain text */
493 goto neg_err_exit;
494 }
Steve French39798772006-05-31 22:40:51 +0000495
Steve Frenchf19159d2010-04-21 04:12:10 +0000496 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000497 /* we will not end up setting signing flags - as no signing
498 was in LANMAN and server did not return the flags on */
499 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000500#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000501 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000502 cERROR(1, "mount failed, cifs module not built "
503 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300504 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000505#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000506 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000507 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000508 /* unknown wct */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
511 }
512 /* else wct == 17 NTLM */
513 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000514 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000515 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000516
Steve French790fe572007-07-07 19:25:05 +0000517 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000518#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000519 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000520#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000521 cERROR(1, "Server requests plain text password"
522 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000523
Steve French790fe572007-07-07 19:25:05 +0000524 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000525 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000526 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000527 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000528 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000529 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000530 else if (secFlags & CIFSSEC_MAY_KRB5)
531 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000532 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000533 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000534 else if (secFlags & CIFSSEC_MAY_LANMAN)
535 server->secType = LANMAN;
536/* #ifdef CONFIG_CIFS_EXPERIMENTAL
537 else if (secFlags & CIFSSEC_MAY_PLNTXT)
538 server->secType = ??
539#endif */
540 else {
541 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000542 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000543 goto neg_err_exit;
544 }
545 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000546
Steve French254e55e2006-06-04 05:53:15 +0000547 /* one byte, so no need to convert this or EncryptionKeyLen from
548 little endian */
549 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
550 /* probably no need to store and check maxvcs */
551 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000553 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000554 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000555 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
556 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000557 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
558 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000559 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
560 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
561 CIFS_CRYPTO_KEY_SIZE);
562 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
563 && (pSMBr->EncryptionKeyLength == 0)) {
564 /* decode security blob */
565 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
566 rc = -EIO; /* no crypt key only if plain text pwd */
567 goto neg_err_exit;
568 }
569
570 /* BB might be helpful to save off the domain of server here */
571
Steve French50c2f752007-07-13 00:33:32 +0000572 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000573 (server->capabilities & CAP_EXTENDED_SECURITY)) {
574 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000575 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000577 goto neg_err_exit;
578 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500579 read_lock(&cifs_tcp_ses_lock);
580 if (server->srv_count > 1) {
581 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000582 if (memcmp(server->server_GUID,
583 pSMBr->u.extended_response.
584 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000585 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000586 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000587 pSMBr->u.extended_response.GUID,
588 16);
589 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500590 } else {
591 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000592 memcpy(server->server_GUID,
593 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500594 }
Jeff Laytone187e442007-10-16 17:10:44 +0000595
596 if (count == 16) {
597 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000598 } else {
599 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400600 SecurityBlob, count - 16,
601 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000602 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000603 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000604 else
Steve French254e55e2006-06-04 05:53:15 +0000605 rc = -EINVAL;
Jeff Layton26efa0b2010-04-24 07:57:49 -0400606
Steve French9fbc5902010-08-20 20:42:26 +0000607 if (server->secType == Kerberos) {
608 if (!server->sec_kerberos &&
609 !server->sec_mskerberos)
610 rc = -EOPNOTSUPP;
611 } else if (server->secType == RawNTLMSSP) {
612 if (!server->sec_ntlmssp)
613 rc = -EOPNOTSUPP;
614 } else
Jeff Layton26efa0b2010-04-24 07:57:49 -0400615 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 }
Steve French254e55e2006-06-04 05:53:15 +0000617 } else
618 server->capabilities &= ~CAP_EXTENDED_SECURITY;
619
Steve French6344a422006-06-12 04:18:35 +0000620#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000621signing_check:
Steve French6344a422006-06-12 04:18:35 +0000622#endif
Steve French762e5ab2007-06-28 18:41:42 +0000623 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
624 /* MUST_SIGN already includes the MAY_SIGN FLAG
625 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000626 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000627 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000628 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000629 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000630 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000631 rc = -EOPNOTSUPP;
632 }
Steve French50c2f752007-07-13 00:33:32 +0000633 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000634 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000635 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
636 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000637 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000638 if ((server->secMode &
639 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000640 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000641 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000642 } else
643 server->secMode |= SECMODE_SIGN_REQUIRED;
644 } else {
645 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000646 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000647 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000648 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 }
Steve French50c2f752007-07-13 00:33:32 +0000650
651neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700652 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000653
Joe Perchesb6b38f72010-04-21 03:50:45 +0000654 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 return rc;
656}
657
658int
659CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
660{
661 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Joe Perchesb6b38f72010-04-21 03:50:45 +0000664 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500665
666 /* BB: do we need to check this? These should never be NULL. */
667 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
668 return -EIO;
669
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500671 * No need to return error on this operation if tid invalidated and
672 * closed on server already e.g. due to tcp session crashing. Also,
673 * the tcon is no longer on the list, so no need to take lock before
674 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 */
Steve French268875b2009-06-25 00:29:21 +0000676 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000677 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Steve French50c2f752007-07-13 00:33:32 +0000679 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700680 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 return rc;
Steve French133672e2007-11-13 22:41:37 +0000683
684 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000686 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Steve French50c2f752007-07-13 00:33:32 +0000688 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500689 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 if (rc == -EAGAIN)
691 rc = 0;
692
693 return rc;
694}
695
696int
697CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
698{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 LOGOFF_ANDX_REQ *pSMB;
700 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
Joe Perchesb6b38f72010-04-21 03:50:45 +0000702 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500703
704 /*
705 * BB: do we need to check validity of ses and server? They should
706 * always be valid since we have an active reference. If not, that
707 * should probably be a BUG()
708 */
709 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 return -EIO;
711
Steve Frenchd7b619c2010-02-25 05:36:46 +0000712 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000713 if (ses->need_reconnect)
714 goto session_already_dead; /* no need to send SMBlogoff if uid
715 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
717 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000718 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return rc;
720 }
721
Steve French3b795212008-11-13 19:45:32 +0000722 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700723
Steve French3b795212008-11-13 19:45:32 +0000724 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
726 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
728 pSMB->hdr.Uid = ses->Suid;
729
730 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000731 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000732session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000733 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
735 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000736 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 error */
738 if (rc == -EAGAIN)
739 rc = 0;
740 return rc;
741}
742
743int
Steve French2d785a52007-07-15 01:48:57 +0000744CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
745 __u16 type, const struct nls_table *nls_codepage, int remap)
746{
747 TRANSACTION2_SPI_REQ *pSMB = NULL;
748 TRANSACTION2_SPI_RSP *pSMBr = NULL;
749 struct unlink_psx_rq *pRqD;
750 int name_len;
751 int rc = 0;
752 int bytes_returned = 0;
753 __u16 params, param_offset, offset, byte_count;
754
Joe Perchesb6b38f72010-04-21 03:50:45 +0000755 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000756PsxDelete:
757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
758 (void **) &pSMBr);
759 if (rc)
760 return rc;
761
762 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
763 name_len =
764 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
765 PATH_MAX, nls_codepage, remap);
766 name_len++; /* trailing null */
767 name_len *= 2;
768 } else { /* BB add path length overrun check */
769 name_len = strnlen(fileName, PATH_MAX);
770 name_len++; /* trailing null */
771 strncpy(pSMB->FileName, fileName, name_len);
772 }
773
774 params = 6 + name_len;
775 pSMB->MaxParameterCount = cpu_to_le16(2);
776 pSMB->MaxDataCount = 0; /* BB double check this with jra */
777 pSMB->MaxSetupCount = 0;
778 pSMB->Reserved = 0;
779 pSMB->Flags = 0;
780 pSMB->Timeout = 0;
781 pSMB->Reserved2 = 0;
782 param_offset = offsetof(struct smb_com_transaction2_spi_req,
783 InformationLevel) - 4;
784 offset = param_offset + params;
785
786 /* Setup pointer to Request Data (inode type) */
787 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
788 pRqD->type = cpu_to_le16(type);
789 pSMB->ParameterOffset = cpu_to_le16(param_offset);
790 pSMB->DataOffset = cpu_to_le16(offset);
791 pSMB->SetupCount = 1;
792 pSMB->Reserved3 = 0;
793 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
794 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
795
796 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
797 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
798 pSMB->ParameterCount = cpu_to_le16(params);
799 pSMB->TotalParameterCount = pSMB->ParameterCount;
800 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
801 pSMB->Reserved4 = 0;
802 pSMB->hdr.smb_buf_length += byte_count;
803 pSMB->ByteCount = cpu_to_le16(byte_count);
804 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
805 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000806 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000807 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000808 cifs_buf_release(pSMB);
809
810 cifs_stats_inc(&tcon->num_deletes);
811
812 if (rc == -EAGAIN)
813 goto PsxDelete;
814
815 return rc;
816}
817
818int
Steve French737b7582005-04-28 22:41:06 -0700819CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
820 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821{
822 DELETE_FILE_REQ *pSMB = NULL;
823 DELETE_FILE_RSP *pSMBr = NULL;
824 int rc = 0;
825 int bytes_returned;
826 int name_len;
827
828DelFileRetry:
829 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
830 (void **) &pSMBr);
831 if (rc)
832 return rc;
833
834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
835 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000836 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700837 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 name_len++; /* trailing null */
839 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700840 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 name_len = strnlen(fileName, PATH_MAX);
842 name_len++; /* trailing null */
843 strncpy(pSMB->fileName, fileName, name_len);
844 }
845 pSMB->SearchAttributes =
846 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
847 pSMB->BufferFormat = 0x04;
848 pSMB->hdr.smb_buf_length += name_len + 1;
849 pSMB->ByteCount = cpu_to_le16(name_len + 1);
850 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
851 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700852 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000853 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000854 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
856 cifs_buf_release(pSMB);
857 if (rc == -EAGAIN)
858 goto DelFileRetry;
859
860 return rc;
861}
862
863int
Steve French50c2f752007-07-13 00:33:32 +0000864CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700865 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
867 DELETE_DIRECTORY_REQ *pSMB = NULL;
868 DELETE_DIRECTORY_RSP *pSMBr = NULL;
869 int rc = 0;
870 int bytes_returned;
871 int name_len;
872
Joe Perchesb6b38f72010-04-21 03:50:45 +0000873 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874RmDirRetry:
875 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
876 (void **) &pSMBr);
877 if (rc)
878 return rc;
879
880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700881 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
882 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 name_len++; /* trailing null */
884 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700885 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 name_len = strnlen(dirName, PATH_MAX);
887 name_len++; /* trailing null */
888 strncpy(pSMB->DirName, dirName, name_len);
889 }
890
891 pSMB->BufferFormat = 0x04;
892 pSMB->hdr.smb_buf_length += name_len + 1;
893 pSMB->ByteCount = cpu_to_le16(name_len + 1);
894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700896 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000897 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000898 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899
900 cifs_buf_release(pSMB);
901 if (rc == -EAGAIN)
902 goto RmDirRetry;
903 return rc;
904}
905
906int
907CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700908 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
910 int rc = 0;
911 CREATE_DIRECTORY_REQ *pSMB = NULL;
912 CREATE_DIRECTORY_RSP *pSMBr = NULL;
913 int bytes_returned;
914 int name_len;
915
Joe Perchesb6b38f72010-04-21 03:50:45 +0000916 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917MkDirRetry:
918 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
919 (void **) &pSMBr);
920 if (rc)
921 return rc;
922
923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000924 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700925 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 name_len++; /* trailing null */
927 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700928 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 name_len = strnlen(name, PATH_MAX);
930 name_len++; /* trailing null */
931 strncpy(pSMB->DirName, name, name_len);
932 }
933
934 pSMB->BufferFormat = 0x04;
935 pSMB->hdr.smb_buf_length += name_len + 1;
936 pSMB->ByteCount = cpu_to_le16(name_len + 1);
937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700939 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000940 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000941 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700942
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 cifs_buf_release(pSMB);
944 if (rc == -EAGAIN)
945 goto MkDirRetry;
946 return rc;
947}
948
Steve French2dd29d32007-04-23 22:07:35 +0000949int
950CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000951 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000952 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000953 const struct nls_table *nls_codepage, int remap)
954{
955 TRANSACTION2_SPI_REQ *pSMB = NULL;
956 TRANSACTION2_SPI_RSP *pSMBr = NULL;
957 int name_len;
958 int rc = 0;
959 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +0000960 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +0000961 OPEN_PSX_REQ *pdata;
962 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +0000963
Joe Perchesb6b38f72010-04-21 03:50:45 +0000964 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +0000965PsxCreat:
966 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
967 (void **) &pSMBr);
968 if (rc)
969 return rc;
970
971 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
972 name_len =
973 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
974 PATH_MAX, nls_codepage, remap);
975 name_len++; /* trailing null */
976 name_len *= 2;
977 } else { /* BB improve the check for buffer overruns BB */
978 name_len = strnlen(name, PATH_MAX);
979 name_len++; /* trailing null */
980 strncpy(pSMB->FileName, name, name_len);
981 }
982
983 params = 6 + name_len;
984 count = sizeof(OPEN_PSX_REQ);
985 pSMB->MaxParameterCount = cpu_to_le16(2);
986 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
987 pSMB->MaxSetupCount = 0;
988 pSMB->Reserved = 0;
989 pSMB->Flags = 0;
990 pSMB->Timeout = 0;
991 pSMB->Reserved2 = 0;
992 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000993 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000994 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +0000995 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000996 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +0000997 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000998 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000999 pdata->OpenFlags = cpu_to_le32(*pOplock);
1000 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1001 pSMB->DataOffset = cpu_to_le16(offset);
1002 pSMB->SetupCount = 1;
1003 pSMB->Reserved3 = 0;
1004 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1005 byte_count = 3 /* pad */ + params + count;
1006
1007 pSMB->DataCount = cpu_to_le16(count);
1008 pSMB->ParameterCount = cpu_to_le16(params);
1009 pSMB->TotalDataCount = pSMB->DataCount;
1010 pSMB->TotalParameterCount = pSMB->ParameterCount;
1011 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1012 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001013 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001014 pSMB->ByteCount = cpu_to_le16(byte_count);
1015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1017 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001018 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001019 goto psx_create_err;
1020 }
1021
Joe Perchesb6b38f72010-04-21 03:50:45 +00001022 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001023 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1024
1025 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1026 rc = -EIO; /* bad smb */
1027 goto psx_create_err;
1028 }
1029
1030 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001031 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001032 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001033
Steve French2dd29d32007-04-23 22:07:35 +00001034 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001035 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001036 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1037 /* Let caller know file was created so we can set the mode. */
1038 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001039 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001040 *pOplock |= CIFS_CREATE_ACTION;
1041 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001042 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1043 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001044 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001045 } else {
Steve French790fe572007-07-07 19:25:05 +00001046 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001047 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001048 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001049 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001050 goto psx_create_err;
1051 }
Steve French50c2f752007-07-13 00:33:32 +00001052 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001053 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001054 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001055 }
Steve French2dd29d32007-04-23 22:07:35 +00001056
1057psx_create_err:
1058 cifs_buf_release(pSMB);
1059
Steve French65bc98b2009-07-10 15:27:25 +00001060 if (posix_flags & SMB_O_DIRECTORY)
1061 cifs_stats_inc(&tcon->num_posixmkdirs);
1062 else
1063 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001064
1065 if (rc == -EAGAIN)
1066 goto PsxCreat;
1067
Steve French50c2f752007-07-13 00:33:32 +00001068 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001069}
1070
Steve Frencha9d02ad2005-08-24 23:06:05 -07001071static __u16 convert_disposition(int disposition)
1072{
1073 __u16 ofun = 0;
1074
1075 switch (disposition) {
1076 case FILE_SUPERSEDE:
1077 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1078 break;
1079 case FILE_OPEN:
1080 ofun = SMBOPEN_OAPPEND;
1081 break;
1082 case FILE_CREATE:
1083 ofun = SMBOPEN_OCREATE;
1084 break;
1085 case FILE_OPEN_IF:
1086 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1087 break;
1088 case FILE_OVERWRITE:
1089 ofun = SMBOPEN_OTRUNC;
1090 break;
1091 case FILE_OVERWRITE_IF:
1092 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1093 break;
1094 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001095 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001096 ofun = SMBOPEN_OAPPEND; /* regular open */
1097 }
1098 return ofun;
1099}
1100
Jeff Layton35fc37d2008-05-14 10:22:03 -07001101static int
1102access_flags_to_smbopen_mode(const int access_flags)
1103{
1104 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1105
1106 if (masked_flags == GENERIC_READ)
1107 return SMBOPEN_READ;
1108 else if (masked_flags == GENERIC_WRITE)
1109 return SMBOPEN_WRITE;
1110
1111 /* just go for read/write */
1112 return SMBOPEN_READWRITE;
1113}
1114
Steve Frencha9d02ad2005-08-24 23:06:05 -07001115int
1116SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1117 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001118 const int access_flags, const int create_options, __u16 *netfid,
1119 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001120 const struct nls_table *nls_codepage, int remap)
1121{
1122 int rc = -EACCES;
1123 OPENX_REQ *pSMB = NULL;
1124 OPENX_RSP *pSMBr = NULL;
1125 int bytes_returned;
1126 int name_len;
1127 __u16 count;
1128
1129OldOpenRetry:
1130 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1131 (void **) &pSMBr);
1132 if (rc)
1133 return rc;
1134
1135 pSMB->AndXCommand = 0xFF; /* none */
1136
1137 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1138 count = 1; /* account for one byte pad to word boundary */
1139 name_len =
1140 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1141 fileName, PATH_MAX, nls_codepage, remap);
1142 name_len++; /* trailing null */
1143 name_len *= 2;
1144 } else { /* BB improve check for buffer overruns BB */
1145 count = 0; /* no pad */
1146 name_len = strnlen(fileName, PATH_MAX);
1147 name_len++; /* trailing null */
1148 strncpy(pSMB->fileName, fileName, name_len);
1149 }
1150 if (*pOplock & REQ_OPLOCK)
1151 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001152 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001153 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001154
Steve Frencha9d02ad2005-08-24 23:06:05 -07001155 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001156 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001157 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1158 /* set file as system file if special file such
1159 as fifo and server expecting SFU style and
1160 no Unix extensions */
1161
Steve French790fe572007-07-07 19:25:05 +00001162 if (create_options & CREATE_OPTION_SPECIAL)
1163 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001164 else /* BB FIXME BB */
1165 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001166
Jeff Layton67750fb2008-05-09 22:28:02 +00001167 if (create_options & CREATE_OPTION_READONLY)
1168 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169
1170 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001171/* pSMB->CreateOptions = cpu_to_le32(create_options &
1172 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001174
1175 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001176 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177 count += name_len;
1178 pSMB->hdr.smb_buf_length += count;
1179
1180 pSMB->ByteCount = cpu_to_le16(count);
1181 /* long_op set to 1 to allow for oplock break timeouts */
1182 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001183 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001184 cifs_stats_inc(&tcon->num_opens);
1185 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001186 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 } else {
1188 /* BB verify if wct == 15 */
1189
Steve French582d21e2008-05-13 04:54:12 +00001190/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001191
1192 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1193 /* Let caller know file was created so we can set the mode. */
1194 /* Do we care about the CreateAction in any other cases? */
1195 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001196/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 *pOplock |= CIFS_CREATE_ACTION; */
1198 /* BB FIXME END */
1199
Steve French790fe572007-07-07 19:25:05 +00001200 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001201 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1202 pfile_info->LastAccessTime = 0; /* BB fixme */
1203 pfile_info->LastWriteTime = 0; /* BB fixme */
1204 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001205 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001206 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001208 pfile_info->AllocationSize =
1209 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1210 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001212 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 }
1214 }
1215
1216 cifs_buf_release(pSMB);
1217 if (rc == -EAGAIN)
1218 goto OldOpenRetry;
1219 return rc;
1220}
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222int
1223CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1224 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001225 const int access_flags, const int create_options, __u16 *netfid,
1226 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001227 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228{
1229 int rc = -EACCES;
1230 OPEN_REQ *pSMB = NULL;
1231 OPEN_RSP *pSMBr = NULL;
1232 int bytes_returned;
1233 int name_len;
1234 __u16 count;
1235
1236openRetry:
1237 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1238 (void **) &pSMBr);
1239 if (rc)
1240 return rc;
1241
1242 pSMB->AndXCommand = 0xFF; /* none */
1243
1244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1245 count = 1; /* account for one byte pad to word boundary */
1246 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001247 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001248 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 name_len++; /* trailing null */
1250 name_len *= 2;
1251 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001252 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 count = 0; /* no pad */
1254 name_len = strnlen(fileName, PATH_MAX);
1255 name_len++; /* trailing null */
1256 pSMB->NameLength = cpu_to_le16(name_len);
1257 strncpy(pSMB->fileName, fileName, name_len);
1258 }
1259 if (*pOplock & REQ_OPLOCK)
1260 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001261 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1264 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001265 /* set file as system file if special file such
1266 as fifo and server expecting SFU style and
1267 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001268 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001269 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1270 else
1271 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 /* XP does not handle ATTR_POSIX_SEMANTICS */
1274 /* but it helps speed up case sensitive checks for other
1275 servers such as Samba */
1276 if (tcon->ses->capabilities & CAP_UNIX)
1277 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1278
Jeff Layton67750fb2008-05-09 22:28:02 +00001279 if (create_options & CREATE_OPTION_READONLY)
1280 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1283 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001284 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001285 /* BB Expirement with various impersonation levels and verify */
1286 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 pSMB->SecurityFlags =
1288 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1289
1290 count += name_len;
1291 pSMB->hdr.smb_buf_length += count;
1292
1293 pSMB->ByteCount = cpu_to_le16(count);
1294 /* long_op set to 1 to allow for oplock break timeouts */
1295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001296 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001297 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001299 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 } else {
Steve French09d1db52005-04-28 22:41:08 -07001301 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1303 /* Let caller know file was created so we can set the mode. */
1304 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001305 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001306 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001307 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001308 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1309 36 /* CreationTime to Attributes */);
1310 /* the file_info buf is endian converted by caller */
1311 pfile_info->AllocationSize = pSMBr->AllocationSize;
1312 pfile_info->EndOfFile = pSMBr->EndOfFile;
1313 pfile_info->NumberOfLinks = cpu_to_le32(1);
1314 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 cifs_buf_release(pSMB);
1319 if (rc == -EAGAIN)
1320 goto openRetry;
1321 return rc;
1322}
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324int
Steve French50c2f752007-07-13 00:33:32 +00001325CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1326 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1327 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328{
1329 int rc = -EACCES;
1330 READ_REQ *pSMB = NULL;
1331 READ_RSP *pSMBr = NULL;
1332 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001333 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001334 int resp_buf_type = 0;
1335 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
Joe Perchesb6b38f72010-04-21 03:50:45 +00001337 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001338 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001339 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001340 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001341 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001342 if ((lseek >> 32) > 0) {
1343 /* can not handle this big offset for old */
1344 return -EIO;
1345 }
1346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001349 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (rc)
1351 return rc;
1352
1353 /* tcon and ses pointer are checked in smb_init */
1354 if (tcon->ses->server == NULL)
1355 return -ECONNABORTED;
1356
Steve Frenchec637e32005-12-12 20:53:18 -08001357 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 pSMB->Fid = netfid;
1359 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001360 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001361 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 pSMB->Remaining = 0;
1364 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1365 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001366 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001367 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1368 else {
1369 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001370 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001371 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001372 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001373 }
Steve Frenchec637e32005-12-12 20:53:18 -08001374
1375 iov[0].iov_base = (char *)pSMB;
1376 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001377 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001378 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001379 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001380 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001382 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 } else {
1384 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1385 data_length = data_length << 16;
1386 data_length += le16_to_cpu(pSMBr->DataLength);
1387 *nbytes = data_length;
1388
1389 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001390 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001392 cFYI(1, "bad length %d for count %d",
1393 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 rc = -EIO;
1395 *nbytes = 0;
1396 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001397 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001398 le16_to_cpu(pSMBr->DataOffset);
1399/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001400 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001401 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001402 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001403 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001404 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 }
1406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
Steve French4b8f9302006-02-26 16:41:18 +00001408/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001409 if (*buf) {
1410 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001411 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001412 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001413 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001414 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001415 /* return buffer to caller to free */
1416 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001417 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001418 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001419 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001420 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001421 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001422
1423 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 since file handle passed in no longer valid */
1425 return rc;
1426}
1427
Steve Frenchec637e32005-12-12 20:53:18 -08001428
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429int
1430CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1431 const int netfid, const unsigned int count,
1432 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001433 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434{
1435 int rc = -EACCES;
1436 WRITE_REQ *pSMB = NULL;
1437 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001438 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 __u32 bytes_sent;
1440 __u16 byte_count;
1441
Steve Frencha24e2d72010-04-03 17:20:21 +00001442 *nbytes = 0;
1443
Joe Perchesb6b38f72010-04-21 03:50:45 +00001444 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001445 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001446 return -ECONNABORTED;
1447
Steve French790fe572007-07-07 19:25:05 +00001448 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001449 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001450 else {
Steve French1c955182005-08-30 20:58:07 -07001451 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001452 if ((offset >> 32) > 0) {
1453 /* can not handle big offset for old srv */
1454 return -EIO;
1455 }
1456 }
Steve French1c955182005-08-30 20:58:07 -07001457
1458 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 (void **) &pSMBr);
1460 if (rc)
1461 return rc;
1462 /* tcon and ses pointer are checked in smb_init */
1463 if (tcon->ses->server == NULL)
1464 return -ECONNABORTED;
1465
1466 pSMB->AndXCommand = 0xFF; /* none */
1467 pSMB->Fid = netfid;
1468 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001469 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001470 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001471
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 pSMB->Reserved = 0xFFFFFFFF;
1473 pSMB->WriteMode = 0;
1474 pSMB->Remaining = 0;
1475
Steve French50c2f752007-07-13 00:33:32 +00001476 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 can send more if LARGE_WRITE_X capability returned by the server and if
1478 our buffer is big enough or if we convert to iovecs on socket writes
1479 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001480 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1482 } else {
1483 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1484 & ~0xFF;
1485 }
1486
1487 if (bytes_sent > count)
1488 bytes_sent = count;
1489 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001490 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001491 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001492 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001493 else if (ubuf) {
1494 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 cifs_buf_release(pSMB);
1496 return -EFAULT;
1497 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001498 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 /* No buffer */
1500 cifs_buf_release(pSMB);
1501 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001502 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001503 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001504 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001505 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001506 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001507
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1509 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001510 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001511
Steve French790fe572007-07-07 19:25:05 +00001512 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001513 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001514 else { /* old style write has byte count 4 bytes earlier
1515 so 4 bytes pad */
1516 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001517 (struct smb_com_writex_req *)pSMB;
1518 pSMBW->ByteCount = cpu_to_le16(byte_count);
1519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520
1521 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1522 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001523 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001525 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 } else {
1527 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1528 *nbytes = (*nbytes) << 16;
1529 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301530
1531 /*
1532 * Mask off high 16 bits when bytes written as returned by the
1533 * server is greater than bytes requested by the client. Some
1534 * OS/2 servers are known to set incorrect CountHigh values.
1535 */
1536 if (*nbytes > count)
1537 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 }
1539
1540 cifs_buf_release(pSMB);
1541
Steve French50c2f752007-07-13 00:33:32 +00001542 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 since file handle passed in no longer valid */
1544
1545 return rc;
1546}
1547
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001548int
1549CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001551 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1552 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553{
1554 int rc = -EACCES;
1555 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001556 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001557 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001558 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001560 *nbytes = 0;
1561
Joe Perchesb6b38f72010-04-21 03:50:45 +00001562 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001563
Steve French4c3130e2008-12-09 00:28:16 +00001564 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001565 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001566 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001567 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001568 if ((offset >> 32) > 0) {
1569 /* can not handle big offset for old srv */
1570 return -EIO;
1571 }
1572 }
Steve French8cc64c62005-10-03 13:49:43 -07001573 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 if (rc)
1575 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 /* tcon and ses pointer are checked in smb_init */
1577 if (tcon->ses->server == NULL)
1578 return -ECONNABORTED;
1579
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001580 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 pSMB->Fid = netfid;
1582 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001583 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001584 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 pSMB->Reserved = 0xFFFFFFFF;
1586 pSMB->WriteMode = 0;
1587 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001588
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001590 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591
Steve French3e844692005-10-03 13:37:24 -07001592 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1593 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001594 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001595 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001596 pSMB->hdr.smb_buf_length += count+1;
1597 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001598 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1599 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001600 pSMB->ByteCount = cpu_to_le16(count + 1);
1601 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001602 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001603 (struct smb_com_writex_req *)pSMB;
1604 pSMBW->ByteCount = cpu_to_le16(count + 5);
1605 }
Steve French3e844692005-10-03 13:37:24 -07001606 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001607 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001608 iov[0].iov_len = smb_hdr_len + 4;
1609 else /* wct == 12 pad bigger by four bytes */
1610 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001611
Steve French3e844692005-10-03 13:37:24 -07001612
Steve Frenchec637e32005-12-12 20:53:18 -08001613 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001614 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001615 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001617 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001618 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001619 /* presumably this can not happen, but best to be safe */
1620 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001621 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001622 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001623 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1624 *nbytes = (*nbytes) << 16;
1625 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301626
1627 /*
1628 * Mask off high 16 bits when bytes written as returned by the
1629 * server is greater than bytes requested by the client. OS/2
1630 * servers are known to set incorrect CountHigh values.
1631 */
1632 if (*nbytes > count)
1633 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635
Steve French4b8f9302006-02-26 16:41:18 +00001636/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001637 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001638 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001639 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001640 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Steve French50c2f752007-07-13 00:33:32 +00001642 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 since file handle passed in no longer valid */
1644
1645 return rc;
1646}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001647
1648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649int
1650CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1651 const __u16 smb_file_id, const __u64 len,
1652 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001653 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654{
1655 int rc = 0;
1656 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001657/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 int bytes_returned;
1659 int timeout = 0;
1660 __u16 count;
1661
Joe Perchesb6b38f72010-04-21 03:50:45 +00001662 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001663 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1664
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 if (rc)
1666 return rc;
1667
Steve French790fe572007-07-07 19:25:05 +00001668 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001669 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001671 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001672 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1674 } else {
1675 pSMB->Timeout = 0;
1676 }
1677
1678 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1679 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1680 pSMB->LockType = lockType;
1681 pSMB->AndXCommand = 0xFF; /* none */
1682 pSMB->Fid = smb_file_id; /* netfid stays le */
1683
Steve French790fe572007-07-07 19:25:05 +00001684 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1686 /* BB where to store pid high? */
1687 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1688 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1689 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1690 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1691 count = sizeof(LOCKING_ANDX_RANGE);
1692 } else {
1693 /* oplock break */
1694 count = 0;
1695 }
1696 pSMB->hdr.smb_buf_length += count;
1697 pSMB->ByteCount = cpu_to_le16(count);
1698
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001699 if (waitFlag) {
1700 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001701 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001702 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001703 } else {
Steve French133672e2007-11-13 22:41:37 +00001704 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1705 timeout);
1706 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001707 }
Steve Frencha4544342005-08-24 13:59:35 -07001708 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001709 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001710 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711
Steve French50c2f752007-07-13 00:33:32 +00001712 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 since file handle passed in no longer valid */
1714 return rc;
1715}
1716
1717int
Steve French08547b02006-02-28 22:39:25 +00001718CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1719 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001720 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001721 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001722{
1723 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1724 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001725 struct cifs_posix_lock *parm_data;
1726 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001727 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001728 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001729 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001730 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001731 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001732
Joe Perchesb6b38f72010-04-21 03:50:45 +00001733 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001734
Steve French790fe572007-07-07 19:25:05 +00001735 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001736 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001737
Steve French08547b02006-02-28 22:39:25 +00001738 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1739
1740 if (rc)
1741 return rc;
1742
1743 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1744
Steve French50c2f752007-07-13 00:33:32 +00001745 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001746 pSMB->MaxSetupCount = 0;
1747 pSMB->Reserved = 0;
1748 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001749 pSMB->Reserved2 = 0;
1750 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1751 offset = param_offset + params;
1752
Steve French08547b02006-02-28 22:39:25 +00001753 count = sizeof(struct cifs_posix_lock);
1754 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001755 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001756 pSMB->SetupCount = 1;
1757 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001758 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001759 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1760 else
1761 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1762 byte_count = 3 /* pad */ + params + count;
1763 pSMB->DataCount = cpu_to_le16(count);
1764 pSMB->ParameterCount = cpu_to_le16(params);
1765 pSMB->TotalDataCount = pSMB->DataCount;
1766 pSMB->TotalParameterCount = pSMB->ParameterCount;
1767 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001768 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001769 (((char *) &pSMB->hdr.Protocol) + offset);
1770
1771 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001772 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001773 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001774 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001775 pSMB->Timeout = cpu_to_le32(-1);
1776 } else
1777 pSMB->Timeout = 0;
1778
Steve French08547b02006-02-28 22:39:25 +00001779 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001780 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001781 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001782
1783 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001784 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001785 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1786 pSMB->Reserved4 = 0;
1787 pSMB->hdr.smb_buf_length += byte_count;
1788 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001789 if (waitFlag) {
1790 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1791 (struct smb_hdr *) pSMBr, &bytes_returned);
1792 } else {
Steve French133672e2007-11-13 22:41:37 +00001793 iov[0].iov_base = (char *)pSMB;
1794 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1795 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1796 &resp_buf_type, timeout);
1797 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1798 not try to free it twice below on exit */
1799 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001800 }
1801
Steve French08547b02006-02-28 22:39:25 +00001802 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001803 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001804 } else if (get_flag) {
1805 /* lock structure can be returned on get */
1806 __u16 data_offset;
1807 __u16 data_count;
1808 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001809
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001810 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1811 rc = -EIO; /* bad smb */
1812 goto plk_err_exit;
1813 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001814 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1815 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001816 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001817 rc = -EIO;
1818 goto plk_err_exit;
1819 }
1820 parm_data = (struct cifs_posix_lock *)
1821 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001822 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001823 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001824 else {
1825 if (parm_data->lock_type ==
1826 __constant_cpu_to_le16(CIFS_RDLCK))
1827 pLockData->fl_type = F_RDLCK;
1828 else if (parm_data->lock_type ==
1829 __constant_cpu_to_le16(CIFS_WRLCK))
1830 pLockData->fl_type = F_WRLCK;
1831
1832 pLockData->fl_start = parm_data->start;
1833 pLockData->fl_end = parm_data->start +
1834 parm_data->length - 1;
1835 pLockData->fl_pid = parm_data->pid;
1836 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001837 }
Steve French50c2f752007-07-13 00:33:32 +00001838
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001839plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001840 if (pSMB)
1841 cifs_small_buf_release(pSMB);
1842
Steve French133672e2007-11-13 22:41:37 +00001843 if (resp_buf_type == CIFS_SMALL_BUFFER)
1844 cifs_small_buf_release(iov[0].iov_base);
1845 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1846 cifs_buf_release(iov[0].iov_base);
1847
Steve French08547b02006-02-28 22:39:25 +00001848 /* Note: On -EAGAIN error only caller can retry on handle based calls
1849 since file handle passed in no longer valid */
1850
1851 return rc;
1852}
1853
1854
1855int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1857{
1858 int rc = 0;
1859 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001860 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861
1862/* do not retry on dead session on close */
1863 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001864 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 return 0;
1866 if (rc)
1867 return rc;
1868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001870 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001872 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001873 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001875 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001877 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 }
1879 }
1880
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001882 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 rc = 0;
1884
1885 return rc;
1886}
1887
1888int
Steve Frenchb298f222009-02-21 21:17:43 +00001889CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1890{
1891 int rc = 0;
1892 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001893 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001894
1895 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1896 if (rc)
1897 return rc;
1898
1899 pSMB->FileID = (__u16) smb_file_id;
1900 pSMB->ByteCount = 0;
1901 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1902 cifs_stats_inc(&tcon->num_flushes);
1903 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001904 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001905
1906 return rc;
1907}
1908
1909int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1911 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001912 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913{
1914 int rc = 0;
1915 RENAME_REQ *pSMB = NULL;
1916 RENAME_RSP *pSMBr = NULL;
1917 int bytes_returned;
1918 int name_len, name_len2;
1919 __u16 count;
1920
Joe Perchesb6b38f72010-04-21 03:50:45 +00001921 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922renameRetry:
1923 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1924 (void **) &pSMBr);
1925 if (rc)
1926 return rc;
1927
1928 pSMB->BufferFormat = 0x04;
1929 pSMB->SearchAttributes =
1930 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1931 ATTR_DIRECTORY);
1932
1933 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1934 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001935 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001936 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 name_len++; /* trailing null */
1938 name_len *= 2;
1939 pSMB->OldFileName[name_len] = 0x04; /* pad */
1940 /* protocol requires ASCII signature byte on Unicode string */
1941 pSMB->OldFileName[name_len + 1] = 0x00;
1942 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001943 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001944 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1946 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001947 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 name_len = strnlen(fromName, PATH_MAX);
1949 name_len++; /* trailing null */
1950 strncpy(pSMB->OldFileName, fromName, name_len);
1951 name_len2 = strnlen(toName, PATH_MAX);
1952 name_len2++; /* trailing null */
1953 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1954 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1955 name_len2++; /* trailing null */
1956 name_len2++; /* signature byte */
1957 }
1958
1959 count = 1 /* 1st signature byte */ + name_len + name_len2;
1960 pSMB->hdr.smb_buf_length += count;
1961 pSMB->ByteCount = cpu_to_le16(count);
1962
1963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001965 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001966 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001967 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969 cifs_buf_release(pSMB);
1970
1971 if (rc == -EAGAIN)
1972 goto renameRetry;
1973
1974 return rc;
1975}
1976
Steve French50c2f752007-07-13 00:33:32 +00001977int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001978 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001979 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980{
1981 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1982 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001983 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 char *data_offset;
1985 char dummy_string[30];
1986 int rc = 0;
1987 int bytes_returned = 0;
1988 int len_of_str;
1989 __u16 params, param_offset, offset, count, byte_count;
1990
Joe Perchesb6b38f72010-04-21 03:50:45 +00001991 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1993 (void **) &pSMBr);
1994 if (rc)
1995 return rc;
1996
1997 params = 6;
1998 pSMB->MaxSetupCount = 0;
1999 pSMB->Reserved = 0;
2000 pSMB->Flags = 0;
2001 pSMB->Timeout = 0;
2002 pSMB->Reserved2 = 0;
2003 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2004 offset = param_offset + params;
2005
2006 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2007 rename_info = (struct set_file_rename *) data_offset;
2008 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002009 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 pSMB->SetupCount = 1;
2011 pSMB->Reserved3 = 0;
2012 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2013 byte_count = 3 /* pad */ + params;
2014 pSMB->ParameterCount = cpu_to_le16(params);
2015 pSMB->TotalParameterCount = pSMB->ParameterCount;
2016 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2017 pSMB->DataOffset = cpu_to_le16(offset);
2018 /* construct random name ".cifs_tmp<inodenum><mid>" */
2019 rename_info->overwrite = cpu_to_le32(1);
2020 rename_info->root_fid = 0;
2021 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002022 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002023 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2024 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002025 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002027 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002028 target_name, PATH_MAX, nls_codepage,
2029 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 }
2031 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002032 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 byte_count += count;
2034 pSMB->DataCount = cpu_to_le16(count);
2035 pSMB->TotalDataCount = pSMB->DataCount;
2036 pSMB->Fid = netfid;
2037 pSMB->InformationLevel =
2038 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2039 pSMB->Reserved4 = 0;
2040 pSMB->hdr.smb_buf_length += byte_count;
2041 pSMB->ByteCount = cpu_to_le16(byte_count);
2042 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002043 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002044 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002045 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002046 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 cifs_buf_release(pSMB);
2049
2050 /* Note: On -EAGAIN error only caller can retry on handle based calls
2051 since file handle passed in no longer valid */
2052
2053 return rc;
2054}
2055
2056int
Steve French50c2f752007-07-13 00:33:32 +00002057CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2058 const __u16 target_tid, const char *toName, const int flags,
2059 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060{
2061 int rc = 0;
2062 COPY_REQ *pSMB = NULL;
2063 COPY_RSP *pSMBr = NULL;
2064 int bytes_returned;
2065 int name_len, name_len2;
2066 __u16 count;
2067
Joe Perchesb6b38f72010-04-21 03:50:45 +00002068 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069copyRetry:
2070 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2071 (void **) &pSMBr);
2072 if (rc)
2073 return rc;
2074
2075 pSMB->BufferFormat = 0x04;
2076 pSMB->Tid2 = target_tid;
2077
2078 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2079
2080 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002081 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002082 fromName, PATH_MAX, nls_codepage,
2083 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 name_len++; /* trailing null */
2085 name_len *= 2;
2086 pSMB->OldFileName[name_len] = 0x04; /* pad */
2087 /* protocol requires ASCII signature byte on Unicode string */
2088 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002089 name_len2 =
2090 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002091 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2093 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002094 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 name_len = strnlen(fromName, PATH_MAX);
2096 name_len++; /* trailing null */
2097 strncpy(pSMB->OldFileName, fromName, name_len);
2098 name_len2 = strnlen(toName, PATH_MAX);
2099 name_len2++; /* trailing null */
2100 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2101 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2102 name_len2++; /* trailing null */
2103 name_len2++; /* signature byte */
2104 }
2105
2106 count = 1 /* 1st signature byte */ + name_len + name_len2;
2107 pSMB->hdr.smb_buf_length += count;
2108 pSMB->ByteCount = cpu_to_le16(count);
2109
2110 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2111 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2112 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002113 cFYI(1, "Send error in copy = %d with %d files copied",
2114 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 }
Steve French0d817bc2008-05-22 02:02:03 +00002116 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
2118 if (rc == -EAGAIN)
2119 goto copyRetry;
2120
2121 return rc;
2122}
2123
2124int
2125CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2126 const char *fromName, const char *toName,
2127 const struct nls_table *nls_codepage)
2128{
2129 TRANSACTION2_SPI_REQ *pSMB = NULL;
2130 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2131 char *data_offset;
2132 int name_len;
2133 int name_len_target;
2134 int rc = 0;
2135 int bytes_returned = 0;
2136 __u16 params, param_offset, offset, byte_count;
2137
Joe Perchesb6b38f72010-04-21 03:50:45 +00002138 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139createSymLinkRetry:
2140 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2141 (void **) &pSMBr);
2142 if (rc)
2143 return rc;
2144
2145 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2146 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002147 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148 /* find define for this maxpathcomponent */
2149 , nls_codepage);
2150 name_len++; /* trailing null */
2151 name_len *= 2;
2152
Steve French50c2f752007-07-13 00:33:32 +00002153 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154 name_len = strnlen(fromName, PATH_MAX);
2155 name_len++; /* trailing null */
2156 strncpy(pSMB->FileName, fromName, name_len);
2157 }
2158 params = 6 + name_len;
2159 pSMB->MaxSetupCount = 0;
2160 pSMB->Reserved = 0;
2161 pSMB->Flags = 0;
2162 pSMB->Timeout = 0;
2163 pSMB->Reserved2 = 0;
2164 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002165 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 offset = param_offset + params;
2167
2168 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2169 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2170 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002171 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 /* find define for this maxpathcomponent */
2173 , nls_codepage);
2174 name_len_target++; /* trailing null */
2175 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002176 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 name_len_target = strnlen(toName, PATH_MAX);
2178 name_len_target++; /* trailing null */
2179 strncpy(data_offset, toName, name_len_target);
2180 }
2181
2182 pSMB->MaxParameterCount = cpu_to_le16(2);
2183 /* BB find exact max on data count below from sess */
2184 pSMB->MaxDataCount = cpu_to_le16(1000);
2185 pSMB->SetupCount = 1;
2186 pSMB->Reserved3 = 0;
2187 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2188 byte_count = 3 /* pad */ + params + name_len_target;
2189 pSMB->DataCount = cpu_to_le16(name_len_target);
2190 pSMB->ParameterCount = cpu_to_le16(params);
2191 pSMB->TotalDataCount = pSMB->DataCount;
2192 pSMB->TotalParameterCount = pSMB->ParameterCount;
2193 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2194 pSMB->DataOffset = cpu_to_le16(offset);
2195 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2196 pSMB->Reserved4 = 0;
2197 pSMB->hdr.smb_buf_length += byte_count;
2198 pSMB->ByteCount = cpu_to_le16(byte_count);
2199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002201 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002202 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002203 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204
Steve French0d817bc2008-05-22 02:02:03 +00002205 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
2207 if (rc == -EAGAIN)
2208 goto createSymLinkRetry;
2209
2210 return rc;
2211}
2212
2213int
2214CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2215 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002216 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
2218 TRANSACTION2_SPI_REQ *pSMB = NULL;
2219 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2220 char *data_offset;
2221 int name_len;
2222 int name_len_target;
2223 int rc = 0;
2224 int bytes_returned = 0;
2225 __u16 params, param_offset, offset, byte_count;
2226
Joe Perchesb6b38f72010-04-21 03:50:45 +00002227 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228createHardLinkRetry:
2229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2230 (void **) &pSMBr);
2231 if (rc)
2232 return rc;
2233
2234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002235 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002236 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237 name_len++; /* trailing null */
2238 name_len *= 2;
2239
Steve French50c2f752007-07-13 00:33:32 +00002240 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 name_len = strnlen(toName, PATH_MAX);
2242 name_len++; /* trailing null */
2243 strncpy(pSMB->FileName, toName, name_len);
2244 }
2245 params = 6 + name_len;
2246 pSMB->MaxSetupCount = 0;
2247 pSMB->Reserved = 0;
2248 pSMB->Flags = 0;
2249 pSMB->Timeout = 0;
2250 pSMB->Reserved2 = 0;
2251 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002252 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 offset = param_offset + params;
2254
2255 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2256 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2257 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002258 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002259 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 name_len_target++; /* trailing null */
2261 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002262 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 name_len_target = strnlen(fromName, PATH_MAX);
2264 name_len_target++; /* trailing null */
2265 strncpy(data_offset, fromName, name_len_target);
2266 }
2267
2268 pSMB->MaxParameterCount = cpu_to_le16(2);
2269 /* BB find exact max on data count below from sess*/
2270 pSMB->MaxDataCount = cpu_to_le16(1000);
2271 pSMB->SetupCount = 1;
2272 pSMB->Reserved3 = 0;
2273 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2274 byte_count = 3 /* pad */ + params + name_len_target;
2275 pSMB->ParameterCount = cpu_to_le16(params);
2276 pSMB->TotalParameterCount = pSMB->ParameterCount;
2277 pSMB->DataCount = cpu_to_le16(name_len_target);
2278 pSMB->TotalDataCount = pSMB->DataCount;
2279 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2280 pSMB->DataOffset = cpu_to_le16(offset);
2281 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2282 pSMB->Reserved4 = 0;
2283 pSMB->hdr.smb_buf_length += byte_count;
2284 pSMB->ByteCount = cpu_to_le16(byte_count);
2285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2286 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002287 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002288 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002289 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290
2291 cifs_buf_release(pSMB);
2292 if (rc == -EAGAIN)
2293 goto createHardLinkRetry;
2294
2295 return rc;
2296}
2297
2298int
2299CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2300 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002301 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302{
2303 int rc = 0;
2304 NT_RENAME_REQ *pSMB = NULL;
2305 RENAME_RSP *pSMBr = NULL;
2306 int bytes_returned;
2307 int name_len, name_len2;
2308 __u16 count;
2309
Joe Perchesb6b38f72010-04-21 03:50:45 +00002310 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311winCreateHardLinkRetry:
2312
2313 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2314 (void **) &pSMBr);
2315 if (rc)
2316 return rc;
2317
2318 pSMB->SearchAttributes =
2319 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2320 ATTR_DIRECTORY);
2321 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2322 pSMB->ClusterCount = 0;
2323
2324 pSMB->BufferFormat = 0x04;
2325
2326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2327 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002328 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002329 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 name_len++; /* trailing null */
2331 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002332
2333 /* protocol specifies ASCII buffer format (0x04) for unicode */
2334 pSMB->OldFileName[name_len] = 0x04;
2335 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002337 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002338 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2340 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002341 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 name_len = strnlen(fromName, PATH_MAX);
2343 name_len++; /* trailing null */
2344 strncpy(pSMB->OldFileName, fromName, name_len);
2345 name_len2 = strnlen(toName, PATH_MAX);
2346 name_len2++; /* trailing null */
2347 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2348 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2349 name_len2++; /* trailing null */
2350 name_len2++; /* signature byte */
2351 }
2352
2353 count = 1 /* string type byte */ + name_len + name_len2;
2354 pSMB->hdr.smb_buf_length += count;
2355 pSMB->ByteCount = cpu_to_le16(count);
2356
2357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002359 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002360 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002361 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002362
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 cifs_buf_release(pSMB);
2364 if (rc == -EAGAIN)
2365 goto winCreateHardLinkRetry;
2366
2367 return rc;
2368}
2369
2370int
2371CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002372 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 const struct nls_table *nls_codepage)
2374{
2375/* SMB_QUERY_FILE_UNIX_LINK */
2376 TRANSACTION2_QPI_REQ *pSMB = NULL;
2377 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2378 int rc = 0;
2379 int bytes_returned;
2380 int name_len;
2381 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002382 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
Joe Perchesb6b38f72010-04-21 03:50:45 +00002384 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385
2386querySymLinkRetry:
2387 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2388 (void **) &pSMBr);
2389 if (rc)
2390 return rc;
2391
2392 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2393 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002394 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2395 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 name_len++; /* trailing null */
2397 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002398 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 name_len = strnlen(searchName, PATH_MAX);
2400 name_len++; /* trailing null */
2401 strncpy(pSMB->FileName, searchName, name_len);
2402 }
2403
2404 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2405 pSMB->TotalDataCount = 0;
2406 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002407 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 pSMB->MaxSetupCount = 0;
2409 pSMB->Reserved = 0;
2410 pSMB->Flags = 0;
2411 pSMB->Timeout = 0;
2412 pSMB->Reserved2 = 0;
2413 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002414 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 pSMB->DataCount = 0;
2416 pSMB->DataOffset = 0;
2417 pSMB->SetupCount = 1;
2418 pSMB->Reserved3 = 0;
2419 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2420 byte_count = params + 1 /* pad */ ;
2421 pSMB->TotalParameterCount = cpu_to_le16(params);
2422 pSMB->ParameterCount = pSMB->TotalParameterCount;
2423 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2424 pSMB->Reserved4 = 0;
2425 pSMB->hdr.smb_buf_length += byte_count;
2426 pSMB->ByteCount = cpu_to_le16(byte_count);
2427
2428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2430 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002431 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 } else {
2433 /* decode response */
2434
2435 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002437 if (rc || (pSMBr->ByteCount < 2))
2438 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002440 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002441 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442
Jeff Layton460b9692009-04-30 07:17:56 -04002443 data_start = ((char *) &pSMBr->hdr.Protocol) +
2444 le16_to_cpu(pSMBr->t2.DataOffset);
2445
Steve French0e0d2cf2009-05-01 05:27:32 +00002446 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2447 is_unicode = true;
2448 else
2449 is_unicode = false;
2450
Steve French737b7582005-04-28 22:41:06 -07002451 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002452 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002453 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002454 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002455 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 }
2457 }
2458 cifs_buf_release(pSMB);
2459 if (rc == -EAGAIN)
2460 goto querySymLinkRetry;
2461 return rc;
2462}
2463
Parag Warudkarc9489772007-10-23 18:09:48 +00002464#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002465/* Initialize NT TRANSACT SMB into small smb request buffer.
2466 This assumes that all NT TRANSACTS that we init here have
2467 total parm and data under about 400 bytes (to fit in small cifs
2468 buffer size), which is the case so far, it easily fits. NB:
2469 Setup words themselves and ByteCount
2470 MaxSetupCount (size of returned setup area) and
2471 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002472static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002473smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002474 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002475 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002476{
2477 int rc;
2478 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002479 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002480
2481 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2482 (void **)&pSMB);
2483 if (rc)
2484 return rc;
2485 *ret_buf = (void *)pSMB;
2486 pSMB->Reserved = 0;
2487 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2488 pSMB->TotalDataCount = 0;
2489 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2490 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2491 pSMB->ParameterCount = pSMB->TotalParameterCount;
2492 pSMB->DataCount = pSMB->TotalDataCount;
2493 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2494 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2495 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2496 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2497 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2498 pSMB->SubCommand = cpu_to_le16(sub_command);
2499 return 0;
2500}
2501
2502static int
Steve French50c2f752007-07-13 00:33:32 +00002503validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002504 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002505{
Steve French50c2f752007-07-13 00:33:32 +00002506 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002507 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002508 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002509
Steve French630f3f0c2007-10-25 21:17:17 +00002510 *pdatalen = 0;
2511 *pparmlen = 0;
2512
Steve French790fe572007-07-07 19:25:05 +00002513 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002514 return -EINVAL;
2515
2516 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2517
2518 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002519 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002520 (char *)&pSMBr->ByteCount;
2521
Steve French0a4b92c2006-01-12 15:44:21 -08002522 data_offset = le32_to_cpu(pSMBr->DataOffset);
2523 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002524 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002525 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2526
2527 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2528 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2529
2530 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002531 if (*ppparm > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002532 cFYI(1, "parms start after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002533 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002534 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002535 cFYI(1, "parm end after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002536 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002537 } else if (*ppdata > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002538 cFYI(1, "data starts after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002539 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002540 } else if (data_count + *ppdata > end_of_smb) {
Steve Frenchf19159d2010-04-21 04:12:10 +00002541 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002542 *ppdata, data_count, (data_count + *ppdata),
Joe Perchesb6b38f72010-04-21 03:50:45 +00002543 end_of_smb, pSMBr);
Steve French0a4b92c2006-01-12 15:44:21 -08002544 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002545 } else if (parm_count + data_count > pSMBr->ByteCount) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002546 cFYI(1, "parm count and data count larger than SMB");
Steve French0a4b92c2006-01-12 15:44:21 -08002547 return -EINVAL;
2548 }
Steve French630f3f0c2007-10-25 21:17:17 +00002549 *pdatalen = data_count;
2550 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002551 return 0;
2552}
2553
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554int
2555CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2556 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002557 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 const struct nls_table *nls_codepage)
2559{
2560 int rc = 0;
2561 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002562 struct smb_com_transaction_ioctl_req *pSMB;
2563 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
Joe Perchesb6b38f72010-04-21 03:50:45 +00002565 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2567 (void **) &pSMBr);
2568 if (rc)
2569 return rc;
2570
2571 pSMB->TotalParameterCount = 0 ;
2572 pSMB->TotalDataCount = 0;
2573 pSMB->MaxParameterCount = cpu_to_le32(2);
2574 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002575 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2576 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 pSMB->MaxSetupCount = 4;
2578 pSMB->Reserved = 0;
2579 pSMB->ParameterOffset = 0;
2580 pSMB->DataCount = 0;
2581 pSMB->DataOffset = 0;
2582 pSMB->SetupCount = 4;
2583 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2584 pSMB->ParameterCount = pSMB->TotalParameterCount;
2585 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2586 pSMB->IsFsctl = 1; /* FSCTL */
2587 pSMB->IsRootFlag = 0;
2588 pSMB->Fid = fid; /* file handle always le */
2589 pSMB->ByteCount = 0;
2590
2591 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2592 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2593 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002594 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595 } else { /* decode response */
2596 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2597 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002598 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 /* BB also check enough total bytes returned */
2600 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002601 goto qreparse_out;
2602 }
2603 if (data_count && (data_count < 2048)) {
2604 char *end_of_smb = 2 /* sizeof byte count */ +
2605 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
Steve Frenchafe48c32009-05-02 05:25:46 +00002607 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002608 (struct reparse_data *)
2609 ((char *)&pSMBr->hdr.Protocol
2610 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002611 if ((char *)reparse_buf >= end_of_smb) {
2612 rc = -EIO;
2613 goto qreparse_out;
2614 }
2615 if ((reparse_buf->LinkNamesBuf +
2616 reparse_buf->TargetNameOffset +
2617 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002618 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002619 rc = -EIO;
2620 goto qreparse_out;
2621 }
Steve French50c2f752007-07-13 00:33:32 +00002622
Steve Frenchafe48c32009-05-02 05:25:46 +00002623 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2624 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002625 (reparse_buf->LinkNamesBuf +
2626 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002627 buflen,
2628 reparse_buf->TargetNameLen,
2629 nls_codepage, 0);
2630 } else { /* ASCII names */
2631 strncpy(symlinkinfo,
2632 reparse_buf->LinkNamesBuf +
2633 reparse_buf->TargetNameOffset,
2634 min_t(const int, buflen,
2635 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002637 } else {
2638 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002639 cFYI(1, "Invalid return data count on "
2640 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002642 symlinkinfo[buflen] = 0; /* just in case so the caller
2643 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002644 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 }
Steve French989c7e52009-05-02 05:32:20 +00002646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002648 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 /* Note: On -EAGAIN error only caller can retry on handle based calls
2651 since file handle passed in no longer valid */
2652
2653 return rc;
2654}
Steve Frenchafe48c32009-05-02 05:25:46 +00002655#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
2657#ifdef CONFIG_CIFS_POSIX
2658
2659/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002660static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2661 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662{
2663 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002664 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2665 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2666 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002667 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
2669 return;
2670}
2671
2672/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002673static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2674 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675{
2676 int size = 0;
2677 int i;
2678 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002679 struct cifs_posix_ace *pACE;
2680 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2681 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682
2683 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2684 return -EOPNOTSUPP;
2685
Steve French790fe572007-07-07 19:25:05 +00002686 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 count = le16_to_cpu(cifs_acl->access_entry_count);
2688 pACE = &cifs_acl->ace_array[0];
2689 size = sizeof(struct cifs_posix_acl);
2690 size += sizeof(struct cifs_posix_ace) * count;
2691 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002692 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002693 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2694 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 return -EINVAL;
2696 }
Steve French790fe572007-07-07 19:25:05 +00002697 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 count = le16_to_cpu(cifs_acl->access_entry_count);
2699 size = sizeof(struct cifs_posix_acl);
2700 size += sizeof(struct cifs_posix_ace) * count;
2701/* skip past access ACEs to get to default ACEs */
2702 pACE = &cifs_acl->ace_array[count];
2703 count = le16_to_cpu(cifs_acl->default_entry_count);
2704 size += sizeof(struct cifs_posix_ace) * count;
2705 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002706 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 return -EINVAL;
2708 } else {
2709 /* illegal type */
2710 return -EINVAL;
2711 }
2712
2713 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002714 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002715 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002716 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return -ERANGE;
2718 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002719 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002720 for (i = 0; i < count ; i++) {
2721 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2722 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 }
2724 }
2725 return size;
2726}
2727
Steve French50c2f752007-07-13 00:33:32 +00002728static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2729 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730{
2731 __u16 rc = 0; /* 0 = ACL converted ok */
2732
Steve Frenchff7feac2005-11-15 16:45:16 -08002733 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2734 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002736 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 /* Probably no need to le convert -1 on any arch but can not hurt */
2738 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002739 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002740 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002741 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 return rc;
2743}
2744
2745/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002746static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2747 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748{
2749 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002750 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2751 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 int count;
2753 int i;
2754
Steve French790fe572007-07-07 19:25:05 +00002755 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 return 0;
2757
2758 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002759 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002760 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002761 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002762 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002763 cFYI(1, "unknown POSIX ACL version %d",
2764 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 return 0;
2766 }
2767 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002768 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002769 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002770 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002771 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002773 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return 0;
2775 }
Steve French50c2f752007-07-13 00:33:32 +00002776 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2778 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002779 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 /* ACE not converted */
2781 break;
2782 }
2783 }
Steve French790fe572007-07-07 19:25:05 +00002784 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2786 rc += sizeof(struct cifs_posix_acl);
2787 /* BB add check to make sure ACL does not overflow SMB */
2788 }
2789 return rc;
2790}
2791
2792int
2793CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002794 const unsigned char *searchName,
2795 char *acl_inf, const int buflen, const int acl_type,
2796 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797{
2798/* SMB_QUERY_POSIX_ACL */
2799 TRANSACTION2_QPI_REQ *pSMB = NULL;
2800 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2801 int rc = 0;
2802 int bytes_returned;
2803 int name_len;
2804 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002805
Joe Perchesb6b38f72010-04-21 03:50:45 +00002806 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808queryAclRetry:
2809 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2810 (void **) &pSMBr);
2811 if (rc)
2812 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002813
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2815 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002816 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002817 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 name_len++; /* trailing null */
2819 name_len *= 2;
2820 pSMB->FileName[name_len] = 0;
2821 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002822 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 name_len = strnlen(searchName, PATH_MAX);
2824 name_len++; /* trailing null */
2825 strncpy(pSMB->FileName, searchName, name_len);
2826 }
2827
2828 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2829 pSMB->TotalDataCount = 0;
2830 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002831 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 pSMB->MaxDataCount = cpu_to_le16(4000);
2833 pSMB->MaxSetupCount = 0;
2834 pSMB->Reserved = 0;
2835 pSMB->Flags = 0;
2836 pSMB->Timeout = 0;
2837 pSMB->Reserved2 = 0;
2838 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002839 offsetof(struct smb_com_transaction2_qpi_req,
2840 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 pSMB->DataCount = 0;
2842 pSMB->DataOffset = 0;
2843 pSMB->SetupCount = 1;
2844 pSMB->Reserved3 = 0;
2845 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2846 byte_count = params + 1 /* pad */ ;
2847 pSMB->TotalParameterCount = cpu_to_le16(params);
2848 pSMB->ParameterCount = pSMB->TotalParameterCount;
2849 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2850 pSMB->Reserved4 = 0;
2851 pSMB->hdr.smb_buf_length += byte_count;
2852 pSMB->ByteCount = cpu_to_le16(byte_count);
2853
2854 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2855 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002856 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002858 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 } else {
2860 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002861
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2863 if (rc || (pSMBr->ByteCount < 2))
2864 /* BB also check enough total bytes returned */
2865 rc = -EIO; /* bad smb */
2866 else {
2867 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2868 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2869 rc = cifs_copy_posix_acl(acl_inf,
2870 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002871 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 }
2873 }
2874 cifs_buf_release(pSMB);
2875 if (rc == -EAGAIN)
2876 goto queryAclRetry;
2877 return rc;
2878}
2879
2880int
2881CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002882 const unsigned char *fileName,
2883 const char *local_acl, const int buflen,
2884 const int acl_type,
2885 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886{
2887 struct smb_com_transaction2_spi_req *pSMB = NULL;
2888 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2889 char *parm_data;
2890 int name_len;
2891 int rc = 0;
2892 int bytes_returned = 0;
2893 __u16 params, byte_count, data_count, param_offset, offset;
2894
Joe Perchesb6b38f72010-04-21 03:50:45 +00002895 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896setAclRetry:
2897 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002898 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 if (rc)
2900 return rc;
2901 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2902 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002903 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002904 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 name_len++; /* trailing null */
2906 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002907 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 name_len = strnlen(fileName, PATH_MAX);
2909 name_len++; /* trailing null */
2910 strncpy(pSMB->FileName, fileName, name_len);
2911 }
2912 params = 6 + name_len;
2913 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002914 /* BB find max SMB size from sess */
2915 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 pSMB->MaxSetupCount = 0;
2917 pSMB->Reserved = 0;
2918 pSMB->Flags = 0;
2919 pSMB->Timeout = 0;
2920 pSMB->Reserved2 = 0;
2921 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002922 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 offset = param_offset + params;
2924 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2925 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2926
2927 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002928 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
Steve French790fe572007-07-07 19:25:05 +00002930 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 rc = -EOPNOTSUPP;
2932 goto setACLerrorExit;
2933 }
2934 pSMB->DataOffset = cpu_to_le16(offset);
2935 pSMB->SetupCount = 1;
2936 pSMB->Reserved3 = 0;
2937 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2938 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2939 byte_count = 3 /* pad */ + params + data_count;
2940 pSMB->DataCount = cpu_to_le16(data_count);
2941 pSMB->TotalDataCount = pSMB->DataCount;
2942 pSMB->ParameterCount = cpu_to_le16(params);
2943 pSMB->TotalParameterCount = pSMB->ParameterCount;
2944 pSMB->Reserved4 = 0;
2945 pSMB->hdr.smb_buf_length += byte_count;
2946 pSMB->ByteCount = cpu_to_le16(byte_count);
2947 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002949 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002950 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
2952setACLerrorExit:
2953 cifs_buf_release(pSMB);
2954 if (rc == -EAGAIN)
2955 goto setAclRetry;
2956 return rc;
2957}
2958
Steve Frenchf654bac2005-04-28 22:41:04 -07002959/* BB fix tabs in this function FIXME BB */
2960int
2961CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002962 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002963{
Steve French50c2f752007-07-13 00:33:32 +00002964 int rc = 0;
2965 struct smb_t2_qfi_req *pSMB = NULL;
2966 struct smb_t2_qfi_rsp *pSMBr = NULL;
2967 int bytes_returned;
2968 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002969
Joe Perchesb6b38f72010-04-21 03:50:45 +00002970 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002971 if (tcon == NULL)
2972 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002973
2974GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002975 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2976 (void **) &pSMBr);
2977 if (rc)
2978 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002979
Steve Frenchad7a2922008-02-07 23:25:02 +00002980 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002981 pSMB->t2.TotalDataCount = 0;
2982 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2983 /* BB find exact max data count below from sess structure BB */
2984 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2985 pSMB->t2.MaxSetupCount = 0;
2986 pSMB->t2.Reserved = 0;
2987 pSMB->t2.Flags = 0;
2988 pSMB->t2.Timeout = 0;
2989 pSMB->t2.Reserved2 = 0;
2990 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2991 Fid) - 4);
2992 pSMB->t2.DataCount = 0;
2993 pSMB->t2.DataOffset = 0;
2994 pSMB->t2.SetupCount = 1;
2995 pSMB->t2.Reserved3 = 0;
2996 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2997 byte_count = params + 1 /* pad */ ;
2998 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2999 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3000 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3001 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003002 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003003 pSMB->hdr.smb_buf_length += byte_count;
3004 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003005
Steve French790fe572007-07-07 19:25:05 +00003006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3008 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003009 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003010 } else {
3011 /* decode response */
3012 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3013 if (rc || (pSMBr->ByteCount < 2))
3014 /* BB also check enough total bytes returned */
3015 /* If rc should we check for EOPNOSUPP and
3016 disable the srvino flag? or in caller? */
3017 rc = -EIO; /* bad smb */
3018 else {
3019 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3020 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3021 struct file_chattr_info *pfinfo;
3022 /* BB Do we need a cast or hash here ? */
3023 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003024 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003025 rc = -EIO;
3026 goto GetExtAttrOut;
3027 }
3028 pfinfo = (struct file_chattr_info *)
3029 (data_offset + (char *) &pSMBr->hdr.Protocol);
3030 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003031 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003032 }
3033 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003034GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003035 cifs_buf_release(pSMB);
3036 if (rc == -EAGAIN)
3037 goto GetExtAttrRetry;
3038 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003039}
3040
Steve Frenchf654bac2005-04-28 22:41:04 -07003041#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
Steve French297647c2007-10-12 04:11:59 +00003043#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003044/* Get Security Descriptor (by handle) from remote server for a file or dir */
3045int
3046CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003047 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003048{
3049 int rc = 0;
3050 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003051 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003052 struct kvec iov[1];
3053
Joe Perchesb6b38f72010-04-21 03:50:45 +00003054 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003055
Steve French630f3f0c2007-10-25 21:17:17 +00003056 *pbuflen = 0;
3057 *acl_inf = NULL;
3058
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003059 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003060 8 /* parm len */, tcon, (void **) &pSMB);
3061 if (rc)
3062 return rc;
3063
3064 pSMB->MaxParameterCount = cpu_to_le32(4);
3065 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3066 pSMB->MaxSetupCount = 0;
3067 pSMB->Fid = fid; /* file handle always le */
3068 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3069 CIFS_ACL_DACL);
3070 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3071 pSMB->hdr.smb_buf_length += 11;
3072 iov[0].iov_base = (char *)pSMB;
3073 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3074
Steve Frencha761ac52007-10-18 21:45:27 +00003075 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003076 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003077 cifs_stats_inc(&tcon->num_acl_get);
3078 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003079 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003080 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003081 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003082 __u32 parm_len;
3083 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003084 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003085 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003086
3087/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003088 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003089 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003090 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003091 goto qsec_out;
3092 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3093
Joe Perchesb6b38f72010-04-21 03:50:45 +00003094 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003095
3096 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3097 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003098 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003099 goto qsec_out;
3100 }
3101
3102/* BB check that data area is minimum length and as big as acl_len */
3103
Steve Frenchaf6f4612007-10-16 18:40:37 +00003104 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003105 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003106 cERROR(1, "acl length %d does not match %d",
3107 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003108 if (*pbuflen > acl_len)
3109 *pbuflen = acl_len;
3110 }
Steve French0a4b92c2006-01-12 15:44:21 -08003111
Steve French630f3f0c2007-10-25 21:17:17 +00003112 /* check if buffer is big enough for the acl
3113 header followed by the smallest SID */
3114 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3115 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003116 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003117 rc = -EINVAL;
3118 *pbuflen = 0;
3119 } else {
3120 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3121 if (*acl_inf == NULL) {
3122 *pbuflen = 0;
3123 rc = -ENOMEM;
3124 }
3125 memcpy(*acl_inf, pdata, *pbuflen);
3126 }
Steve French0a4b92c2006-01-12 15:44:21 -08003127 }
3128qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003129 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003130 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003131 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003132 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003133/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003134 return rc;
3135}
Steve French97837582007-12-31 07:47:21 +00003136
3137int
3138CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3139 struct cifs_ntsd *pntsd, __u32 acllen)
3140{
3141 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3142 int rc = 0;
3143 int bytes_returned = 0;
3144 SET_SEC_DESC_REQ *pSMB = NULL;
3145 NTRANSACT_RSP *pSMBr = NULL;
3146
3147setCifsAclRetry:
3148 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3149 (void **) &pSMBr);
3150 if (rc)
3151 return (rc);
3152
3153 pSMB->MaxSetupCount = 0;
3154 pSMB->Reserved = 0;
3155
3156 param_count = 8;
3157 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3158 data_count = acllen;
3159 data_offset = param_offset + param_count;
3160 byte_count = 3 /* pad */ + param_count;
3161
3162 pSMB->DataCount = cpu_to_le32(data_count);
3163 pSMB->TotalDataCount = pSMB->DataCount;
3164 pSMB->MaxParameterCount = cpu_to_le32(4);
3165 pSMB->MaxDataCount = cpu_to_le32(16384);
3166 pSMB->ParameterCount = cpu_to_le32(param_count);
3167 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3168 pSMB->TotalParameterCount = pSMB->ParameterCount;
3169 pSMB->DataOffset = cpu_to_le32(data_offset);
3170 pSMB->SetupCount = 0;
3171 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3172 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3173
3174 pSMB->Fid = fid; /* file handle always le */
3175 pSMB->Reserved2 = 0;
3176 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3177
3178 if (pntsd && acllen) {
3179 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3180 (char *) pntsd,
3181 acllen);
3182 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3183
3184 } else
3185 pSMB->hdr.smb_buf_length += byte_count;
3186
3187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3189
Joe Perchesb6b38f72010-04-21 03:50:45 +00003190 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003191 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003192 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003193 cifs_buf_release(pSMB);
3194
3195 if (rc == -EAGAIN)
3196 goto setCifsAclRetry;
3197
3198 return (rc);
3199}
3200
Steve French297647c2007-10-12 04:11:59 +00003201#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003202
Steve French6b8edfe2005-08-23 20:26:03 -07003203/* Legacy Query Path Information call for lookup to old servers such
3204 as Win9x/WinME */
3205int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003206 const unsigned char *searchName,
3207 FILE_ALL_INFO *pFinfo,
3208 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003209{
Steve Frenchad7a2922008-02-07 23:25:02 +00003210 QUERY_INFORMATION_REQ *pSMB;
3211 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003212 int rc = 0;
3213 int bytes_returned;
3214 int name_len;
3215
Joe Perchesb6b38f72010-04-21 03:50:45 +00003216 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003217QInfRetry:
3218 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003219 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003220 if (rc)
3221 return rc;
3222
3223 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3224 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003225 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3226 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003227 name_len++; /* trailing null */
3228 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003229 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003230 name_len = strnlen(searchName, PATH_MAX);
3231 name_len++; /* trailing null */
3232 strncpy(pSMB->FileName, searchName, name_len);
3233 }
3234 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003235 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003236 pSMB->hdr.smb_buf_length += (__u16) name_len;
3237 pSMB->ByteCount = cpu_to_le16(name_len);
3238
3239 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003240 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003241 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003242 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003243 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003244 struct timespec ts;
3245 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003246
3247 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003248 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003249 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003250 ts.tv_nsec = 0;
3251 ts.tv_sec = time;
3252 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003253 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003254 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3255 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003256 pFinfo->AllocationSize =
3257 cpu_to_le64(le32_to_cpu(pSMBr->size));
3258 pFinfo->EndOfFile = pFinfo->AllocationSize;
3259 pFinfo->Attributes =
3260 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003261 } else
3262 rc = -EIO; /* bad buffer passed in */
3263
3264 cifs_buf_release(pSMB);
3265
3266 if (rc == -EAGAIN)
3267 goto QInfRetry;
3268
3269 return rc;
3270}
3271
Jeff Laytonbcd53572010-02-12 07:44:16 -05003272int
3273CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3274 u16 netfid, FILE_ALL_INFO *pFindData)
3275{
3276 struct smb_t2_qfi_req *pSMB = NULL;
3277 struct smb_t2_qfi_rsp *pSMBr = NULL;
3278 int rc = 0;
3279 int bytes_returned;
3280 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003281
Jeff Laytonbcd53572010-02-12 07:44:16 -05003282QFileInfoRetry:
3283 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3284 (void **) &pSMBr);
3285 if (rc)
3286 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003287
Jeff Laytonbcd53572010-02-12 07:44:16 -05003288 params = 2 /* level */ + 2 /* fid */;
3289 pSMB->t2.TotalDataCount = 0;
3290 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3291 /* BB find exact max data count below from sess structure BB */
3292 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3293 pSMB->t2.MaxSetupCount = 0;
3294 pSMB->t2.Reserved = 0;
3295 pSMB->t2.Flags = 0;
3296 pSMB->t2.Timeout = 0;
3297 pSMB->t2.Reserved2 = 0;
3298 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3299 Fid) - 4);
3300 pSMB->t2.DataCount = 0;
3301 pSMB->t2.DataOffset = 0;
3302 pSMB->t2.SetupCount = 1;
3303 pSMB->t2.Reserved3 = 0;
3304 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3305 byte_count = params + 1 /* pad */ ;
3306 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3307 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3308 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3309 pSMB->Pad = 0;
3310 pSMB->Fid = netfid;
3311 pSMB->hdr.smb_buf_length += byte_count;
3312
3313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3314 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3315 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003316 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003317 } else { /* decode response */
3318 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3319
3320 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3321 rc = -EIO;
3322 else if (pSMBr->ByteCount < 40)
3323 rc = -EIO; /* bad smb */
3324 else if (pFindData) {
3325 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3326 memcpy((char *) pFindData,
3327 (char *) &pSMBr->hdr.Protocol +
3328 data_offset, sizeof(FILE_ALL_INFO));
3329 } else
3330 rc = -ENOMEM;
3331 }
3332 cifs_buf_release(pSMB);
3333 if (rc == -EAGAIN)
3334 goto QFileInfoRetry;
3335
3336 return rc;
3337}
Steve French6b8edfe2005-08-23 20:26:03 -07003338
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339int
3340CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3341 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003342 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003343 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003344 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345{
3346/* level 263 SMB_QUERY_FILE_ALL_INFO */
3347 TRANSACTION2_QPI_REQ *pSMB = NULL;
3348 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3349 int rc = 0;
3350 int bytes_returned;
3351 int name_len;
3352 __u16 params, byte_count;
3353
Joe Perchesb6b38f72010-04-21 03:50:45 +00003354/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355QPathInfoRetry:
3356 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3357 (void **) &pSMBr);
3358 if (rc)
3359 return rc;
3360
3361 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3362 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003363 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003364 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 name_len++; /* trailing null */
3366 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003367 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 name_len = strnlen(searchName, PATH_MAX);
3369 name_len++; /* trailing null */
3370 strncpy(pSMB->FileName, searchName, name_len);
3371 }
3372
Steve French50c2f752007-07-13 00:33:32 +00003373 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 pSMB->TotalDataCount = 0;
3375 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003376 /* BB find exact max SMB PDU from sess structure BB */
3377 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 pSMB->MaxSetupCount = 0;
3379 pSMB->Reserved = 0;
3380 pSMB->Flags = 0;
3381 pSMB->Timeout = 0;
3382 pSMB->Reserved2 = 0;
3383 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003384 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003385 pSMB->DataCount = 0;
3386 pSMB->DataOffset = 0;
3387 pSMB->SetupCount = 1;
3388 pSMB->Reserved3 = 0;
3389 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3390 byte_count = params + 1 /* pad */ ;
3391 pSMB->TotalParameterCount = cpu_to_le16(params);
3392 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003393 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003394 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3395 else
3396 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 pSMB->Reserved4 = 0;
3398 pSMB->hdr.smb_buf_length += byte_count;
3399 pSMB->ByteCount = cpu_to_le16(byte_count);
3400
3401 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3403 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003404 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 } else { /* decode response */
3406 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3407
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003408 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3409 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003410 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003412 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003413 rc = -EIO; /* 24 or 26 expected but we do not read
3414 last field */
3415 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003416 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003418
3419 /* On legacy responses we do not read the last field,
3420 EAsize, fortunately since it varies by subdialect and
3421 also note it differs on Set vs. Get, ie two bytes or 4
3422 bytes depending but we don't care here */
3423 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003424 size = sizeof(FILE_INFO_STANDARD);
3425 else
3426 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003427 memcpy((char *) pFindData,
3428 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003429 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 } else
3431 rc = -ENOMEM;
3432 }
3433 cifs_buf_release(pSMB);
3434 if (rc == -EAGAIN)
3435 goto QPathInfoRetry;
3436
3437 return rc;
3438}
3439
3440int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003441CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3442 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3443{
3444 struct smb_t2_qfi_req *pSMB = NULL;
3445 struct smb_t2_qfi_rsp *pSMBr = NULL;
3446 int rc = 0;
3447 int bytes_returned;
3448 __u16 params, byte_count;
3449
3450UnixQFileInfoRetry:
3451 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3452 (void **) &pSMBr);
3453 if (rc)
3454 return rc;
3455
3456 params = 2 /* level */ + 2 /* fid */;
3457 pSMB->t2.TotalDataCount = 0;
3458 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3459 /* BB find exact max data count below from sess structure BB */
3460 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3461 pSMB->t2.MaxSetupCount = 0;
3462 pSMB->t2.Reserved = 0;
3463 pSMB->t2.Flags = 0;
3464 pSMB->t2.Timeout = 0;
3465 pSMB->t2.Reserved2 = 0;
3466 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3467 Fid) - 4);
3468 pSMB->t2.DataCount = 0;
3469 pSMB->t2.DataOffset = 0;
3470 pSMB->t2.SetupCount = 1;
3471 pSMB->t2.Reserved3 = 0;
3472 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3473 byte_count = params + 1 /* pad */ ;
3474 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3475 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3476 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3477 pSMB->Pad = 0;
3478 pSMB->Fid = netfid;
3479 pSMB->hdr.smb_buf_length += byte_count;
3480
3481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3482 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3483 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003484 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003485 } else { /* decode response */
3486 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3487
3488 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003489 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003490 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003491 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003492 rc = -EIO; /* bad smb */
3493 } else {
3494 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3495 memcpy((char *) pFindData,
3496 (char *) &pSMBr->hdr.Protocol +
3497 data_offset,
3498 sizeof(FILE_UNIX_BASIC_INFO));
3499 }
3500 }
3501
3502 cifs_buf_release(pSMB);
3503 if (rc == -EAGAIN)
3504 goto UnixQFileInfoRetry;
3505
3506 return rc;
3507}
3508
3509int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3511 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003512 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003513 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514{
3515/* SMB_QUERY_FILE_UNIX_BASIC */
3516 TRANSACTION2_QPI_REQ *pSMB = NULL;
3517 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3518 int rc = 0;
3519 int bytes_returned = 0;
3520 int name_len;
3521 __u16 params, byte_count;
3522
Joe Perchesb6b38f72010-04-21 03:50:45 +00003523 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524UnixQPathInfoRetry:
3525 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3526 (void **) &pSMBr);
3527 if (rc)
3528 return rc;
3529
3530 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3531 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003532 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003533 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 name_len++; /* trailing null */
3535 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003536 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 name_len = strnlen(searchName, PATH_MAX);
3538 name_len++; /* trailing null */
3539 strncpy(pSMB->FileName, searchName, name_len);
3540 }
3541
Steve French50c2f752007-07-13 00:33:32 +00003542 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 pSMB->TotalDataCount = 0;
3544 pSMB->MaxParameterCount = cpu_to_le16(2);
3545 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003546 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 pSMB->MaxSetupCount = 0;
3548 pSMB->Reserved = 0;
3549 pSMB->Flags = 0;
3550 pSMB->Timeout = 0;
3551 pSMB->Reserved2 = 0;
3552 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003553 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 pSMB->DataCount = 0;
3555 pSMB->DataOffset = 0;
3556 pSMB->SetupCount = 1;
3557 pSMB->Reserved3 = 0;
3558 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3559 byte_count = params + 1 /* pad */ ;
3560 pSMB->TotalParameterCount = cpu_to_le16(params);
3561 pSMB->ParameterCount = pSMB->TotalParameterCount;
3562 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3563 pSMB->Reserved4 = 0;
3564 pSMB->hdr.smb_buf_length += byte_count;
3565 pSMB->ByteCount = cpu_to_le16(byte_count);
3566
3567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3569 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003570 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 } else { /* decode response */
3572 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3573
3574 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003575 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003576 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003577 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 rc = -EIO; /* bad smb */
3579 } else {
3580 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3581 memcpy((char *) pFindData,
3582 (char *) &pSMBr->hdr.Protocol +
3583 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003584 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 }
3586 }
3587 cifs_buf_release(pSMB);
3588 if (rc == -EAGAIN)
3589 goto UnixQPathInfoRetry;
3590
3591 return rc;
3592}
3593
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594/* xid, tcon, searchName and codepage are input parms, rest are returned */
3595int
3596CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003597 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003599 __u16 *pnetfid,
3600 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601{
3602/* level 257 SMB_ */
3603 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3604 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003605 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 int rc = 0;
3607 int bytes_returned = 0;
3608 int name_len;
3609 __u16 params, byte_count;
3610
Joe Perchesb6b38f72010-04-21 03:50:45 +00003611 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
3613findFirstRetry:
3614 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3615 (void **) &pSMBr);
3616 if (rc)
3617 return rc;
3618
3619 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3620 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003621 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003622 PATH_MAX, nls_codepage, remap);
3623 /* We can not add the asterik earlier in case
3624 it got remapped to 0xF03A as if it were part of the
3625 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003627 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003628 pSMB->FileName[name_len+1] = 0;
3629 pSMB->FileName[name_len+2] = '*';
3630 pSMB->FileName[name_len+3] = 0;
3631 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3633 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003634 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 } else { /* BB add check for overrun of SMB buf BB */
3636 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003638 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003639 free buffer exit; BB */
3640 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003641 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003642 pSMB->FileName[name_len+1] = '*';
3643 pSMB->FileName[name_len+2] = 0;
3644 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 }
3646
3647 params = 12 + name_len /* includes null */ ;
3648 pSMB->TotalDataCount = 0; /* no EAs */
3649 pSMB->MaxParameterCount = cpu_to_le16(10);
3650 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3651 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3652 pSMB->MaxSetupCount = 0;
3653 pSMB->Reserved = 0;
3654 pSMB->Flags = 0;
3655 pSMB->Timeout = 0;
3656 pSMB->Reserved2 = 0;
3657 byte_count = params + 1 /* pad */ ;
3658 pSMB->TotalParameterCount = cpu_to_le16(params);
3659 pSMB->ParameterCount = pSMB->TotalParameterCount;
3660 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003661 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3662 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 pSMB->DataCount = 0;
3664 pSMB->DataOffset = 0;
3665 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3666 pSMB->Reserved3 = 0;
3667 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3668 pSMB->SearchAttributes =
3669 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3670 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003671 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3672 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 CIFS_SEARCH_RETURN_RESUME);
3674 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3675
3676 /* BB what should we set StorageType to? Does it matter? BB */
3677 pSMB->SearchStorageType = 0;
3678 pSMB->hdr.smb_buf_length += byte_count;
3679 pSMB->ByteCount = cpu_to_le16(byte_count);
3680
3681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003683 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
Steve French88274812006-03-09 22:21:45 +00003685 if (rc) {/* BB add logic to retry regular search if Unix search
3686 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003688 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003689
Steve French88274812006-03-09 22:21:45 +00003690 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691
3692 /* BB eventually could optimize out free and realloc of buf */
3693 /* for this case */
3694 if (rc == -EAGAIN)
3695 goto findFirstRetry;
3696 } else { /* decode response */
3697 /* BB remember to free buffer if error BB */
3698 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003699 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003700 unsigned int lnoff;
3701
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003703 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 else
Steve French4b18f2a2008-04-29 00:06:05 +00003705 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706
3707 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003708 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003709 psrch_inf->srch_entries_start =
3710 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3713 le16_to_cpu(pSMBr->t2.ParameterOffset));
3714
Steve French790fe572007-07-07 19:25:05 +00003715 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003716 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 else
Steve French4b18f2a2008-04-29 00:06:05 +00003718 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
Steve French50c2f752007-07-13 00:33:32 +00003720 psrch_inf->entries_in_buffer =
3721 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003722 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003724 lnoff = le16_to_cpu(parms->LastNameOffset);
3725 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3726 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003727 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003728 psrch_inf->last_entry = NULL;
3729 return rc;
3730 }
3731
Steve French0752f152008-10-07 20:03:33 +00003732 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003733 lnoff;
3734
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 *pnetfid = parms->SearchHandle;
3736 } else {
3737 cifs_buf_release(pSMB);
3738 }
3739 }
3740
3741 return rc;
3742}
3743
3744int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003745 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746{
3747 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3748 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003749 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 char *response_data;
3751 int rc = 0;
3752 int bytes_returned, name_len;
3753 __u16 params, byte_count;
3754
Joe Perchesb6b38f72010-04-21 03:50:45 +00003755 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
Steve French4b18f2a2008-04-29 00:06:05 +00003757 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 return -ENOENT;
3759
3760 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3761 (void **) &pSMBr);
3762 if (rc)
3763 return rc;
3764
Steve French50c2f752007-07-13 00:33:32 +00003765 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 byte_count = 0;
3767 pSMB->TotalDataCount = 0; /* no EAs */
3768 pSMB->MaxParameterCount = cpu_to_le16(8);
3769 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003770 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3771 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 pSMB->MaxSetupCount = 0;
3773 pSMB->Reserved = 0;
3774 pSMB->Flags = 0;
3775 pSMB->Timeout = 0;
3776 pSMB->Reserved2 = 0;
3777 pSMB->ParameterOffset = cpu_to_le16(
3778 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3779 pSMB->DataCount = 0;
3780 pSMB->DataOffset = 0;
3781 pSMB->SetupCount = 1;
3782 pSMB->Reserved3 = 0;
3783 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3784 pSMB->SearchHandle = searchHandle; /* always kept as le */
3785 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003786 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3788 pSMB->ResumeKey = psrch_inf->resume_key;
3789 pSMB->SearchFlags =
3790 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3791
3792 name_len = psrch_inf->resume_name_len;
3793 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003794 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3796 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003797 /* 14 byte parm len above enough for 2 byte null terminator */
3798 pSMB->ResumeFileName[name_len] = 0;
3799 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 } else {
3801 rc = -EINVAL;
3802 goto FNext2_err_exit;
3803 }
3804 byte_count = params + 1 /* pad */ ;
3805 pSMB->TotalParameterCount = cpu_to_le16(params);
3806 pSMB->ParameterCount = pSMB->TotalParameterCount;
3807 pSMB->hdr.smb_buf_length += byte_count;
3808 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003809
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003812 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 if (rc) {
3814 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003815 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003816 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003817 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003819 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820 } else { /* decode response */
3821 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003822
Steve French790fe572007-07-07 19:25:05 +00003823 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003824 unsigned int lnoff;
3825
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826 /* BB fixme add lock for file (srch_info) struct here */
3827 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003828 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 else
Steve French4b18f2a2008-04-29 00:06:05 +00003830 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 response_data = (char *) &pSMBr->hdr.Protocol +
3832 le16_to_cpu(pSMBr->t2.ParameterOffset);
3833 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3834 response_data = (char *)&pSMBr->hdr.Protocol +
3835 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003836 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003837 cifs_small_buf_release(
3838 psrch_inf->ntwrk_buf_start);
3839 else
3840 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 psrch_inf->srch_entries_start = response_data;
3842 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003843 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003844 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003845 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 else
Steve French4b18f2a2008-04-29 00:06:05 +00003847 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003848 psrch_inf->entries_in_buffer =
3849 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 psrch_inf->index_of_last_entry +=
3851 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003852 lnoff = le16_to_cpu(parms->LastNameOffset);
3853 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3854 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003855 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003856 psrch_inf->last_entry = NULL;
3857 return rc;
3858 } else
3859 psrch_inf->last_entry =
3860 psrch_inf->srch_entries_start + lnoff;
3861
Joe Perchesb6b38f72010-04-21 03:50:45 +00003862/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3863 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864
3865 /* BB fixme add unlock here */
3866 }
3867
3868 }
3869
3870 /* BB On error, should we leave previous search buf (and count and
3871 last entry fields) intact or free the previous one? */
3872
3873 /* Note: On -EAGAIN error only caller can retry on handle based calls
3874 since file handle passed in no longer valid */
3875FNext2_err_exit:
3876 if (rc != 0)
3877 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 return rc;
3879}
3880
3881int
Steve French50c2f752007-07-13 00:33:32 +00003882CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3883 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884{
3885 int rc = 0;
3886 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
Joe Perchesb6b38f72010-04-21 03:50:45 +00003888 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3890
3891 /* no sense returning error if session restarted
3892 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003893 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 return 0;
3895 if (rc)
3896 return rc;
3897
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 pSMB->FileID = searchHandle;
3899 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003900 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003901 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003902 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003903
Steve Frencha4544342005-08-24 13:59:35 -07003904 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
3906 /* Since session is dead, search handle closed on server already */
3907 if (rc == -EAGAIN)
3908 rc = 0;
3909
3910 return rc;
3911}
3912
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913int
3914CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003915 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003916 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003917 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918{
3919 int rc = 0;
3920 TRANSACTION2_QPI_REQ *pSMB = NULL;
3921 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3922 int name_len, bytes_returned;
3923 __u16 params, byte_count;
3924
Joe Perchesb6b38f72010-04-21 03:50:45 +00003925 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003926 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003927 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928
3929GetInodeNumberRetry:
3930 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003931 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 if (rc)
3933 return rc;
3934
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3936 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003937 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003938 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 name_len++; /* trailing null */
3940 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003941 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 name_len = strnlen(searchName, PATH_MAX);
3943 name_len++; /* trailing null */
3944 strncpy(pSMB->FileName, searchName, name_len);
3945 }
3946
3947 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3948 pSMB->TotalDataCount = 0;
3949 pSMB->MaxParameterCount = cpu_to_le16(2);
3950 /* BB find exact max data count below from sess structure BB */
3951 pSMB->MaxDataCount = cpu_to_le16(4000);
3952 pSMB->MaxSetupCount = 0;
3953 pSMB->Reserved = 0;
3954 pSMB->Flags = 0;
3955 pSMB->Timeout = 0;
3956 pSMB->Reserved2 = 0;
3957 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003958 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 pSMB->DataCount = 0;
3960 pSMB->DataOffset = 0;
3961 pSMB->SetupCount = 1;
3962 pSMB->Reserved3 = 0;
3963 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3964 byte_count = params + 1 /* pad */ ;
3965 pSMB->TotalParameterCount = cpu_to_le16(params);
3966 pSMB->ParameterCount = pSMB->TotalParameterCount;
3967 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3968 pSMB->Reserved4 = 0;
3969 pSMB->hdr.smb_buf_length += byte_count;
3970 pSMB->ByteCount = cpu_to_le16(byte_count);
3971
3972 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3973 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3974 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003975 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 } else {
3977 /* decode response */
3978 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3979 if (rc || (pSMBr->ByteCount < 2))
3980 /* BB also check enough total bytes returned */
3981 /* If rc should we check for EOPNOSUPP and
3982 disable the srvino flag? or in caller? */
3983 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003984 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3986 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003987 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003989 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003990 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 rc = -EIO;
3992 goto GetInodeNumOut;
3993 }
3994 pfinfo = (struct file_internal_info *)
3995 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003996 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 }
3998 }
3999GetInodeNumOut:
4000 cifs_buf_release(pSMB);
4001 if (rc == -EAGAIN)
4002 goto GetInodeNumberRetry;
4003 return rc;
4004}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005
Igor Mammedovfec45852008-05-16 13:06:30 +04004006/* parses DFS refferal V3 structure
4007 * caller is responsible for freeing target_nodes
4008 * returns:
4009 * on success - 0
4010 * on failure - errno
4011 */
4012static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004013parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004014 unsigned int *num_of_nodes,
4015 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004016 const struct nls_table *nls_codepage, int remap,
4017 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004018{
4019 int i, rc = 0;
4020 char *data_end;
4021 bool is_unicode;
4022 struct dfs_referral_level_3 *ref;
4023
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004024 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4025 is_unicode = true;
4026 else
4027 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004028 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4029
4030 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004031 cERROR(1, "num_referrals: must be at least > 0,"
4032 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004033 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004034 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004035 }
4036
4037 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004038 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004039 cERROR(1, "Referrals of V%d version are not supported,"
4040 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004041 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004042 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004043 }
4044
4045 /* get the upper boundary of the resp buffer */
4046 data_end = (char *)(&(pSMBr->PathConsumed)) +
4047 le16_to_cpu(pSMBr->t2.DataCount);
4048
Steve Frenchf19159d2010-04-21 04:12:10 +00004049 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004050 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004051 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004052
4053 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4054 *num_of_nodes, GFP_KERNEL);
4055 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004056 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004057 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004058 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004059 }
4060
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004061 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004062 for (i = 0; i < *num_of_nodes; i++) {
4063 char *temp;
4064 int max_len;
4065 struct dfs_info3_param *node = (*target_nodes)+i;
4066
Steve French0e0d2cf2009-05-01 05:27:32 +00004067 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004068 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004069 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4070 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004071 if (tmp == NULL) {
4072 rc = -ENOMEM;
4073 goto parse_DFS_referrals_exit;
4074 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004075 cifsConvertToUCS((__le16 *) tmp, searchName,
4076 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004077 node->path_consumed = cifs_ucs2_bytes(tmp,
4078 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004079 nls_codepage);
4080 kfree(tmp);
4081 } else
4082 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4083
Igor Mammedovfec45852008-05-16 13:06:30 +04004084 node->server_type = le16_to_cpu(ref->ServerType);
4085 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4086
4087 /* copy DfsPath */
4088 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4089 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004090 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4091 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004092 if (!node->path_name) {
4093 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004094 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004095 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004096
4097 /* copy link target UNC */
4098 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4099 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004100 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4101 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004102 if (!node->node_name)
4103 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004104 }
4105
Steve Frencha1fe78f2008-05-16 18:48:38 +00004106parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004107 if (rc) {
4108 free_dfs_info_array(*target_nodes, *num_of_nodes);
4109 *target_nodes = NULL;
4110 *num_of_nodes = 0;
4111 }
4112 return rc;
4113}
4114
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115int
4116CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4117 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004118 struct dfs_info3_param **target_nodes,
4119 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004120 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121{
4122/* TRANS2_GET_DFS_REFERRAL */
4123 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4124 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 int rc = 0;
4126 int bytes_returned;
4127 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004129 *num_of_nodes = 0;
4130 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131
Joe Perchesb6b38f72010-04-21 03:50:45 +00004132 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 if (ses == NULL)
4134 return -ENODEV;
4135getDFSRetry:
4136 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4137 (void **) &pSMBr);
4138 if (rc)
4139 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004140
4141 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004142 but should never be null here anyway */
4143 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 pSMB->hdr.Tid = ses->ipc_tid;
4145 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004146 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004148 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150
4151 if (ses->capabilities & CAP_UNICODE) {
4152 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4153 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004154 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004155 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 name_len++; /* trailing null */
4157 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004158 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 name_len = strnlen(searchName, PATH_MAX);
4160 name_len++; /* trailing null */
4161 strncpy(pSMB->RequestFileName, searchName, name_len);
4162 }
4163
Steve French790fe572007-07-07 19:25:05 +00004164 if (ses->server) {
4165 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004166 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4167 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4168 }
4169
Steve French50c2f752007-07-13 00:33:32 +00004170 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004171
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 params = 2 /* level */ + name_len /*includes null */ ;
4173 pSMB->TotalDataCount = 0;
4174 pSMB->DataCount = 0;
4175 pSMB->DataOffset = 0;
4176 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004177 /* BB find exact max SMB PDU from sess structure BB */
4178 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 pSMB->MaxSetupCount = 0;
4180 pSMB->Reserved = 0;
4181 pSMB->Flags = 0;
4182 pSMB->Timeout = 0;
4183 pSMB->Reserved2 = 0;
4184 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004185 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 pSMB->SetupCount = 1;
4187 pSMB->Reserved3 = 0;
4188 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4189 byte_count = params + 3 /* pad */ ;
4190 pSMB->ParameterCount = cpu_to_le16(params);
4191 pSMB->TotalParameterCount = pSMB->ParameterCount;
4192 pSMB->MaxReferralLevel = cpu_to_le16(3);
4193 pSMB->hdr.smb_buf_length += byte_count;
4194 pSMB->ByteCount = cpu_to_le16(byte_count);
4195
4196 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4198 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004199 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004200 goto GetDFSRefExit;
4201 }
4202 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004204 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004205 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004206 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004207 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004209
Joe Perchesb6b38f72010-04-21 03:50:45 +00004210 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Igor Mammedovfec45852008-05-16 13:06:30 +04004211 pSMBr->ByteCount,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004212 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004213
4214 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004215 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004216 target_nodes, nls_codepage, remap,
4217 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004218
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004220 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221
4222 if (rc == -EAGAIN)
4223 goto getDFSRetry;
4224
4225 return rc;
4226}
4227
Steve French20962432005-09-21 22:05:57 -07004228/* Query File System Info such as free space to old servers such as Win 9x */
4229int
4230SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4231{
4232/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4233 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4234 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4235 FILE_SYSTEM_ALLOC_INFO *response_data;
4236 int rc = 0;
4237 int bytes_returned = 0;
4238 __u16 params, byte_count;
4239
Joe Perchesb6b38f72010-04-21 03:50:45 +00004240 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004241oldQFSInfoRetry:
4242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4243 (void **) &pSMBr);
4244 if (rc)
4245 return rc;
Steve French20962432005-09-21 22:05:57 -07004246
4247 params = 2; /* level */
4248 pSMB->TotalDataCount = 0;
4249 pSMB->MaxParameterCount = cpu_to_le16(2);
4250 pSMB->MaxDataCount = cpu_to_le16(1000);
4251 pSMB->MaxSetupCount = 0;
4252 pSMB->Reserved = 0;
4253 pSMB->Flags = 0;
4254 pSMB->Timeout = 0;
4255 pSMB->Reserved2 = 0;
4256 byte_count = params + 1 /* pad */ ;
4257 pSMB->TotalParameterCount = cpu_to_le16(params);
4258 pSMB->ParameterCount = pSMB->TotalParameterCount;
4259 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4260 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4261 pSMB->DataCount = 0;
4262 pSMB->DataOffset = 0;
4263 pSMB->SetupCount = 1;
4264 pSMB->Reserved3 = 0;
4265 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4266 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4267 pSMB->hdr.smb_buf_length += byte_count;
4268 pSMB->ByteCount = cpu_to_le16(byte_count);
4269
4270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4272 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004273 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004274 } else { /* decode response */
4275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4276
4277 if (rc || (pSMBr->ByteCount < 18))
4278 rc = -EIO; /* bad smb */
4279 else {
4280 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004281 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4282 pSMBr->ByteCount, data_offset);
Steve French20962432005-09-21 22:05:57 -07004283
Steve French50c2f752007-07-13 00:33:32 +00004284 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004285 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4286 FSData->f_bsize =
4287 le16_to_cpu(response_data->BytesPerSector) *
4288 le32_to_cpu(response_data->
4289 SectorsPerAllocationUnit);
4290 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004291 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004292 FSData->f_bfree = FSData->f_bavail =
4293 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004294 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4295 (unsigned long long)FSData->f_blocks,
4296 (unsigned long long)FSData->f_bfree,
4297 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004298 }
4299 }
4300 cifs_buf_release(pSMB);
4301
4302 if (rc == -EAGAIN)
4303 goto oldQFSInfoRetry;
4304
4305 return rc;
4306}
4307
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308int
Steve French737b7582005-04-28 22:41:06 -07004309CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310{
4311/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4312 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4313 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4314 FILE_SYSTEM_INFO *response_data;
4315 int rc = 0;
4316 int bytes_returned = 0;
4317 __u16 params, byte_count;
4318
Joe Perchesb6b38f72010-04-21 03:50:45 +00004319 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320QFSInfoRetry:
4321 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4322 (void **) &pSMBr);
4323 if (rc)
4324 return rc;
4325
4326 params = 2; /* level */
4327 pSMB->TotalDataCount = 0;
4328 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004329 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 pSMB->MaxSetupCount = 0;
4331 pSMB->Reserved = 0;
4332 pSMB->Flags = 0;
4333 pSMB->Timeout = 0;
4334 pSMB->Reserved2 = 0;
4335 byte_count = params + 1 /* pad */ ;
4336 pSMB->TotalParameterCount = cpu_to_le16(params);
4337 pSMB->ParameterCount = pSMB->TotalParameterCount;
4338 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004339 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 pSMB->DataCount = 0;
4341 pSMB->DataOffset = 0;
4342 pSMB->SetupCount = 1;
4343 pSMB->Reserved3 = 0;
4344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4346 pSMB->hdr.smb_buf_length += byte_count;
4347 pSMB->ByteCount = cpu_to_le16(byte_count);
4348
4349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4351 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004352 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Steve French20962432005-09-21 22:05:57 -07004356 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 rc = -EIO; /* bad smb */
4358 else {
4359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
4361 response_data =
4362 (FILE_SYSTEM_INFO
4363 *) (((char *) &pSMBr->hdr.Protocol) +
4364 data_offset);
4365 FSData->f_bsize =
4366 le32_to_cpu(response_data->BytesPerSector) *
4367 le32_to_cpu(response_data->
4368 SectorsPerAllocationUnit);
4369 FSData->f_blocks =
4370 le64_to_cpu(response_data->TotalAllocationUnits);
4371 FSData->f_bfree = FSData->f_bavail =
4372 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004373 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4374 (unsigned long long)FSData->f_blocks,
4375 (unsigned long long)FSData->f_bfree,
4376 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 }
4378 }
4379 cifs_buf_release(pSMB);
4380
4381 if (rc == -EAGAIN)
4382 goto QFSInfoRetry;
4383
4384 return rc;
4385}
4386
4387int
Steve French737b7582005-04-28 22:41:06 -07004388CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389{
4390/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4391 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4392 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4393 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4394 int rc = 0;
4395 int bytes_returned = 0;
4396 __u16 params, byte_count;
4397
Joe Perchesb6b38f72010-04-21 03:50:45 +00004398 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004399QFSAttributeRetry:
4400 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4401 (void **) &pSMBr);
4402 if (rc)
4403 return rc;
4404
4405 params = 2; /* level */
4406 pSMB->TotalDataCount = 0;
4407 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004408 /* BB find exact max SMB PDU from sess structure BB */
4409 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 pSMB->MaxSetupCount = 0;
4411 pSMB->Reserved = 0;
4412 pSMB->Flags = 0;
4413 pSMB->Timeout = 0;
4414 pSMB->Reserved2 = 0;
4415 byte_count = params + 1 /* pad */ ;
4416 pSMB->TotalParameterCount = cpu_to_le16(params);
4417 pSMB->ParameterCount = pSMB->TotalParameterCount;
4418 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004419 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420 pSMB->DataCount = 0;
4421 pSMB->DataOffset = 0;
4422 pSMB->SetupCount = 1;
4423 pSMB->Reserved3 = 0;
4424 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4425 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4426 pSMB->hdr.smb_buf_length += byte_count;
4427 pSMB->ByteCount = cpu_to_le16(byte_count);
4428
4429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4431 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004432 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 } else { /* decode response */
4434 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4435
Steve French50c2f752007-07-13 00:33:32 +00004436 if (rc || (pSMBr->ByteCount < 13)) {
4437 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 rc = -EIO; /* bad smb */
4439 } else {
4440 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4441 response_data =
4442 (FILE_SYSTEM_ATTRIBUTE_INFO
4443 *) (((char *) &pSMBr->hdr.Protocol) +
4444 data_offset);
4445 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004446 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 }
4448 }
4449 cifs_buf_release(pSMB);
4450
4451 if (rc == -EAGAIN)
4452 goto QFSAttributeRetry;
4453
4454 return rc;
4455}
4456
4457int
Steve French737b7582005-04-28 22:41:06 -07004458CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459{
4460/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4461 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4462 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4463 FILE_SYSTEM_DEVICE_INFO *response_data;
4464 int rc = 0;
4465 int bytes_returned = 0;
4466 __u16 params, byte_count;
4467
Joe Perchesb6b38f72010-04-21 03:50:45 +00004468 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469QFSDeviceRetry:
4470 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4471 (void **) &pSMBr);
4472 if (rc)
4473 return rc;
4474
4475 params = 2; /* level */
4476 pSMB->TotalDataCount = 0;
4477 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004478 /* BB find exact max SMB PDU from sess structure BB */
4479 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 pSMB->MaxSetupCount = 0;
4481 pSMB->Reserved = 0;
4482 pSMB->Flags = 0;
4483 pSMB->Timeout = 0;
4484 pSMB->Reserved2 = 0;
4485 byte_count = params + 1 /* pad */ ;
4486 pSMB->TotalParameterCount = cpu_to_le16(params);
4487 pSMB->ParameterCount = pSMB->TotalParameterCount;
4488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004489 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
4491 pSMB->DataCount = 0;
4492 pSMB->DataOffset = 0;
4493 pSMB->SetupCount = 1;
4494 pSMB->Reserved3 = 0;
4495 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4496 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4497 pSMB->hdr.smb_buf_length += byte_count;
4498 pSMB->ByteCount = cpu_to_le16(byte_count);
4499
4500 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4502 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004503 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 } else { /* decode response */
4505 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4506
Steve French630f3f0c2007-10-25 21:17:17 +00004507 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 rc = -EIO; /* bad smb */
4509 else {
4510 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4511 response_data =
Steve French737b7582005-04-28 22:41:06 -07004512 (FILE_SYSTEM_DEVICE_INFO *)
4513 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 data_offset);
4515 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004516 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 }
4518 }
4519 cifs_buf_release(pSMB);
4520
4521 if (rc == -EAGAIN)
4522 goto QFSDeviceRetry;
4523
4524 return rc;
4525}
4526
4527int
Steve French737b7582005-04-28 22:41:06 -07004528CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529{
4530/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4531 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4532 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4533 FILE_SYSTEM_UNIX_INFO *response_data;
4534 int rc = 0;
4535 int bytes_returned = 0;
4536 __u16 params, byte_count;
4537
Joe Perchesb6b38f72010-04-21 03:50:45 +00004538 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539QFSUnixRetry:
4540 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4541 (void **) &pSMBr);
4542 if (rc)
4543 return rc;
4544
4545 params = 2; /* level */
4546 pSMB->TotalDataCount = 0;
4547 pSMB->DataCount = 0;
4548 pSMB->DataOffset = 0;
4549 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004550 /* BB find exact max SMB PDU from sess structure BB */
4551 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 pSMB->MaxSetupCount = 0;
4553 pSMB->Reserved = 0;
4554 pSMB->Flags = 0;
4555 pSMB->Timeout = 0;
4556 pSMB->Reserved2 = 0;
4557 byte_count = params + 1 /* pad */ ;
4558 pSMB->ParameterCount = cpu_to_le16(params);
4559 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004560 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4561 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 pSMB->SetupCount = 1;
4563 pSMB->Reserved3 = 0;
4564 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4565 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4566 pSMB->hdr.smb_buf_length += byte_count;
4567 pSMB->ByteCount = cpu_to_le16(byte_count);
4568
4569 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4570 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4571 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004572 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004573 } else { /* decode response */
4574 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4575
4576 if (rc || (pSMBr->ByteCount < 13)) {
4577 rc = -EIO; /* bad smb */
4578 } else {
4579 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4580 response_data =
4581 (FILE_SYSTEM_UNIX_INFO
4582 *) (((char *) &pSMBr->hdr.Protocol) +
4583 data_offset);
4584 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004585 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 }
4587 }
4588 cifs_buf_release(pSMB);
4589
4590 if (rc == -EAGAIN)
4591 goto QFSUnixRetry;
4592
4593
4594 return rc;
4595}
4596
Jeremy Allisonac670552005-06-22 17:26:35 -07004597int
Steve French45abc6e2005-06-23 13:42:03 -05004598CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004599{
4600/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4601 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4602 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4603 int rc = 0;
4604 int bytes_returned = 0;
4605 __u16 params, param_offset, offset, byte_count;
4606
Joe Perchesb6b38f72010-04-21 03:50:45 +00004607 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004608SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004609 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004610 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4611 (void **) &pSMBr);
4612 if (rc)
4613 return rc;
4614
4615 params = 4; /* 2 bytes zero followed by info level. */
4616 pSMB->MaxSetupCount = 0;
4617 pSMB->Reserved = 0;
4618 pSMB->Flags = 0;
4619 pSMB->Timeout = 0;
4620 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004621 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4622 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004623 offset = param_offset + params;
4624
4625 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004626 /* BB find exact max SMB PDU from sess structure BB */
4627 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004628 pSMB->SetupCount = 1;
4629 pSMB->Reserved3 = 0;
4630 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4631 byte_count = 1 /* pad */ + params + 12;
4632
4633 pSMB->DataCount = cpu_to_le16(12);
4634 pSMB->ParameterCount = cpu_to_le16(params);
4635 pSMB->TotalDataCount = pSMB->DataCount;
4636 pSMB->TotalParameterCount = pSMB->ParameterCount;
4637 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4638 pSMB->DataOffset = cpu_to_le16(offset);
4639
4640 /* Params. */
4641 pSMB->FileNum = 0;
4642 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4643
4644 /* Data. */
4645 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4646 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4647 pSMB->ClientUnixCap = cpu_to_le64(cap);
4648
4649 pSMB->hdr.smb_buf_length += byte_count;
4650 pSMB->ByteCount = cpu_to_le16(byte_count);
4651
4652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4654 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004655 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004656 } else { /* decode response */
4657 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004658 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004659 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004660 }
4661 cifs_buf_release(pSMB);
4662
4663 if (rc == -EAGAIN)
4664 goto SETFSUnixRetry;
4665
4666 return rc;
4667}
4668
4669
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670
4671int
4672CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004673 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674{
4675/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4676 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4677 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4678 FILE_SYSTEM_POSIX_INFO *response_data;
4679 int rc = 0;
4680 int bytes_returned = 0;
4681 __u16 params, byte_count;
4682
Joe Perchesb6b38f72010-04-21 03:50:45 +00004683 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684QFSPosixRetry:
4685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4686 (void **) &pSMBr);
4687 if (rc)
4688 return rc;
4689
4690 params = 2; /* level */
4691 pSMB->TotalDataCount = 0;
4692 pSMB->DataCount = 0;
4693 pSMB->DataOffset = 0;
4694 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004695 /* BB find exact max SMB PDU from sess structure BB */
4696 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 pSMB->MaxSetupCount = 0;
4698 pSMB->Reserved = 0;
4699 pSMB->Flags = 0;
4700 pSMB->Timeout = 0;
4701 pSMB->Reserved2 = 0;
4702 byte_count = params + 1 /* pad */ ;
4703 pSMB->ParameterCount = cpu_to_le16(params);
4704 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004705 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4706 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 pSMB->SetupCount = 1;
4708 pSMB->Reserved3 = 0;
4709 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4710 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4711 pSMB->hdr.smb_buf_length += byte_count;
4712 pSMB->ByteCount = cpu_to_le16(byte_count);
4713
4714 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4715 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4716 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004717 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 } else { /* decode response */
4719 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4720
4721 if (rc || (pSMBr->ByteCount < 13)) {
4722 rc = -EIO; /* bad smb */
4723 } else {
4724 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4725 response_data =
4726 (FILE_SYSTEM_POSIX_INFO
4727 *) (((char *) &pSMBr->hdr.Protocol) +
4728 data_offset);
4729 FSData->f_bsize =
4730 le32_to_cpu(response_data->BlockSize);
4731 FSData->f_blocks =
4732 le64_to_cpu(response_data->TotalBlocks);
4733 FSData->f_bfree =
4734 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004735 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 FSData->f_bavail = FSData->f_bfree;
4737 } else {
4738 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004739 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 }
Steve French790fe572007-07-07 19:25:05 +00004741 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004743 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004744 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004746 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 }
4748 }
4749 cifs_buf_release(pSMB);
4750
4751 if (rc == -EAGAIN)
4752 goto QFSPosixRetry;
4753
4754 return rc;
4755}
4756
4757
Steve French50c2f752007-07-13 00:33:32 +00004758/* We can not use write of zero bytes trick to
4759 set file size due to need for large file support. Also note that
4760 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 routine which is only needed to work around a sharing violation bug
4762 in Samba which this routine can run into */
4763
4764int
4765CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004766 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004767 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
4769 struct smb_com_transaction2_spi_req *pSMB = NULL;
4770 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4771 struct file_end_of_file_info *parm_data;
4772 int name_len;
4773 int rc = 0;
4774 int bytes_returned = 0;
4775 __u16 params, byte_count, data_count, param_offset, offset;
4776
Joe Perchesb6b38f72010-04-21 03:50:45 +00004777 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778SetEOFRetry:
4779 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4780 (void **) &pSMBr);
4781 if (rc)
4782 return rc;
4783
4784 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4785 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004786 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004787 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 name_len++; /* trailing null */
4789 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004790 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 name_len = strnlen(fileName, PATH_MAX);
4792 name_len++; /* trailing null */
4793 strncpy(pSMB->FileName, fileName, name_len);
4794 }
4795 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004796 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004798 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 pSMB->MaxSetupCount = 0;
4800 pSMB->Reserved = 0;
4801 pSMB->Flags = 0;
4802 pSMB->Timeout = 0;
4803 pSMB->Reserved2 = 0;
4804 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004805 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004807 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004808 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4809 pSMB->InformationLevel =
4810 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4811 else
4812 pSMB->InformationLevel =
4813 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4814 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004817 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 else
4819 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004820 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 }
4822
4823 parm_data =
4824 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4825 offset);
4826 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4827 pSMB->DataOffset = cpu_to_le16(offset);
4828 pSMB->SetupCount = 1;
4829 pSMB->Reserved3 = 0;
4830 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4831 byte_count = 3 /* pad */ + params + data_count;
4832 pSMB->DataCount = cpu_to_le16(data_count);
4833 pSMB->TotalDataCount = pSMB->DataCount;
4834 pSMB->ParameterCount = cpu_to_le16(params);
4835 pSMB->TotalParameterCount = pSMB->ParameterCount;
4836 pSMB->Reserved4 = 0;
4837 pSMB->hdr.smb_buf_length += byte_count;
4838 parm_data->FileSize = cpu_to_le64(size);
4839 pSMB->ByteCount = cpu_to_le16(byte_count);
4840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004842 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004843 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844
4845 cifs_buf_release(pSMB);
4846
4847 if (rc == -EAGAIN)
4848 goto SetEOFRetry;
4849
4850 return rc;
4851}
4852
4853int
Steve French50c2f752007-07-13 00:33:32 +00004854CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004855 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856{
4857 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 char *data_offset;
4859 struct file_end_of_file_info *parm_data;
4860 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 __u16 params, param_offset, offset, byte_count, count;
4862
Joe Perchesb6b38f72010-04-21 03:50:45 +00004863 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4864 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004865 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4866
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 if (rc)
4868 return rc;
4869
4870 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4871 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004872
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 params = 6;
4874 pSMB->MaxSetupCount = 0;
4875 pSMB->Reserved = 0;
4876 pSMB->Flags = 0;
4877 pSMB->Timeout = 0;
4878 pSMB->Reserved2 = 0;
4879 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4880 offset = param_offset + params;
4881
Steve French50c2f752007-07-13 00:33:32 +00004882 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883
4884 count = sizeof(struct file_end_of_file_info);
4885 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004886 /* BB find exact max SMB PDU from sess structure BB */
4887 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 pSMB->SetupCount = 1;
4889 pSMB->Reserved3 = 0;
4890 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4891 byte_count = 3 /* pad */ + params + count;
4892 pSMB->DataCount = cpu_to_le16(count);
4893 pSMB->ParameterCount = cpu_to_le16(params);
4894 pSMB->TotalDataCount = pSMB->DataCount;
4895 pSMB->TotalParameterCount = pSMB->ParameterCount;
4896 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4897 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004898 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4899 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 pSMB->DataOffset = cpu_to_le16(offset);
4901 parm_data->FileSize = cpu_to_le64(size);
4902 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004903 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4905 pSMB->InformationLevel =
4906 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4907 else
4908 pSMB->InformationLevel =
4909 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004910 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4912 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004913 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 else
4915 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004916 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 }
4918 pSMB->Reserved4 = 0;
4919 pSMB->hdr.smb_buf_length += byte_count;
4920 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004921 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004923 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 }
4925
Steve French50c2f752007-07-13 00:33:32 +00004926 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 since file handle passed in no longer valid */
4928
4929 return rc;
4930}
4931
Steve French50c2f752007-07-13 00:33:32 +00004932/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 an open handle, rather than by pathname - this is awkward due to
4934 potential access conflicts on the open, but it is unavoidable for these
4935 old servers since the only other choice is to go from 100 nanosecond DCE
4936 time and resort to the original setpathinfo level which takes the ancient
4937 DOS time format with 2 second granularity */
4938int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004939CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4940 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941{
4942 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 char *data_offset;
4944 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 __u16 params, param_offset, offset, byte_count, count;
4946
Joe Perchesb6b38f72010-04-21 03:50:45 +00004947 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07004948 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4949
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 if (rc)
4951 return rc;
4952
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004953 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4954 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004955
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 params = 6;
4957 pSMB->MaxSetupCount = 0;
4958 pSMB->Reserved = 0;
4959 pSMB->Flags = 0;
4960 pSMB->Timeout = 0;
4961 pSMB->Reserved2 = 0;
4962 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4963 offset = param_offset + params;
4964
Steve French50c2f752007-07-13 00:33:32 +00004965 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966
Steve French26f57362007-08-30 22:09:15 +00004967 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004968 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004969 /* BB find max SMB PDU from sess */
4970 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004971 pSMB->SetupCount = 1;
4972 pSMB->Reserved3 = 0;
4973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4974 byte_count = 3 /* pad */ + params + count;
4975 pSMB->DataCount = cpu_to_le16(count);
4976 pSMB->ParameterCount = cpu_to_le16(params);
4977 pSMB->TotalDataCount = pSMB->DataCount;
4978 pSMB->TotalParameterCount = pSMB->ParameterCount;
4979 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4980 pSMB->DataOffset = cpu_to_le16(offset);
4981 pSMB->Fid = fid;
4982 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4983 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4984 else
4985 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4986 pSMB->Reserved4 = 0;
4987 pSMB->hdr.smb_buf_length += byte_count;
4988 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004989 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004990 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004991 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004992 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993
Steve French50c2f752007-07-13 00:33:32 +00004994 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 since file handle passed in no longer valid */
4996
4997 return rc;
4998}
4999
Jeff Layton6d22f092008-09-23 11:48:35 -04005000int
5001CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5002 bool delete_file, __u16 fid, __u32 pid_of_opener)
5003{
5004 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5005 char *data_offset;
5006 int rc = 0;
5007 __u16 params, param_offset, offset, byte_count, count;
5008
Joe Perchesb6b38f72010-04-21 03:50:45 +00005009 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005010 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5011
5012 if (rc)
5013 return rc;
5014
5015 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5016 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5017
5018 params = 6;
5019 pSMB->MaxSetupCount = 0;
5020 pSMB->Reserved = 0;
5021 pSMB->Flags = 0;
5022 pSMB->Timeout = 0;
5023 pSMB->Reserved2 = 0;
5024 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5025 offset = param_offset + params;
5026
5027 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5028
5029 count = 1;
5030 pSMB->MaxParameterCount = cpu_to_le16(2);
5031 /* BB find max SMB PDU from sess */
5032 pSMB->MaxDataCount = cpu_to_le16(1000);
5033 pSMB->SetupCount = 1;
5034 pSMB->Reserved3 = 0;
5035 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5036 byte_count = 3 /* pad */ + params + count;
5037 pSMB->DataCount = cpu_to_le16(count);
5038 pSMB->ParameterCount = cpu_to_le16(params);
5039 pSMB->TotalDataCount = pSMB->DataCount;
5040 pSMB->TotalParameterCount = pSMB->ParameterCount;
5041 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5042 pSMB->DataOffset = cpu_to_le16(offset);
5043 pSMB->Fid = fid;
5044 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5045 pSMB->Reserved4 = 0;
5046 pSMB->hdr.smb_buf_length += byte_count;
5047 pSMB->ByteCount = cpu_to_le16(byte_count);
5048 *data_offset = delete_file ? 1 : 0;
5049 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5050 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005051 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005052
5053 return rc;
5054}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055
5056int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005057CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5058 const char *fileName, const FILE_BASIC_INFO *data,
5059 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060{
5061 TRANSACTION2_SPI_REQ *pSMB = NULL;
5062 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5063 int name_len;
5064 int rc = 0;
5065 int bytes_returned = 0;
5066 char *data_offset;
5067 __u16 params, param_offset, offset, byte_count, count;
5068
Joe Perchesb6b38f72010-04-21 03:50:45 +00005069 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070
5071SetTimesRetry:
5072 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5073 (void **) &pSMBr);
5074 if (rc)
5075 return rc;
5076
5077 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5078 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005079 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005080 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 name_len++; /* trailing null */
5082 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005083 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 name_len = strnlen(fileName, PATH_MAX);
5085 name_len++; /* trailing null */
5086 strncpy(pSMB->FileName, fileName, name_len);
5087 }
5088
5089 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005090 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005092 /* BB find max SMB PDU from sess structure BB */
5093 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 pSMB->MaxSetupCount = 0;
5095 pSMB->Reserved = 0;
5096 pSMB->Flags = 0;
5097 pSMB->Timeout = 0;
5098 pSMB->Reserved2 = 0;
5099 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005100 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 offset = param_offset + params;
5102 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5103 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5104 pSMB->DataOffset = cpu_to_le16(offset);
5105 pSMB->SetupCount = 1;
5106 pSMB->Reserved3 = 0;
5107 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5108 byte_count = 3 /* pad */ + params + count;
5109
5110 pSMB->DataCount = cpu_to_le16(count);
5111 pSMB->ParameterCount = cpu_to_le16(params);
5112 pSMB->TotalDataCount = pSMB->DataCount;
5113 pSMB->TotalParameterCount = pSMB->ParameterCount;
5114 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5115 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5116 else
5117 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5118 pSMB->Reserved4 = 0;
5119 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005120 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 pSMB->ByteCount = cpu_to_le16(byte_count);
5122 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5123 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005124 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005125 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126
5127 cifs_buf_release(pSMB);
5128
5129 if (rc == -EAGAIN)
5130 goto SetTimesRetry;
5131
5132 return rc;
5133}
5134
5135/* Can not be used to set time stamps yet (due to old DOS time format) */
5136/* Can be used to set attributes */
5137#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5138 handling it anyway and NT4 was what we thought it would be needed for
5139 Do not delete it until we prove whether needed for Win9x though */
5140int
5141CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5142 __u16 dos_attrs, const struct nls_table *nls_codepage)
5143{
5144 SETATTR_REQ *pSMB = NULL;
5145 SETATTR_RSP *pSMBr = NULL;
5146 int rc = 0;
5147 int bytes_returned;
5148 int name_len;
5149
Joe Perchesb6b38f72010-04-21 03:50:45 +00005150 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151
5152SetAttrLgcyRetry:
5153 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5154 (void **) &pSMBr);
5155 if (rc)
5156 return rc;
5157
5158 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5159 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005160 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 PATH_MAX, nls_codepage);
5162 name_len++; /* trailing null */
5163 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005164 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 name_len = strnlen(fileName, PATH_MAX);
5166 name_len++; /* trailing null */
5167 strncpy(pSMB->fileName, fileName, name_len);
5168 }
5169 pSMB->attr = cpu_to_le16(dos_attrs);
5170 pSMB->BufferFormat = 0x04;
5171 pSMB->hdr.smb_buf_length += name_len + 1;
5172 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5173 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5174 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005175 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005176 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005177
5178 cifs_buf_release(pSMB);
5179
5180 if (rc == -EAGAIN)
5181 goto SetAttrLgcyRetry;
5182
5183 return rc;
5184}
5185#endif /* temporarily unneeded SetAttr legacy function */
5186
Jeff Layton654cf142009-07-09 20:02:49 -04005187static void
5188cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5189 const struct cifs_unix_set_info_args *args)
5190{
5191 u64 mode = args->mode;
5192
5193 /*
5194 * Samba server ignores set of file size to zero due to bugs in some
5195 * older clients, but we should be precise - we use SetFileSize to
5196 * set file size and do not want to truncate file size to zero
5197 * accidently as happened on one Samba server beta by putting
5198 * zero instead of -1 here
5199 */
5200 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5201 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5202 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5203 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5204 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5205 data_offset->Uid = cpu_to_le64(args->uid);
5206 data_offset->Gid = cpu_to_le64(args->gid);
5207 /* better to leave device as zero when it is */
5208 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5209 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5210 data_offset->Permissions = cpu_to_le64(mode);
5211
5212 if (S_ISREG(mode))
5213 data_offset->Type = cpu_to_le32(UNIX_FILE);
5214 else if (S_ISDIR(mode))
5215 data_offset->Type = cpu_to_le32(UNIX_DIR);
5216 else if (S_ISLNK(mode))
5217 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5218 else if (S_ISCHR(mode))
5219 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5220 else if (S_ISBLK(mode))
5221 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5222 else if (S_ISFIFO(mode))
5223 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5224 else if (S_ISSOCK(mode))
5225 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5226}
5227
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005229CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5230 const struct cifs_unix_set_info_args *args,
5231 u16 fid, u32 pid_of_opener)
5232{
5233 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5234 FILE_UNIX_BASIC_INFO *data_offset;
5235 int rc = 0;
5236 u16 params, param_offset, offset, byte_count, count;
5237
Joe Perchesb6b38f72010-04-21 03:50:45 +00005238 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005239 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5240
5241 if (rc)
5242 return rc;
5243
5244 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5245 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5246
5247 params = 6;
5248 pSMB->MaxSetupCount = 0;
5249 pSMB->Reserved = 0;
5250 pSMB->Flags = 0;
5251 pSMB->Timeout = 0;
5252 pSMB->Reserved2 = 0;
5253 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5254 offset = param_offset + params;
5255
5256 data_offset = (FILE_UNIX_BASIC_INFO *)
5257 ((char *)(&pSMB->hdr.Protocol) + offset);
5258 count = sizeof(FILE_UNIX_BASIC_INFO);
5259
5260 pSMB->MaxParameterCount = cpu_to_le16(2);
5261 /* BB find max SMB PDU from sess */
5262 pSMB->MaxDataCount = cpu_to_le16(1000);
5263 pSMB->SetupCount = 1;
5264 pSMB->Reserved3 = 0;
5265 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5266 byte_count = 3 /* pad */ + params + count;
5267 pSMB->DataCount = cpu_to_le16(count);
5268 pSMB->ParameterCount = cpu_to_le16(params);
5269 pSMB->TotalDataCount = pSMB->DataCount;
5270 pSMB->TotalParameterCount = pSMB->ParameterCount;
5271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5272 pSMB->DataOffset = cpu_to_le16(offset);
5273 pSMB->Fid = fid;
5274 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5275 pSMB->Reserved4 = 0;
5276 pSMB->hdr.smb_buf_length += byte_count;
5277 pSMB->ByteCount = cpu_to_le16(byte_count);
5278
5279 cifs_fill_unix_set_info(data_offset, args);
5280
5281 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5282 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005283 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005284
5285 /* Note: On -EAGAIN error only caller can retry on handle based calls
5286 since file handle passed in no longer valid */
5287
5288 return rc;
5289}
5290
5291int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005292CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5293 const struct cifs_unix_set_info_args *args,
5294 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295{
5296 TRANSACTION2_SPI_REQ *pSMB = NULL;
5297 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5298 int name_len;
5299 int rc = 0;
5300 int bytes_returned = 0;
5301 FILE_UNIX_BASIC_INFO *data_offset;
5302 __u16 params, param_offset, offset, count, byte_count;
5303
Joe Perchesb6b38f72010-04-21 03:50:45 +00005304 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305setPermsRetry:
5306 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5307 (void **) &pSMBr);
5308 if (rc)
5309 return rc;
5310
5311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5312 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005313 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005314 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 name_len++; /* trailing null */
5316 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005317 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 name_len = strnlen(fileName, PATH_MAX);
5319 name_len++; /* trailing null */
5320 strncpy(pSMB->FileName, fileName, name_len);
5321 }
5322
5323 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005324 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005326 /* BB find max SMB PDU from sess structure BB */
5327 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 pSMB->MaxSetupCount = 0;
5329 pSMB->Reserved = 0;
5330 pSMB->Flags = 0;
5331 pSMB->Timeout = 0;
5332 pSMB->Reserved2 = 0;
5333 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005334 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 offset = param_offset + params;
5336 data_offset =
5337 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5338 offset);
5339 memset(data_offset, 0, count);
5340 pSMB->DataOffset = cpu_to_le16(offset);
5341 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5342 pSMB->SetupCount = 1;
5343 pSMB->Reserved3 = 0;
5344 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5345 byte_count = 3 /* pad */ + params + count;
5346 pSMB->ParameterCount = cpu_to_le16(params);
5347 pSMB->DataCount = cpu_to_le16(count);
5348 pSMB->TotalParameterCount = pSMB->ParameterCount;
5349 pSMB->TotalDataCount = pSMB->DataCount;
5350 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5351 pSMB->Reserved4 = 0;
5352 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005353
Jeff Layton654cf142009-07-09 20:02:49 -04005354 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355
5356 pSMB->ByteCount = cpu_to_le16(byte_count);
5357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005359 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005360 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361
Steve French0d817bc2008-05-22 02:02:03 +00005362 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005363 if (rc == -EAGAIN)
5364 goto setPermsRetry;
5365 return rc;
5366}
5367
Steve French50c2f752007-07-13 00:33:32 +00005368int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005369 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005370 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005371 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372{
5373 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005374 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5375 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005376 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 int bytes_returned;
5378
Joe Perchesb6b38f72010-04-21 03:50:45 +00005379 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005381 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 if (rc)
5383 return rc;
5384
5385 pSMB->TotalParameterCount = 0 ;
5386 pSMB->TotalDataCount = 0;
5387 pSMB->MaxParameterCount = cpu_to_le32(2);
5388 /* BB find exact data count max from sess structure BB */
5389 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005390/* BB VERIFY verify which is correct for above BB */
5391 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5392 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5393
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 pSMB->MaxSetupCount = 4;
5395 pSMB->Reserved = 0;
5396 pSMB->ParameterOffset = 0;
5397 pSMB->DataCount = 0;
5398 pSMB->DataOffset = 0;
5399 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5400 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5401 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005402 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5404 pSMB->Reserved2 = 0;
5405 pSMB->CompletionFilter = cpu_to_le32(filter);
5406 pSMB->Fid = netfid; /* file handle always le */
5407 pSMB->ByteCount = 0;
5408
5409 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005410 (struct smb_hdr *)pSMBr, &bytes_returned,
5411 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005413 cFYI(1, "Error in Notify = %d", rc);
Steve Frenchff5dbd92005-08-24 17:10:36 -07005414 } else {
5415 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005416 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005417 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005418 sizeof(struct dir_notify_req),
5419 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005420 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005421 dnotify_req->Pid = pSMB->hdr.Pid;
5422 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5423 dnotify_req->Mid = pSMB->hdr.Mid;
5424 dnotify_req->Tid = pSMB->hdr.Tid;
5425 dnotify_req->Uid = pSMB->hdr.Uid;
5426 dnotify_req->netfid = netfid;
5427 dnotify_req->pfile = pfile;
5428 dnotify_req->filter = filter;
5429 dnotify_req->multishot = multishot;
5430 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005431 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005432 &GlobalDnotifyReqList);
5433 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005434 } else
Steve French47c786e2005-10-11 20:03:18 -07005435 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005436 }
5437 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005438 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439}
Jeff Layton31c05192010-02-10 16:18:26 -05005440
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005442/*
5443 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5444 * function used by listxattr and getxattr type calls. When ea_name is set,
5445 * it looks for that attribute name and stuffs that value into the EAData
5446 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5447 * buffer. In both cases, the return value is either the length of the
5448 * resulting data or a negative error code. If EAData is a NULL pointer then
5449 * the data isn't copied to it, but the length is returned.
5450 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451ssize_t
5452CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005453 const unsigned char *searchName, const unsigned char *ea_name,
5454 char *EAData, size_t buf_size,
5455 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456{
5457 /* BB assumes one setup word */
5458 TRANSACTION2_QPI_REQ *pSMB = NULL;
5459 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5460 int rc = 0;
5461 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005462 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005463 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005464 struct fea *temp_fea;
5465 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005466 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005467 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468
Joe Perchesb6b38f72010-04-21 03:50:45 +00005469 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470QAllEAsRetry:
5471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5472 (void **) &pSMBr);
5473 if (rc)
5474 return rc;
5475
5476 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005477 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005478 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005479 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005480 list_len++; /* trailing null */
5481 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005483 list_len = strnlen(searchName, PATH_MAX);
5484 list_len++; /* trailing null */
5485 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 }
5487
Jeff Layton6e462b92010-02-10 16:18:26 -05005488 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 pSMB->TotalDataCount = 0;
5490 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005491 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005492 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 pSMB->MaxSetupCount = 0;
5494 pSMB->Reserved = 0;
5495 pSMB->Flags = 0;
5496 pSMB->Timeout = 0;
5497 pSMB->Reserved2 = 0;
5498 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005499 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 pSMB->DataCount = 0;
5501 pSMB->DataOffset = 0;
5502 pSMB->SetupCount = 1;
5503 pSMB->Reserved3 = 0;
5504 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5505 byte_count = params + 1 /* pad */ ;
5506 pSMB->TotalParameterCount = cpu_to_le16(params);
5507 pSMB->ParameterCount = pSMB->TotalParameterCount;
5508 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5509 pSMB->Reserved4 = 0;
5510 pSMB->hdr.smb_buf_length += byte_count;
5511 pSMB->ByteCount = cpu_to_le16(byte_count);
5512
5513 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5514 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5515 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005516 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005517 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005519
5520
5521 /* BB also check enough total bytes returned */
5522 /* BB we need to improve the validity checking
5523 of these trans2 responses */
5524
5525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5526 if (rc || (pSMBr->ByteCount < 4)) {
5527 rc = -EIO; /* bad smb */
5528 goto QAllEAsOut;
5529 }
5530
5531 /* check that length of list is not more than bcc */
5532 /* check that each entry does not go beyond length
5533 of list */
5534 /* check that each element of each entry does not
5535 go beyond end of list */
5536 /* validate_trans2_offsets() */
5537 /* BB check if start of smb + data_offset > &bcc+ bcc */
5538
5539 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5540 ea_response_data = (struct fealist *)
5541 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5542
Jeff Layton6e462b92010-02-10 16:18:26 -05005543 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005544 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005545 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005546 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005547 goto QAllEAsOut;
5548 }
5549
Jeff Layton0cd126b2010-02-10 16:18:26 -05005550 /* make sure list_len doesn't go past end of SMB */
5551 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5552 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005553 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005554 rc = -EIO;
5555 goto QAllEAsOut;
5556 }
5557
Jeff Laytonf0d38682010-02-10 16:18:26 -05005558 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005559 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005560 temp_fea = ea_response_data->list;
5561 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005562 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005563 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005564 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005565
Jeff Layton6e462b92010-02-10 16:18:26 -05005566 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005567 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005568 /* make sure we can read name_len and value_len */
5569 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005570 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005571 rc = -EIO;
5572 goto QAllEAsOut;
5573 }
5574
5575 name_len = temp_fea->name_len;
5576 value_len = le16_to_cpu(temp_fea->value_len);
5577 list_len -= name_len + 1 + value_len;
5578 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005579 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005580 rc = -EIO;
5581 goto QAllEAsOut;
5582 }
5583
Jeff Layton31c05192010-02-10 16:18:26 -05005584 if (ea_name) {
5585 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5586 temp_ptr += name_len + 1;
5587 rc = value_len;
5588 if (buf_size == 0)
5589 goto QAllEAsOut;
5590 if ((size_t)value_len > buf_size) {
5591 rc = -ERANGE;
5592 goto QAllEAsOut;
5593 }
5594 memcpy(EAData, temp_ptr, value_len);
5595 goto QAllEAsOut;
5596 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005597 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005598 /* account for prefix user. and trailing null */
5599 rc += (5 + 1 + name_len);
5600 if (rc < (int) buf_size) {
5601 memcpy(EAData, "user.", 5);
5602 EAData += 5;
5603 memcpy(EAData, temp_ptr, name_len);
5604 EAData += name_len;
5605 /* null terminate name */
5606 *EAData = 0;
5607 ++EAData;
5608 } else if (buf_size == 0) {
5609 /* skip copy - calc size only */
5610 } else {
5611 /* stop before overrun buffer */
5612 rc = -ERANGE;
5613 break;
5614 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005615 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005616 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005617 temp_fea = (struct fea *)temp_ptr;
5618 }
5619
Jeff Layton31c05192010-02-10 16:18:26 -05005620 /* didn't find the named attribute */
5621 if (ea_name)
5622 rc = -ENODATA;
5623
Jeff Laytonf0d38682010-02-10 16:18:26 -05005624QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005625 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 if (rc == -EAGAIN)
5627 goto QAllEAsRetry;
5628
5629 return (ssize_t)rc;
5630}
5631
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632int
5633CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005634 const char *ea_name, const void *ea_value,
5635 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5636 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637{
5638 struct smb_com_transaction2_spi_req *pSMB = NULL;
5639 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5640 struct fealist *parm_data;
5641 int name_len;
5642 int rc = 0;
5643 int bytes_returned = 0;
5644 __u16 params, param_offset, byte_count, offset, count;
5645
Joe Perchesb6b38f72010-04-21 03:50:45 +00005646 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647SetEARetry:
5648 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5649 (void **) &pSMBr);
5650 if (rc)
5651 return rc;
5652
5653 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5654 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005655 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005656 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 name_len++; /* trailing null */
5658 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005659 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005660 name_len = strnlen(fileName, PATH_MAX);
5661 name_len++; /* trailing null */
5662 strncpy(pSMB->FileName, fileName, name_len);
5663 }
5664
5665 params = 6 + name_len;
5666
5667 /* done calculating parms using name_len of file name,
5668 now use name_len to calculate length of ea name
5669 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005670 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005671 name_len = 0;
5672 else
Steve French50c2f752007-07-13 00:33:32 +00005673 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005674
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00005675 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005677 /* BB find max SMB PDU from sess */
5678 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005679 pSMB->MaxSetupCount = 0;
5680 pSMB->Reserved = 0;
5681 pSMB->Flags = 0;
5682 pSMB->Timeout = 0;
5683 pSMB->Reserved2 = 0;
5684 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005685 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 offset = param_offset + params;
5687 pSMB->InformationLevel =
5688 cpu_to_le16(SMB_SET_FILE_EA);
5689
5690 parm_data =
5691 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5692 offset);
5693 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5694 pSMB->DataOffset = cpu_to_le16(offset);
5695 pSMB->SetupCount = 1;
5696 pSMB->Reserved3 = 0;
5697 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5698 byte_count = 3 /* pad */ + params + count;
5699 pSMB->DataCount = cpu_to_le16(count);
5700 parm_data->list_len = cpu_to_le32(count);
5701 parm_data->list[0].EA_flags = 0;
5702 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005703 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005705 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005706 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707 parm_data->list[0].name[name_len] = 0;
5708 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5709 /* caller ensures that ea_value_len is less than 64K but
5710 we need to ensure that it fits within the smb */
5711
Steve French50c2f752007-07-13 00:33:32 +00005712 /*BB add length check to see if it would fit in
5713 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005714 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5715 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005716 memcpy(parm_data->list[0].name+name_len+1,
5717 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718
5719 pSMB->TotalDataCount = pSMB->DataCount;
5720 pSMB->ParameterCount = cpu_to_le16(params);
5721 pSMB->TotalParameterCount = pSMB->ParameterCount;
5722 pSMB->Reserved4 = 0;
5723 pSMB->hdr.smb_buf_length += byte_count;
5724 pSMB->ByteCount = cpu_to_le16(byte_count);
5725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005727 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005728 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005729
5730 cifs_buf_release(pSMB);
5731
5732 if (rc == -EAGAIN)
5733 goto SetEARetry;
5734
5735 return rc;
5736}
5737
5738#endif