blob: 13c854e4107351d211924725259e5b14588e8179 [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;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500606 if (server->secType == Kerberos) {
607 if (!server->sec_kerberos &&
608 !server->sec_mskerberos)
609 rc = -EOPNOTSUPP;
610 } else if (server->secType == RawNTLMSSP) {
611 if (!server->sec_ntlmssp)
612 rc = -EOPNOTSUPP;
613 } else
614 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
Steve French254e55e2006-06-04 05:53:15 +0000616 } else
617 server->capabilities &= ~CAP_EXTENDED_SECURITY;
618
Steve French6344a422006-06-12 04:18:35 +0000619#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000620signing_check:
Steve French6344a422006-06-12 04:18:35 +0000621#endif
Steve French762e5ab2007-06-28 18:41:42 +0000622 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
623 /* MUST_SIGN already includes the MAY_SIGN FLAG
624 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000625 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000626 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000627 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000628 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000629 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000630 rc = -EOPNOTSUPP;
631 }
Steve French50c2f752007-07-13 00:33:32 +0000632 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000633 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000634 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
635 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000637 if ((server->secMode &
638 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000639 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000640 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000641 } else
642 server->secMode |= SECMODE_SIGN_REQUIRED;
643 } else {
644 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000645 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000646 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000647 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
Steve French50c2f752007-07-13 00:33:32 +0000649
650neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700651 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000652
Joe Perchesb6b38f72010-04-21 03:50:45 +0000653 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return rc;
655}
656
657int
658CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
659{
660 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662
Joe Perchesb6b38f72010-04-21 03:50:45 +0000663 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500664
665 /* BB: do we need to check this? These should never be NULL. */
666 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
667 return -EIO;
668
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500670 * No need to return error on this operation if tid invalidated and
671 * closed on server already e.g. due to tcp session crashing. Also,
672 * the tcon is no longer on the list, so no need to take lock before
673 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 */
Steve French268875b2009-06-25 00:29:21 +0000675 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000676 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Steve French50c2f752007-07-13 00:33:32 +0000678 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700679 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500680 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return rc;
Steve French133672e2007-11-13 22:41:37 +0000682
683 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000685 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Steve French50c2f752007-07-13 00:33:32 +0000687 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500688 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (rc == -EAGAIN)
690 rc = 0;
691
692 return rc;
693}
694
695int
696CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
697{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 LOGOFF_ANDX_REQ *pSMB;
699 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Joe Perchesb6b38f72010-04-21 03:50:45 +0000701 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500702
703 /*
704 * BB: do we need to check validity of ses and server? They should
705 * always be valid since we have an active reference. If not, that
706 * should probably be a BUG()
707 */
708 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 return -EIO;
710
Steve Frenchd7b619c2010-02-25 05:36:46 +0000711 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000712 if (ses->need_reconnect)
713 goto session_already_dead; /* no need to send SMBlogoff if uid
714 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
716 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000717 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return rc;
719 }
720
Steve French3b795212008-11-13 19:45:32 +0000721 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700722
Steve French3b795212008-11-13 19:45:32 +0000723 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
725 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 pSMB->hdr.Uid = ses->Suid;
728
729 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000730 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000731session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000732 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000735 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 error */
737 if (rc == -EAGAIN)
738 rc = 0;
739 return rc;
740}
741
742int
Steve French2d785a52007-07-15 01:48:57 +0000743CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
744 __u16 type, const struct nls_table *nls_codepage, int remap)
745{
746 TRANSACTION2_SPI_REQ *pSMB = NULL;
747 TRANSACTION2_SPI_RSP *pSMBr = NULL;
748 struct unlink_psx_rq *pRqD;
749 int name_len;
750 int rc = 0;
751 int bytes_returned = 0;
752 __u16 params, param_offset, offset, byte_count;
753
Joe Perchesb6b38f72010-04-21 03:50:45 +0000754 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000755PsxDelete:
756 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
757 (void **) &pSMBr);
758 if (rc)
759 return rc;
760
761 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
762 name_len =
763 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
764 PATH_MAX, nls_codepage, remap);
765 name_len++; /* trailing null */
766 name_len *= 2;
767 } else { /* BB add path length overrun check */
768 name_len = strnlen(fileName, PATH_MAX);
769 name_len++; /* trailing null */
770 strncpy(pSMB->FileName, fileName, name_len);
771 }
772
773 params = 6 + name_len;
774 pSMB->MaxParameterCount = cpu_to_le16(2);
775 pSMB->MaxDataCount = 0; /* BB double check this with jra */
776 pSMB->MaxSetupCount = 0;
777 pSMB->Reserved = 0;
778 pSMB->Flags = 0;
779 pSMB->Timeout = 0;
780 pSMB->Reserved2 = 0;
781 param_offset = offsetof(struct smb_com_transaction2_spi_req,
782 InformationLevel) - 4;
783 offset = param_offset + params;
784
785 /* Setup pointer to Request Data (inode type) */
786 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
787 pRqD->type = cpu_to_le16(type);
788 pSMB->ParameterOffset = cpu_to_le16(param_offset);
789 pSMB->DataOffset = cpu_to_le16(offset);
790 pSMB->SetupCount = 1;
791 pSMB->Reserved3 = 0;
792 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
793 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
794
795 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
796 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
797 pSMB->ParameterCount = cpu_to_le16(params);
798 pSMB->TotalParameterCount = pSMB->ParameterCount;
799 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
800 pSMB->Reserved4 = 0;
801 pSMB->hdr.smb_buf_length += byte_count;
802 pSMB->ByteCount = cpu_to_le16(byte_count);
803 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
804 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000805 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000806 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000807 cifs_buf_release(pSMB);
808
809 cifs_stats_inc(&tcon->num_deletes);
810
811 if (rc == -EAGAIN)
812 goto PsxDelete;
813
814 return rc;
815}
816
817int
Steve French737b7582005-04-28 22:41:06 -0700818CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
821 DELETE_FILE_REQ *pSMB = NULL;
822 DELETE_FILE_RSP *pSMBr = NULL;
823 int rc = 0;
824 int bytes_returned;
825 int name_len;
826
827DelFileRetry:
828 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
829 (void **) &pSMBr);
830 if (rc)
831 return rc;
832
833 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
834 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000835 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700836 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 name_len++; /* trailing null */
838 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700839 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 name_len = strnlen(fileName, PATH_MAX);
841 name_len++; /* trailing null */
842 strncpy(pSMB->fileName, fileName, name_len);
843 }
844 pSMB->SearchAttributes =
845 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
846 pSMB->BufferFormat = 0x04;
847 pSMB->hdr.smb_buf_length += name_len + 1;
848 pSMB->ByteCount = cpu_to_le16(name_len + 1);
849 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
850 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700851 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000852 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000853 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855 cifs_buf_release(pSMB);
856 if (rc == -EAGAIN)
857 goto DelFileRetry;
858
859 return rc;
860}
861
862int
Steve French50c2f752007-07-13 00:33:32 +0000863CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700864 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865{
866 DELETE_DIRECTORY_REQ *pSMB = NULL;
867 DELETE_DIRECTORY_RSP *pSMBr = NULL;
868 int rc = 0;
869 int bytes_returned;
870 int name_len;
871
Joe Perchesb6b38f72010-04-21 03:50:45 +0000872 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873RmDirRetry:
874 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
875 (void **) &pSMBr);
876 if (rc)
877 return rc;
878
879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700880 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
881 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 name_len++; /* trailing null */
883 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700884 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 name_len = strnlen(dirName, PATH_MAX);
886 name_len++; /* trailing null */
887 strncpy(pSMB->DirName, dirName, name_len);
888 }
889
890 pSMB->BufferFormat = 0x04;
891 pSMB->hdr.smb_buf_length += name_len + 1;
892 pSMB->ByteCount = cpu_to_le16(name_len + 1);
893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700895 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000896 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000897 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
899 cifs_buf_release(pSMB);
900 if (rc == -EAGAIN)
901 goto RmDirRetry;
902 return rc;
903}
904
905int
906CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700907 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
909 int rc = 0;
910 CREATE_DIRECTORY_REQ *pSMB = NULL;
911 CREATE_DIRECTORY_RSP *pSMBr = NULL;
912 int bytes_returned;
913 int name_len;
914
Joe Perchesb6b38f72010-04-21 03:50:45 +0000915 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916MkDirRetry:
917 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
918 (void **) &pSMBr);
919 if (rc)
920 return rc;
921
922 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000923 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700924 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 name_len++; /* trailing null */
926 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700927 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 name_len = strnlen(name, PATH_MAX);
929 name_len++; /* trailing null */
930 strncpy(pSMB->DirName, name, name_len);
931 }
932
933 pSMB->BufferFormat = 0x04;
934 pSMB->hdr.smb_buf_length += name_len + 1;
935 pSMB->ByteCount = cpu_to_le16(name_len + 1);
936 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
937 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700938 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000939 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000940 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700941
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 cifs_buf_release(pSMB);
943 if (rc == -EAGAIN)
944 goto MkDirRetry;
945 return rc;
946}
947
Steve French2dd29d32007-04-23 22:07:35 +0000948int
949CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000950 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000951 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000952 const struct nls_table *nls_codepage, int remap)
953{
954 TRANSACTION2_SPI_REQ *pSMB = NULL;
955 TRANSACTION2_SPI_RSP *pSMBr = NULL;
956 int name_len;
957 int rc = 0;
958 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +0000959 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +0000960 OPEN_PSX_REQ *pdata;
961 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +0000962
Joe Perchesb6b38f72010-04-21 03:50:45 +0000963 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +0000964PsxCreat:
965 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
966 (void **) &pSMBr);
967 if (rc)
968 return rc;
969
970 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
971 name_len =
972 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
973 PATH_MAX, nls_codepage, remap);
974 name_len++; /* trailing null */
975 name_len *= 2;
976 } else { /* BB improve the check for buffer overruns BB */
977 name_len = strnlen(name, PATH_MAX);
978 name_len++; /* trailing null */
979 strncpy(pSMB->FileName, name, name_len);
980 }
981
982 params = 6 + name_len;
983 count = sizeof(OPEN_PSX_REQ);
984 pSMB->MaxParameterCount = cpu_to_le16(2);
985 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
986 pSMB->MaxSetupCount = 0;
987 pSMB->Reserved = 0;
988 pSMB->Flags = 0;
989 pSMB->Timeout = 0;
990 pSMB->Reserved2 = 0;
991 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000992 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000993 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +0000994 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000995 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +0000996 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000997 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000998 pdata->OpenFlags = cpu_to_le32(*pOplock);
999 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1000 pSMB->DataOffset = cpu_to_le16(offset);
1001 pSMB->SetupCount = 1;
1002 pSMB->Reserved3 = 0;
1003 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1004 byte_count = 3 /* pad */ + params + count;
1005
1006 pSMB->DataCount = cpu_to_le16(count);
1007 pSMB->ParameterCount = cpu_to_le16(params);
1008 pSMB->TotalDataCount = pSMB->DataCount;
1009 pSMB->TotalParameterCount = pSMB->ParameterCount;
1010 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1011 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001012 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001013 pSMB->ByteCount = cpu_to_le16(byte_count);
1014 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1015 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1016 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001017 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001018 goto psx_create_err;
1019 }
1020
Joe Perchesb6b38f72010-04-21 03:50:45 +00001021 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001022 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1023
1024 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1025 rc = -EIO; /* bad smb */
1026 goto psx_create_err;
1027 }
1028
1029 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001030 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001031 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001032
Steve French2dd29d32007-04-23 22:07:35 +00001033 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001034 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001035 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1036 /* Let caller know file was created so we can set the mode. */
1037 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001038 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001039 *pOplock |= CIFS_CREATE_ACTION;
1040 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001041 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1042 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001043 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001044 } else {
Steve French790fe572007-07-07 19:25:05 +00001045 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001046 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001047 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001048 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001049 goto psx_create_err;
1050 }
Steve French50c2f752007-07-13 00:33:32 +00001051 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001052 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001053 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001054 }
Steve French2dd29d32007-04-23 22:07:35 +00001055
1056psx_create_err:
1057 cifs_buf_release(pSMB);
1058
Steve French65bc98b2009-07-10 15:27:25 +00001059 if (posix_flags & SMB_O_DIRECTORY)
1060 cifs_stats_inc(&tcon->num_posixmkdirs);
1061 else
1062 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001063
1064 if (rc == -EAGAIN)
1065 goto PsxCreat;
1066
Steve French50c2f752007-07-13 00:33:32 +00001067 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001068}
1069
Steve Frencha9d02ad2005-08-24 23:06:05 -07001070static __u16 convert_disposition(int disposition)
1071{
1072 __u16 ofun = 0;
1073
1074 switch (disposition) {
1075 case FILE_SUPERSEDE:
1076 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1077 break;
1078 case FILE_OPEN:
1079 ofun = SMBOPEN_OAPPEND;
1080 break;
1081 case FILE_CREATE:
1082 ofun = SMBOPEN_OCREATE;
1083 break;
1084 case FILE_OPEN_IF:
1085 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1086 break;
1087 case FILE_OVERWRITE:
1088 ofun = SMBOPEN_OTRUNC;
1089 break;
1090 case FILE_OVERWRITE_IF:
1091 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1092 break;
1093 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001094 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001095 ofun = SMBOPEN_OAPPEND; /* regular open */
1096 }
1097 return ofun;
1098}
1099
Jeff Layton35fc37d2008-05-14 10:22:03 -07001100static int
1101access_flags_to_smbopen_mode(const int access_flags)
1102{
1103 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1104
1105 if (masked_flags == GENERIC_READ)
1106 return SMBOPEN_READ;
1107 else if (masked_flags == GENERIC_WRITE)
1108 return SMBOPEN_WRITE;
1109
1110 /* just go for read/write */
1111 return SMBOPEN_READWRITE;
1112}
1113
Steve Frencha9d02ad2005-08-24 23:06:05 -07001114int
1115SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1116 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001117 const int access_flags, const int create_options, __u16 *netfid,
1118 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001119 const struct nls_table *nls_codepage, int remap)
1120{
1121 int rc = -EACCES;
1122 OPENX_REQ *pSMB = NULL;
1123 OPENX_RSP *pSMBr = NULL;
1124 int bytes_returned;
1125 int name_len;
1126 __u16 count;
1127
1128OldOpenRetry:
1129 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1130 (void **) &pSMBr);
1131 if (rc)
1132 return rc;
1133
1134 pSMB->AndXCommand = 0xFF; /* none */
1135
1136 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1137 count = 1; /* account for one byte pad to word boundary */
1138 name_len =
1139 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1140 fileName, PATH_MAX, nls_codepage, remap);
1141 name_len++; /* trailing null */
1142 name_len *= 2;
1143 } else { /* BB improve check for buffer overruns BB */
1144 count = 0; /* no pad */
1145 name_len = strnlen(fileName, PATH_MAX);
1146 name_len++; /* trailing null */
1147 strncpy(pSMB->fileName, fileName, name_len);
1148 }
1149 if (*pOplock & REQ_OPLOCK)
1150 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001151 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001152 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001153
Steve Frencha9d02ad2005-08-24 23:06:05 -07001154 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001155 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1157 /* set file as system file if special file such
1158 as fifo and server expecting SFU style and
1159 no Unix extensions */
1160
Steve French790fe572007-07-07 19:25:05 +00001161 if (create_options & CREATE_OPTION_SPECIAL)
1162 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001163 else /* BB FIXME BB */
1164 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001165
Jeff Layton67750fb2008-05-09 22:28:02 +00001166 if (create_options & CREATE_OPTION_READONLY)
1167 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001168
1169 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001170/* pSMB->CreateOptions = cpu_to_le32(create_options &
1171 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001172 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001173
1174 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001175 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001176 count += name_len;
1177 pSMB->hdr.smb_buf_length += count;
1178
1179 pSMB->ByteCount = cpu_to_le16(count);
1180 /* long_op set to 1 to allow for oplock break timeouts */
1181 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001182 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183 cifs_stats_inc(&tcon->num_opens);
1184 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001185 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001186 } else {
1187 /* BB verify if wct == 15 */
1188
Steve French582d21e2008-05-13 04:54:12 +00001189/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001190
1191 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1192 /* Let caller know file was created so we can set the mode. */
1193 /* Do we care about the CreateAction in any other cases? */
1194 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001195/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001196 *pOplock |= CIFS_CREATE_ACTION; */
1197 /* BB FIXME END */
1198
Steve French790fe572007-07-07 19:25:05 +00001199 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001200 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1201 pfile_info->LastAccessTime = 0; /* BB fixme */
1202 pfile_info->LastWriteTime = 0; /* BB fixme */
1203 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001204 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001205 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001207 pfile_info->AllocationSize =
1208 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1209 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001211 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 }
1213 }
1214
1215 cifs_buf_release(pSMB);
1216 if (rc == -EAGAIN)
1217 goto OldOpenRetry;
1218 return rc;
1219}
1220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221int
1222CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1223 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 const int access_flags, const int create_options, __u16 *netfid,
1225 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001226 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227{
1228 int rc = -EACCES;
1229 OPEN_REQ *pSMB = NULL;
1230 OPEN_RSP *pSMBr = NULL;
1231 int bytes_returned;
1232 int name_len;
1233 __u16 count;
1234
1235openRetry:
1236 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1237 (void **) &pSMBr);
1238 if (rc)
1239 return rc;
1240
1241 pSMB->AndXCommand = 0xFF; /* none */
1242
1243 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1244 count = 1; /* account for one byte pad to word boundary */
1245 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001246 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001247 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 name_len++; /* trailing null */
1249 name_len *= 2;
1250 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001251 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 count = 0; /* no pad */
1253 name_len = strnlen(fileName, PATH_MAX);
1254 name_len++; /* trailing null */
1255 pSMB->NameLength = cpu_to_le16(name_len);
1256 strncpy(pSMB->fileName, fileName, name_len);
1257 }
1258 if (*pOplock & REQ_OPLOCK)
1259 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001260 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1263 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001264 /* set file as system file if special file such
1265 as fifo and server expecting SFU style and
1266 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001267 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001268 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1269 else
1270 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 /* XP does not handle ATTR_POSIX_SEMANTICS */
1273 /* but it helps speed up case sensitive checks for other
1274 servers such as Samba */
1275 if (tcon->ses->capabilities & CAP_UNIX)
1276 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1277
Jeff Layton67750fb2008-05-09 22:28:02 +00001278 if (create_options & CREATE_OPTION_READONLY)
1279 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1280
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1282 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001283 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001284 /* BB Expirement with various impersonation levels and verify */
1285 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 pSMB->SecurityFlags =
1287 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1288
1289 count += name_len;
1290 pSMB->hdr.smb_buf_length += count;
1291
1292 pSMB->ByteCount = cpu_to_le16(count);
1293 /* long_op set to 1 to allow for oplock break timeouts */
1294 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001295 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001296 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001298 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 } else {
Steve French09d1db52005-04-28 22:41:08 -07001300 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1302 /* Let caller know file was created so we can set the mode. */
1303 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001304 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001305 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001306 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001307 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1308 36 /* CreationTime to Attributes */);
1309 /* the file_info buf is endian converted by caller */
1310 pfile_info->AllocationSize = pSMBr->AllocationSize;
1311 pfile_info->EndOfFile = pSMBr->EndOfFile;
1312 pfile_info->NumberOfLinks = cpu_to_le32(1);
1313 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001316
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 cifs_buf_release(pSMB);
1318 if (rc == -EAGAIN)
1319 goto openRetry;
1320 return rc;
1321}
1322
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323int
Steve French50c2f752007-07-13 00:33:32 +00001324CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1325 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1326 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327{
1328 int rc = -EACCES;
1329 READ_REQ *pSMB = NULL;
1330 READ_RSP *pSMBr = NULL;
1331 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001332 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001333 int resp_buf_type = 0;
1334 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335
Joe Perchesb6b38f72010-04-21 03:50:45 +00001336 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001337 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001338 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001339 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001340 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001341 if ((lseek >> 32) > 0) {
1342 /* can not handle this big offset for old */
1343 return -EIO;
1344 }
1345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001348 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 if (rc)
1350 return rc;
1351
1352 /* tcon and ses pointer are checked in smb_init */
1353 if (tcon->ses->server == NULL)
1354 return -ECONNABORTED;
1355
Steve Frenchec637e32005-12-12 20:53:18 -08001356 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 pSMB->Fid = netfid;
1358 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001359 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001360 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001361
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 pSMB->Remaining = 0;
1363 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1364 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001365 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001366 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1367 else {
1368 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001369 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001370 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001371 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001372 }
Steve Frenchec637e32005-12-12 20:53:18 -08001373
1374 iov[0].iov_base = (char *)pSMB;
1375 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001376 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001377 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001378 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001379 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001381 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 } else {
1383 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1384 data_length = data_length << 16;
1385 data_length += le16_to_cpu(pSMBr->DataLength);
1386 *nbytes = data_length;
1387
1388 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001389 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001391 cFYI(1, "bad length %d for count %d",
1392 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 rc = -EIO;
1394 *nbytes = 0;
1395 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001396 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001397 le16_to_cpu(pSMBr->DataOffset);
1398/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001399 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001400 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001401 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001402 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001403 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 }
1405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Steve French4b8f9302006-02-26 16:41:18 +00001407/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001408 if (*buf) {
1409 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001410 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001411 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001412 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001413 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001414 /* return buffer to caller to free */
1415 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001416 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001417 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001418 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001419 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001420 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001421
1422 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 since file handle passed in no longer valid */
1424 return rc;
1425}
1426
Steve Frenchec637e32005-12-12 20:53:18 -08001427
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428int
1429CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1430 const int netfid, const unsigned int count,
1431 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001432 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433{
1434 int rc = -EACCES;
1435 WRITE_REQ *pSMB = NULL;
1436 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001437 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 __u32 bytes_sent;
1439 __u16 byte_count;
1440
Steve Frencha24e2d72010-04-03 17:20:21 +00001441 *nbytes = 0;
1442
Joe Perchesb6b38f72010-04-21 03:50:45 +00001443 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001444 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001445 return -ECONNABORTED;
1446
Steve French790fe572007-07-07 19:25:05 +00001447 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001448 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001449 else {
Steve French1c955182005-08-30 20:58:07 -07001450 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001451 if ((offset >> 32) > 0) {
1452 /* can not handle big offset for old srv */
1453 return -EIO;
1454 }
1455 }
Steve French1c955182005-08-30 20:58:07 -07001456
1457 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 (void **) &pSMBr);
1459 if (rc)
1460 return rc;
1461 /* tcon and ses pointer are checked in smb_init */
1462 if (tcon->ses->server == NULL)
1463 return -ECONNABORTED;
1464
1465 pSMB->AndXCommand = 0xFF; /* none */
1466 pSMB->Fid = netfid;
1467 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001468 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001469 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001470
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 pSMB->Reserved = 0xFFFFFFFF;
1472 pSMB->WriteMode = 0;
1473 pSMB->Remaining = 0;
1474
Steve French50c2f752007-07-13 00:33:32 +00001475 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 can send more if LARGE_WRITE_X capability returned by the server and if
1477 our buffer is big enough or if we convert to iovecs on socket writes
1478 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001479 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1481 } else {
1482 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1483 & ~0xFF;
1484 }
1485
1486 if (bytes_sent > count)
1487 bytes_sent = count;
1488 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001489 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001490 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001491 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001492 else if (ubuf) {
1493 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 cifs_buf_release(pSMB);
1495 return -EFAULT;
1496 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001497 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 /* No buffer */
1499 cifs_buf_release(pSMB);
1500 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001501 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001502 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001503 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001504 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001505 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001506
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1508 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001509 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001510
Steve French790fe572007-07-07 19:25:05 +00001511 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001512 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001513 else { /* old style write has byte count 4 bytes earlier
1514 so 4 bytes pad */
1515 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001516 (struct smb_com_writex_req *)pSMB;
1517 pSMBW->ByteCount = cpu_to_le16(byte_count);
1518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
1520 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1521 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001522 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001524 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 } else {
1526 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1527 *nbytes = (*nbytes) << 16;
1528 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301529
1530 /*
1531 * Mask off high 16 bits when bytes written as returned by the
1532 * server is greater than bytes requested by the client. Some
1533 * OS/2 servers are known to set incorrect CountHigh values.
1534 */
1535 if (*nbytes > count)
1536 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 }
1538
1539 cifs_buf_release(pSMB);
1540
Steve French50c2f752007-07-13 00:33:32 +00001541 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 since file handle passed in no longer valid */
1543
1544 return rc;
1545}
1546
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001547int
1548CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001550 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1551 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552{
1553 int rc = -EACCES;
1554 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001555 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001556 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001557 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001559 *nbytes = 0;
1560
Joe Perchesb6b38f72010-04-21 03:50:45 +00001561 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001562
Steve French4c3130e2008-12-09 00:28:16 +00001563 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001564 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001565 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001566 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001567 if ((offset >> 32) > 0) {
1568 /* can not handle big offset for old srv */
1569 return -EIO;
1570 }
1571 }
Steve French8cc64c62005-10-03 13:49:43 -07001572 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 if (rc)
1574 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 /* tcon and ses pointer are checked in smb_init */
1576 if (tcon->ses->server == NULL)
1577 return -ECONNABORTED;
1578
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001579 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 pSMB->Fid = netfid;
1581 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001582 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001583 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 pSMB->Reserved = 0xFFFFFFFF;
1585 pSMB->WriteMode = 0;
1586 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001587
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001589 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Steve French3e844692005-10-03 13:37:24 -07001591 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1592 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001593 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001594 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001595 pSMB->hdr.smb_buf_length += count+1;
1596 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001597 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1598 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001599 pSMB->ByteCount = cpu_to_le16(count + 1);
1600 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001601 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001602 (struct smb_com_writex_req *)pSMB;
1603 pSMBW->ByteCount = cpu_to_le16(count + 5);
1604 }
Steve French3e844692005-10-03 13:37:24 -07001605 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001606 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001607 iov[0].iov_len = smb_hdr_len + 4;
1608 else /* wct == 12 pad bigger by four bytes */
1609 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001610
Steve French3e844692005-10-03 13:37:24 -07001611
Steve Frenchec637e32005-12-12 20:53:18 -08001612 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001613 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001614 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001616 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001617 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001618 /* presumably this can not happen, but best to be safe */
1619 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001620 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001621 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001622 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1623 *nbytes = (*nbytes) << 16;
1624 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301625
1626 /*
1627 * Mask off high 16 bits when bytes written as returned by the
1628 * server is greater than bytes requested by the client. OS/2
1629 * servers are known to set incorrect CountHigh values.
1630 */
1631 if (*nbytes > count)
1632 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001633 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634
Steve French4b8f9302006-02-26 16:41:18 +00001635/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001636 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001637 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001638 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001639 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
Steve French50c2f752007-07-13 00:33:32 +00001641 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 since file handle passed in no longer valid */
1643
1644 return rc;
1645}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001646
1647
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648int
1649CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1650 const __u16 smb_file_id, const __u64 len,
1651 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001652 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653{
1654 int rc = 0;
1655 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001656/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 int bytes_returned;
1658 int timeout = 0;
1659 __u16 count;
1660
Joe Perchesb6b38f72010-04-21 03:50:45 +00001661 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001662 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1663
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 if (rc)
1665 return rc;
1666
Steve French790fe572007-07-07 19:25:05 +00001667 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001668 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001670 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001671 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1673 } else {
1674 pSMB->Timeout = 0;
1675 }
1676
1677 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1678 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1679 pSMB->LockType = lockType;
1680 pSMB->AndXCommand = 0xFF; /* none */
1681 pSMB->Fid = smb_file_id; /* netfid stays le */
1682
Steve French790fe572007-07-07 19:25:05 +00001683 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1685 /* BB where to store pid high? */
1686 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1687 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1688 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1689 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1690 count = sizeof(LOCKING_ANDX_RANGE);
1691 } else {
1692 /* oplock break */
1693 count = 0;
1694 }
1695 pSMB->hdr.smb_buf_length += count;
1696 pSMB->ByteCount = cpu_to_le16(count);
1697
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001698 if (waitFlag) {
1699 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001700 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001701 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001702 } else {
Steve French133672e2007-11-13 22:41:37 +00001703 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1704 timeout);
1705 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001706 }
Steve Frencha4544342005-08-24 13:59:35 -07001707 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001708 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001709 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710
Steve French50c2f752007-07-13 00:33:32 +00001711 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 since file handle passed in no longer valid */
1713 return rc;
1714}
1715
1716int
Steve French08547b02006-02-28 22:39:25 +00001717CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1718 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001719 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001720 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001721{
1722 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1723 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001724 struct cifs_posix_lock *parm_data;
1725 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001726 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001727 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001728 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001729 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001730 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001731
Joe Perchesb6b38f72010-04-21 03:50:45 +00001732 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001733
Steve French790fe572007-07-07 19:25:05 +00001734 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001735 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001736
Steve French08547b02006-02-28 22:39:25 +00001737 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1738
1739 if (rc)
1740 return rc;
1741
1742 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1743
Steve French50c2f752007-07-13 00:33:32 +00001744 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001745 pSMB->MaxSetupCount = 0;
1746 pSMB->Reserved = 0;
1747 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001748 pSMB->Reserved2 = 0;
1749 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1750 offset = param_offset + params;
1751
Steve French08547b02006-02-28 22:39:25 +00001752 count = sizeof(struct cifs_posix_lock);
1753 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001754 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001755 pSMB->SetupCount = 1;
1756 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001757 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001758 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1759 else
1760 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1761 byte_count = 3 /* pad */ + params + count;
1762 pSMB->DataCount = cpu_to_le16(count);
1763 pSMB->ParameterCount = cpu_to_le16(params);
1764 pSMB->TotalDataCount = pSMB->DataCount;
1765 pSMB->TotalParameterCount = pSMB->ParameterCount;
1766 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001767 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001768 (((char *) &pSMB->hdr.Protocol) + offset);
1769
1770 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001771 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001772 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001773 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001774 pSMB->Timeout = cpu_to_le32(-1);
1775 } else
1776 pSMB->Timeout = 0;
1777
Steve French08547b02006-02-28 22:39:25 +00001778 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001779 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001780 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001781
1782 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001783 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001784 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1785 pSMB->Reserved4 = 0;
1786 pSMB->hdr.smb_buf_length += byte_count;
1787 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001788 if (waitFlag) {
1789 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1790 (struct smb_hdr *) pSMBr, &bytes_returned);
1791 } else {
Steve French133672e2007-11-13 22:41:37 +00001792 iov[0].iov_base = (char *)pSMB;
1793 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1794 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1795 &resp_buf_type, timeout);
1796 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1797 not try to free it twice below on exit */
1798 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001799 }
1800
Steve French08547b02006-02-28 22:39:25 +00001801 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001802 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001803 } else if (get_flag) {
1804 /* lock structure can be returned on get */
1805 __u16 data_offset;
1806 __u16 data_count;
1807 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001808
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001809 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1810 rc = -EIO; /* bad smb */
1811 goto plk_err_exit;
1812 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001813 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1814 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001815 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001816 rc = -EIO;
1817 goto plk_err_exit;
1818 }
1819 parm_data = (struct cifs_posix_lock *)
1820 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001821 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001822 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001823 else {
1824 if (parm_data->lock_type ==
1825 __constant_cpu_to_le16(CIFS_RDLCK))
1826 pLockData->fl_type = F_RDLCK;
1827 else if (parm_data->lock_type ==
1828 __constant_cpu_to_le16(CIFS_WRLCK))
1829 pLockData->fl_type = F_WRLCK;
1830
1831 pLockData->fl_start = parm_data->start;
1832 pLockData->fl_end = parm_data->start +
1833 parm_data->length - 1;
1834 pLockData->fl_pid = parm_data->pid;
1835 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001836 }
Steve French50c2f752007-07-13 00:33:32 +00001837
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001838plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001839 if (pSMB)
1840 cifs_small_buf_release(pSMB);
1841
Steve French133672e2007-11-13 22:41:37 +00001842 if (resp_buf_type == CIFS_SMALL_BUFFER)
1843 cifs_small_buf_release(iov[0].iov_base);
1844 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1845 cifs_buf_release(iov[0].iov_base);
1846
Steve French08547b02006-02-28 22:39:25 +00001847 /* Note: On -EAGAIN error only caller can retry on handle based calls
1848 since file handle passed in no longer valid */
1849
1850 return rc;
1851}
1852
1853
1854int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1856{
1857 int rc = 0;
1858 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001859 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860
1861/* do not retry on dead session on close */
1862 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001863 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 return 0;
1865 if (rc)
1866 return rc;
1867
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001869 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001871 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001872 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001874 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001876 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 }
1878 }
1879
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001881 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 rc = 0;
1883
1884 return rc;
1885}
1886
1887int
Steve Frenchb298f222009-02-21 21:17:43 +00001888CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1889{
1890 int rc = 0;
1891 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001892 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001893
1894 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1895 if (rc)
1896 return rc;
1897
1898 pSMB->FileID = (__u16) smb_file_id;
1899 pSMB->ByteCount = 0;
1900 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1901 cifs_stats_inc(&tcon->num_flushes);
1902 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001903 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001904
1905 return rc;
1906}
1907
1908int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1910 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001911 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912{
1913 int rc = 0;
1914 RENAME_REQ *pSMB = NULL;
1915 RENAME_RSP *pSMBr = NULL;
1916 int bytes_returned;
1917 int name_len, name_len2;
1918 __u16 count;
1919
Joe Perchesb6b38f72010-04-21 03:50:45 +00001920 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921renameRetry:
1922 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1923 (void **) &pSMBr);
1924 if (rc)
1925 return rc;
1926
1927 pSMB->BufferFormat = 0x04;
1928 pSMB->SearchAttributes =
1929 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1930 ATTR_DIRECTORY);
1931
1932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1933 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001934 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001935 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 name_len++; /* trailing null */
1937 name_len *= 2;
1938 pSMB->OldFileName[name_len] = 0x04; /* pad */
1939 /* protocol requires ASCII signature byte on Unicode string */
1940 pSMB->OldFileName[name_len + 1] = 0x00;
1941 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001942 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001943 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1945 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001946 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 name_len = strnlen(fromName, PATH_MAX);
1948 name_len++; /* trailing null */
1949 strncpy(pSMB->OldFileName, fromName, name_len);
1950 name_len2 = strnlen(toName, PATH_MAX);
1951 name_len2++; /* trailing null */
1952 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1953 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1954 name_len2++; /* trailing null */
1955 name_len2++; /* signature byte */
1956 }
1957
1958 count = 1 /* 1st signature byte */ + name_len + name_len2;
1959 pSMB->hdr.smb_buf_length += count;
1960 pSMB->ByteCount = cpu_to_le16(count);
1961
1962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001964 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001965 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001966 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 cifs_buf_release(pSMB);
1969
1970 if (rc == -EAGAIN)
1971 goto renameRetry;
1972
1973 return rc;
1974}
1975
Steve French50c2f752007-07-13 00:33:32 +00001976int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001977 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001978 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1981 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001982 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 char *data_offset;
1984 char dummy_string[30];
1985 int rc = 0;
1986 int bytes_returned = 0;
1987 int len_of_str;
1988 __u16 params, param_offset, offset, count, byte_count;
1989
Joe Perchesb6b38f72010-04-21 03:50:45 +00001990 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1992 (void **) &pSMBr);
1993 if (rc)
1994 return rc;
1995
1996 params = 6;
1997 pSMB->MaxSetupCount = 0;
1998 pSMB->Reserved = 0;
1999 pSMB->Flags = 0;
2000 pSMB->Timeout = 0;
2001 pSMB->Reserved2 = 0;
2002 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2003 offset = param_offset + params;
2004
2005 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2006 rename_info = (struct set_file_rename *) data_offset;
2007 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002008 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 pSMB->SetupCount = 1;
2010 pSMB->Reserved3 = 0;
2011 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2012 byte_count = 3 /* pad */ + params;
2013 pSMB->ParameterCount = cpu_to_le16(params);
2014 pSMB->TotalParameterCount = pSMB->ParameterCount;
2015 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2016 pSMB->DataOffset = cpu_to_le16(offset);
2017 /* construct random name ".cifs_tmp<inodenum><mid>" */
2018 rename_info->overwrite = cpu_to_le32(1);
2019 rename_info->root_fid = 0;
2020 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002021 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002022 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2023 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002024 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002026 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002027 target_name, PATH_MAX, nls_codepage,
2028 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 }
2030 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002031 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 byte_count += count;
2033 pSMB->DataCount = cpu_to_le16(count);
2034 pSMB->TotalDataCount = pSMB->DataCount;
2035 pSMB->Fid = netfid;
2036 pSMB->InformationLevel =
2037 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2038 pSMB->Reserved4 = 0;
2039 pSMB->hdr.smb_buf_length += byte_count;
2040 pSMB->ByteCount = cpu_to_le16(byte_count);
2041 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002042 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002043 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002044 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002045 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002046
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 cifs_buf_release(pSMB);
2048
2049 /* Note: On -EAGAIN error only caller can retry on handle based calls
2050 since file handle passed in no longer valid */
2051
2052 return rc;
2053}
2054
2055int
Steve French50c2f752007-07-13 00:33:32 +00002056CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2057 const __u16 target_tid, const char *toName, const int flags,
2058 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059{
2060 int rc = 0;
2061 COPY_REQ *pSMB = NULL;
2062 COPY_RSP *pSMBr = NULL;
2063 int bytes_returned;
2064 int name_len, name_len2;
2065 __u16 count;
2066
Joe Perchesb6b38f72010-04-21 03:50:45 +00002067 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068copyRetry:
2069 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2070 (void **) &pSMBr);
2071 if (rc)
2072 return rc;
2073
2074 pSMB->BufferFormat = 0x04;
2075 pSMB->Tid2 = target_tid;
2076
2077 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2078
2079 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002080 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002081 fromName, PATH_MAX, nls_codepage,
2082 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 name_len++; /* trailing null */
2084 name_len *= 2;
2085 pSMB->OldFileName[name_len] = 0x04; /* pad */
2086 /* protocol requires ASCII signature byte on Unicode string */
2087 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002088 name_len2 =
2089 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002090 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2092 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002093 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 name_len = strnlen(fromName, PATH_MAX);
2095 name_len++; /* trailing null */
2096 strncpy(pSMB->OldFileName, fromName, name_len);
2097 name_len2 = strnlen(toName, PATH_MAX);
2098 name_len2++; /* trailing null */
2099 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2100 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2101 name_len2++; /* trailing null */
2102 name_len2++; /* signature byte */
2103 }
2104
2105 count = 1 /* 1st signature byte */ + name_len + name_len2;
2106 pSMB->hdr.smb_buf_length += count;
2107 pSMB->ByteCount = cpu_to_le16(count);
2108
2109 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2110 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2111 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002112 cFYI(1, "Send error in copy = %d with %d files copied",
2113 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 }
Steve French0d817bc2008-05-22 02:02:03 +00002115 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116
2117 if (rc == -EAGAIN)
2118 goto copyRetry;
2119
2120 return rc;
2121}
2122
2123int
2124CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2125 const char *fromName, const char *toName,
2126 const struct nls_table *nls_codepage)
2127{
2128 TRANSACTION2_SPI_REQ *pSMB = NULL;
2129 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2130 char *data_offset;
2131 int name_len;
2132 int name_len_target;
2133 int rc = 0;
2134 int bytes_returned = 0;
2135 __u16 params, param_offset, offset, byte_count;
2136
Joe Perchesb6b38f72010-04-21 03:50:45 +00002137 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138createSymLinkRetry:
2139 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2140 (void **) &pSMBr);
2141 if (rc)
2142 return rc;
2143
2144 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2145 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002146 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 /* find define for this maxpathcomponent */
2148 , nls_codepage);
2149 name_len++; /* trailing null */
2150 name_len *= 2;
2151
Steve French50c2f752007-07-13 00:33:32 +00002152 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 name_len = strnlen(fromName, PATH_MAX);
2154 name_len++; /* trailing null */
2155 strncpy(pSMB->FileName, fromName, name_len);
2156 }
2157 params = 6 + name_len;
2158 pSMB->MaxSetupCount = 0;
2159 pSMB->Reserved = 0;
2160 pSMB->Flags = 0;
2161 pSMB->Timeout = 0;
2162 pSMB->Reserved2 = 0;
2163 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002164 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 offset = param_offset + params;
2166
2167 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2168 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2169 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002170 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 /* find define for this maxpathcomponent */
2172 , nls_codepage);
2173 name_len_target++; /* trailing null */
2174 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002175 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 name_len_target = strnlen(toName, PATH_MAX);
2177 name_len_target++; /* trailing null */
2178 strncpy(data_offset, toName, name_len_target);
2179 }
2180
2181 pSMB->MaxParameterCount = cpu_to_le16(2);
2182 /* BB find exact max on data count below from sess */
2183 pSMB->MaxDataCount = cpu_to_le16(1000);
2184 pSMB->SetupCount = 1;
2185 pSMB->Reserved3 = 0;
2186 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2187 byte_count = 3 /* pad */ + params + name_len_target;
2188 pSMB->DataCount = cpu_to_le16(name_len_target);
2189 pSMB->ParameterCount = cpu_to_le16(params);
2190 pSMB->TotalDataCount = pSMB->DataCount;
2191 pSMB->TotalParameterCount = pSMB->ParameterCount;
2192 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2193 pSMB->DataOffset = cpu_to_le16(offset);
2194 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2195 pSMB->Reserved4 = 0;
2196 pSMB->hdr.smb_buf_length += byte_count;
2197 pSMB->ByteCount = cpu_to_le16(byte_count);
2198 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2199 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002200 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002201 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002202 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203
Steve French0d817bc2008-05-22 02:02:03 +00002204 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
2206 if (rc == -EAGAIN)
2207 goto createSymLinkRetry;
2208
2209 return rc;
2210}
2211
2212int
2213CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2214 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002215 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216{
2217 TRANSACTION2_SPI_REQ *pSMB = NULL;
2218 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2219 char *data_offset;
2220 int name_len;
2221 int name_len_target;
2222 int rc = 0;
2223 int bytes_returned = 0;
2224 __u16 params, param_offset, offset, byte_count;
2225
Joe Perchesb6b38f72010-04-21 03:50:45 +00002226 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227createHardLinkRetry:
2228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2229 (void **) &pSMBr);
2230 if (rc)
2231 return rc;
2232
2233 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002234 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002235 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 name_len++; /* trailing null */
2237 name_len *= 2;
2238
Steve French50c2f752007-07-13 00:33:32 +00002239 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240 name_len = strnlen(toName, PATH_MAX);
2241 name_len++; /* trailing null */
2242 strncpy(pSMB->FileName, toName, name_len);
2243 }
2244 params = 6 + name_len;
2245 pSMB->MaxSetupCount = 0;
2246 pSMB->Reserved = 0;
2247 pSMB->Flags = 0;
2248 pSMB->Timeout = 0;
2249 pSMB->Reserved2 = 0;
2250 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002251 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 offset = param_offset + params;
2253
2254 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2255 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2256 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002257 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002258 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 name_len_target++; /* trailing null */
2260 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002261 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len_target = strnlen(fromName, PATH_MAX);
2263 name_len_target++; /* trailing null */
2264 strncpy(data_offset, fromName, name_len_target);
2265 }
2266
2267 pSMB->MaxParameterCount = cpu_to_le16(2);
2268 /* BB find exact max on data count below from sess*/
2269 pSMB->MaxDataCount = cpu_to_le16(1000);
2270 pSMB->SetupCount = 1;
2271 pSMB->Reserved3 = 0;
2272 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2273 byte_count = 3 /* pad */ + params + name_len_target;
2274 pSMB->ParameterCount = cpu_to_le16(params);
2275 pSMB->TotalParameterCount = pSMB->ParameterCount;
2276 pSMB->DataCount = cpu_to_le16(name_len_target);
2277 pSMB->TotalDataCount = pSMB->DataCount;
2278 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2279 pSMB->DataOffset = cpu_to_le16(offset);
2280 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2281 pSMB->Reserved4 = 0;
2282 pSMB->hdr.smb_buf_length += byte_count;
2283 pSMB->ByteCount = cpu_to_le16(byte_count);
2284 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2285 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002286 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002287 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002288 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290 cifs_buf_release(pSMB);
2291 if (rc == -EAGAIN)
2292 goto createHardLinkRetry;
2293
2294 return rc;
2295}
2296
2297int
2298CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2299 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002300 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301{
2302 int rc = 0;
2303 NT_RENAME_REQ *pSMB = NULL;
2304 RENAME_RSP *pSMBr = NULL;
2305 int bytes_returned;
2306 int name_len, name_len2;
2307 __u16 count;
2308
Joe Perchesb6b38f72010-04-21 03:50:45 +00002309 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310winCreateHardLinkRetry:
2311
2312 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2313 (void **) &pSMBr);
2314 if (rc)
2315 return rc;
2316
2317 pSMB->SearchAttributes =
2318 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2319 ATTR_DIRECTORY);
2320 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2321 pSMB->ClusterCount = 0;
2322
2323 pSMB->BufferFormat = 0x04;
2324
2325 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2326 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002327 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002328 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 name_len++; /* trailing null */
2330 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002331
2332 /* protocol specifies ASCII buffer format (0x04) for unicode */
2333 pSMB->OldFileName[name_len] = 0x04;
2334 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002336 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002337 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2339 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002340 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 name_len = strnlen(fromName, PATH_MAX);
2342 name_len++; /* trailing null */
2343 strncpy(pSMB->OldFileName, fromName, name_len);
2344 name_len2 = strnlen(toName, PATH_MAX);
2345 name_len2++; /* trailing null */
2346 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2347 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2348 name_len2++; /* trailing null */
2349 name_len2++; /* signature byte */
2350 }
2351
2352 count = 1 /* string type byte */ + name_len + name_len2;
2353 pSMB->hdr.smb_buf_length += count;
2354 pSMB->ByteCount = cpu_to_le16(count);
2355
2356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002358 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002359 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002360 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002361
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 cifs_buf_release(pSMB);
2363 if (rc == -EAGAIN)
2364 goto winCreateHardLinkRetry;
2365
2366 return rc;
2367}
2368
2369int
2370CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002371 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 const struct nls_table *nls_codepage)
2373{
2374/* SMB_QUERY_FILE_UNIX_LINK */
2375 TRANSACTION2_QPI_REQ *pSMB = NULL;
2376 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2377 int rc = 0;
2378 int bytes_returned;
2379 int name_len;
2380 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002381 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Joe Perchesb6b38f72010-04-21 03:50:45 +00002383 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
2385querySymLinkRetry:
2386 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2387 (void **) &pSMBr);
2388 if (rc)
2389 return rc;
2390
2391 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2392 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002393 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2394 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 name_len++; /* trailing null */
2396 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002397 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 name_len = strnlen(searchName, PATH_MAX);
2399 name_len++; /* trailing null */
2400 strncpy(pSMB->FileName, searchName, name_len);
2401 }
2402
2403 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2404 pSMB->TotalDataCount = 0;
2405 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002406 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 pSMB->MaxSetupCount = 0;
2408 pSMB->Reserved = 0;
2409 pSMB->Flags = 0;
2410 pSMB->Timeout = 0;
2411 pSMB->Reserved2 = 0;
2412 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002413 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 pSMB->DataCount = 0;
2415 pSMB->DataOffset = 0;
2416 pSMB->SetupCount = 1;
2417 pSMB->Reserved3 = 0;
2418 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2419 byte_count = params + 1 /* pad */ ;
2420 pSMB->TotalParameterCount = cpu_to_le16(params);
2421 pSMB->ParameterCount = pSMB->TotalParameterCount;
2422 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2423 pSMB->Reserved4 = 0;
2424 pSMB->hdr.smb_buf_length += byte_count;
2425 pSMB->ByteCount = cpu_to_le16(byte_count);
2426
2427 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2428 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2429 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002430 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 } else {
2432 /* decode response */
2433
2434 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002436 if (rc || (pSMBr->ByteCount < 2))
2437 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002439 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002440 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
Jeff Layton460b9692009-04-30 07:17:56 -04002442 data_start = ((char *) &pSMBr->hdr.Protocol) +
2443 le16_to_cpu(pSMBr->t2.DataOffset);
2444
Steve French0e0d2cf2009-05-01 05:27:32 +00002445 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2446 is_unicode = true;
2447 else
2448 is_unicode = false;
2449
Steve French737b7582005-04-28 22:41:06 -07002450 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002451 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002452 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002453 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002454 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 }
2456 }
2457 cifs_buf_release(pSMB);
2458 if (rc == -EAGAIN)
2459 goto querySymLinkRetry;
2460 return rc;
2461}
2462
Parag Warudkarc9489772007-10-23 18:09:48 +00002463#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002464/* Initialize NT TRANSACT SMB into small smb request buffer.
2465 This assumes that all NT TRANSACTS that we init here have
2466 total parm and data under about 400 bytes (to fit in small cifs
2467 buffer size), which is the case so far, it easily fits. NB:
2468 Setup words themselves and ByteCount
2469 MaxSetupCount (size of returned setup area) and
2470 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002471static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002472smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002473 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002474 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002475{
2476 int rc;
2477 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002478 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002479
2480 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2481 (void **)&pSMB);
2482 if (rc)
2483 return rc;
2484 *ret_buf = (void *)pSMB;
2485 pSMB->Reserved = 0;
2486 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2487 pSMB->TotalDataCount = 0;
2488 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2489 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2490 pSMB->ParameterCount = pSMB->TotalParameterCount;
2491 pSMB->DataCount = pSMB->TotalDataCount;
2492 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2493 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2494 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2495 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2496 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2497 pSMB->SubCommand = cpu_to_le16(sub_command);
2498 return 0;
2499}
2500
2501static int
Steve French50c2f752007-07-13 00:33:32 +00002502validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002503 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002504{
Steve French50c2f752007-07-13 00:33:32 +00002505 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002506 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002507 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002508
Steve French630f3f0c2007-10-25 21:17:17 +00002509 *pdatalen = 0;
2510 *pparmlen = 0;
2511
Steve French790fe572007-07-07 19:25:05 +00002512 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002513 return -EINVAL;
2514
2515 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2516
2517 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002518 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002519 (char *)&pSMBr->ByteCount;
2520
Steve French0a4b92c2006-01-12 15:44:21 -08002521 data_offset = le32_to_cpu(pSMBr->DataOffset);
2522 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002523 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002524 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2525
2526 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2527 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2528
2529 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002530 if (*ppparm > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002531 cFYI(1, "parms start after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002532 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002533 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002534 cFYI(1, "parm end after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002535 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002536 } else if (*ppdata > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002537 cFYI(1, "data starts after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002538 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002539 } else if (data_count + *ppdata > end_of_smb) {
Steve Frenchf19159d2010-04-21 04:12:10 +00002540 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002541 *ppdata, data_count, (data_count + *ppdata),
Joe Perchesb6b38f72010-04-21 03:50:45 +00002542 end_of_smb, pSMBr);
Steve French0a4b92c2006-01-12 15:44:21 -08002543 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002544 } else if (parm_count + data_count > pSMBr->ByteCount) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002545 cFYI(1, "parm count and data count larger than SMB");
Steve French0a4b92c2006-01-12 15:44:21 -08002546 return -EINVAL;
2547 }
Steve French630f3f0c2007-10-25 21:17:17 +00002548 *pdatalen = data_count;
2549 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002550 return 0;
2551}
2552
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553int
2554CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2555 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002556 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 const struct nls_table *nls_codepage)
2558{
2559 int rc = 0;
2560 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002561 struct smb_com_transaction_ioctl_req *pSMB;
2562 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563
Joe Perchesb6b38f72010-04-21 03:50:45 +00002564 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2566 (void **) &pSMBr);
2567 if (rc)
2568 return rc;
2569
2570 pSMB->TotalParameterCount = 0 ;
2571 pSMB->TotalDataCount = 0;
2572 pSMB->MaxParameterCount = cpu_to_le32(2);
2573 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002574 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2575 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 pSMB->MaxSetupCount = 4;
2577 pSMB->Reserved = 0;
2578 pSMB->ParameterOffset = 0;
2579 pSMB->DataCount = 0;
2580 pSMB->DataOffset = 0;
2581 pSMB->SetupCount = 4;
2582 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2583 pSMB->ParameterCount = pSMB->TotalParameterCount;
2584 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2585 pSMB->IsFsctl = 1; /* FSCTL */
2586 pSMB->IsRootFlag = 0;
2587 pSMB->Fid = fid; /* file handle always le */
2588 pSMB->ByteCount = 0;
2589
2590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2591 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2592 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002593 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 } else { /* decode response */
2595 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2596 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002597 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 /* BB also check enough total bytes returned */
2599 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002600 goto qreparse_out;
2601 }
2602 if (data_count && (data_count < 2048)) {
2603 char *end_of_smb = 2 /* sizeof byte count */ +
2604 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Steve Frenchafe48c32009-05-02 05:25:46 +00002606 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002607 (struct reparse_data *)
2608 ((char *)&pSMBr->hdr.Protocol
2609 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002610 if ((char *)reparse_buf >= end_of_smb) {
2611 rc = -EIO;
2612 goto qreparse_out;
2613 }
2614 if ((reparse_buf->LinkNamesBuf +
2615 reparse_buf->TargetNameOffset +
2616 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002617 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002618 rc = -EIO;
2619 goto qreparse_out;
2620 }
Steve French50c2f752007-07-13 00:33:32 +00002621
Steve Frenchafe48c32009-05-02 05:25:46 +00002622 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2623 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002624 (reparse_buf->LinkNamesBuf +
2625 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002626 buflen,
2627 reparse_buf->TargetNameLen,
2628 nls_codepage, 0);
2629 } else { /* ASCII names */
2630 strncpy(symlinkinfo,
2631 reparse_buf->LinkNamesBuf +
2632 reparse_buf->TargetNameOffset,
2633 min_t(const int, buflen,
2634 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002636 } else {
2637 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002638 cFYI(1, "Invalid return data count on "
2639 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002641 symlinkinfo[buflen] = 0; /* just in case so the caller
2642 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002643 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 }
Steve French989c7e52009-05-02 05:32:20 +00002645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002647 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
2649 /* Note: On -EAGAIN error only caller can retry on handle based calls
2650 since file handle passed in no longer valid */
2651
2652 return rc;
2653}
Steve Frenchafe48c32009-05-02 05:25:46 +00002654#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
2656#ifdef CONFIG_CIFS_POSIX
2657
2658/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002659static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2660 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661{
2662 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002663 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2664 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2665 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002666 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667
2668 return;
2669}
2670
2671/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002672static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2673 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674{
2675 int size = 0;
2676 int i;
2677 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002678 struct cifs_posix_ace *pACE;
2679 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2680 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
2682 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2683 return -EOPNOTSUPP;
2684
Steve French790fe572007-07-07 19:25:05 +00002685 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 count = le16_to_cpu(cifs_acl->access_entry_count);
2687 pACE = &cifs_acl->ace_array[0];
2688 size = sizeof(struct cifs_posix_acl);
2689 size += sizeof(struct cifs_posix_ace) * count;
2690 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002691 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002692 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2693 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 return -EINVAL;
2695 }
Steve French790fe572007-07-07 19:25:05 +00002696 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 count = le16_to_cpu(cifs_acl->access_entry_count);
2698 size = sizeof(struct cifs_posix_acl);
2699 size += sizeof(struct cifs_posix_ace) * count;
2700/* skip past access ACEs to get to default ACEs */
2701 pACE = &cifs_acl->ace_array[count];
2702 count = le16_to_cpu(cifs_acl->default_entry_count);
2703 size += sizeof(struct cifs_posix_ace) * count;
2704 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002705 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 return -EINVAL;
2707 } else {
2708 /* illegal type */
2709 return -EINVAL;
2710 }
2711
2712 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002713 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002714 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002715 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 return -ERANGE;
2717 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002718 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002719 for (i = 0; i < count ; i++) {
2720 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2721 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 }
2723 }
2724 return size;
2725}
2726
Steve French50c2f752007-07-13 00:33:32 +00002727static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2728 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729{
2730 __u16 rc = 0; /* 0 = ACL converted ok */
2731
Steve Frenchff7feac2005-11-15 16:45:16 -08002732 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2733 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002735 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 /* Probably no need to le convert -1 on any arch but can not hurt */
2737 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002738 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002739 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002740 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 return rc;
2742}
2743
2744/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002745static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2746 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747{
2748 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002749 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2750 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 int count;
2752 int i;
2753
Steve French790fe572007-07-07 19:25:05 +00002754 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return 0;
2756
2757 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002758 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002759 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002760 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002761 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002762 cFYI(1, "unknown POSIX ACL version %d",
2763 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 return 0;
2765 }
2766 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002767 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002768 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002769 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002770 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002772 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 return 0;
2774 }
Steve French50c2f752007-07-13 00:33:32 +00002775 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2777 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002778 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 /* ACE not converted */
2780 break;
2781 }
2782 }
Steve French790fe572007-07-07 19:25:05 +00002783 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2785 rc += sizeof(struct cifs_posix_acl);
2786 /* BB add check to make sure ACL does not overflow SMB */
2787 }
2788 return rc;
2789}
2790
2791int
2792CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002793 const unsigned char *searchName,
2794 char *acl_inf, const int buflen, const int acl_type,
2795 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796{
2797/* SMB_QUERY_POSIX_ACL */
2798 TRANSACTION2_QPI_REQ *pSMB = NULL;
2799 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2800 int rc = 0;
2801 int bytes_returned;
2802 int name_len;
2803 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002804
Joe Perchesb6b38f72010-04-21 03:50:45 +00002805 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
2807queryAclRetry:
2808 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2809 (void **) &pSMBr);
2810 if (rc)
2811 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002812
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2814 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002815 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002816 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 name_len++; /* trailing null */
2818 name_len *= 2;
2819 pSMB->FileName[name_len] = 0;
2820 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002821 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 name_len = strnlen(searchName, PATH_MAX);
2823 name_len++; /* trailing null */
2824 strncpy(pSMB->FileName, searchName, name_len);
2825 }
2826
2827 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2828 pSMB->TotalDataCount = 0;
2829 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002830 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 pSMB->MaxDataCount = cpu_to_le16(4000);
2832 pSMB->MaxSetupCount = 0;
2833 pSMB->Reserved = 0;
2834 pSMB->Flags = 0;
2835 pSMB->Timeout = 0;
2836 pSMB->Reserved2 = 0;
2837 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002838 offsetof(struct smb_com_transaction2_qpi_req,
2839 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 pSMB->DataCount = 0;
2841 pSMB->DataOffset = 0;
2842 pSMB->SetupCount = 1;
2843 pSMB->Reserved3 = 0;
2844 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2845 byte_count = params + 1 /* pad */ ;
2846 pSMB->TotalParameterCount = cpu_to_le16(params);
2847 pSMB->ParameterCount = pSMB->TotalParameterCount;
2848 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2849 pSMB->Reserved4 = 0;
2850 pSMB->hdr.smb_buf_length += byte_count;
2851 pSMB->ByteCount = cpu_to_le16(byte_count);
2852
2853 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2854 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002855 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002857 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 } else {
2859 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002860
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2862 if (rc || (pSMBr->ByteCount < 2))
2863 /* BB also check enough total bytes returned */
2864 rc = -EIO; /* bad smb */
2865 else {
2866 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2867 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2868 rc = cifs_copy_posix_acl(acl_inf,
2869 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002870 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 }
2872 }
2873 cifs_buf_release(pSMB);
2874 if (rc == -EAGAIN)
2875 goto queryAclRetry;
2876 return rc;
2877}
2878
2879int
2880CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002881 const unsigned char *fileName,
2882 const char *local_acl, const int buflen,
2883 const int acl_type,
2884 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885{
2886 struct smb_com_transaction2_spi_req *pSMB = NULL;
2887 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2888 char *parm_data;
2889 int name_len;
2890 int rc = 0;
2891 int bytes_returned = 0;
2892 __u16 params, byte_count, data_count, param_offset, offset;
2893
Joe Perchesb6b38f72010-04-21 03:50:45 +00002894 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895setAclRetry:
2896 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002897 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 if (rc)
2899 return rc;
2900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2901 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002902 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002903 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 name_len++; /* trailing null */
2905 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002906 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 name_len = strnlen(fileName, PATH_MAX);
2908 name_len++; /* trailing null */
2909 strncpy(pSMB->FileName, fileName, name_len);
2910 }
2911 params = 6 + name_len;
2912 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002913 /* BB find max SMB size from sess */
2914 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 pSMB->MaxSetupCount = 0;
2916 pSMB->Reserved = 0;
2917 pSMB->Flags = 0;
2918 pSMB->Timeout = 0;
2919 pSMB->Reserved2 = 0;
2920 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002921 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 offset = param_offset + params;
2923 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2924 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2925
2926 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002927 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928
Steve French790fe572007-07-07 19:25:05 +00002929 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 rc = -EOPNOTSUPP;
2931 goto setACLerrorExit;
2932 }
2933 pSMB->DataOffset = cpu_to_le16(offset);
2934 pSMB->SetupCount = 1;
2935 pSMB->Reserved3 = 0;
2936 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2937 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2938 byte_count = 3 /* pad */ + params + data_count;
2939 pSMB->DataCount = cpu_to_le16(data_count);
2940 pSMB->TotalDataCount = pSMB->DataCount;
2941 pSMB->ParameterCount = cpu_to_le16(params);
2942 pSMB->TotalParameterCount = pSMB->ParameterCount;
2943 pSMB->Reserved4 = 0;
2944 pSMB->hdr.smb_buf_length += byte_count;
2945 pSMB->ByteCount = cpu_to_le16(byte_count);
2946 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002948 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002949 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
2951setACLerrorExit:
2952 cifs_buf_release(pSMB);
2953 if (rc == -EAGAIN)
2954 goto setAclRetry;
2955 return rc;
2956}
2957
Steve Frenchf654bac2005-04-28 22:41:04 -07002958/* BB fix tabs in this function FIXME BB */
2959int
2960CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002961 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002962{
Steve French50c2f752007-07-13 00:33:32 +00002963 int rc = 0;
2964 struct smb_t2_qfi_req *pSMB = NULL;
2965 struct smb_t2_qfi_rsp *pSMBr = NULL;
2966 int bytes_returned;
2967 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002968
Joe Perchesb6b38f72010-04-21 03:50:45 +00002969 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002970 if (tcon == NULL)
2971 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002972
2973GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002974 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2975 (void **) &pSMBr);
2976 if (rc)
2977 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002978
Steve Frenchad7a2922008-02-07 23:25:02 +00002979 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002980 pSMB->t2.TotalDataCount = 0;
2981 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2982 /* BB find exact max data count below from sess structure BB */
2983 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2984 pSMB->t2.MaxSetupCount = 0;
2985 pSMB->t2.Reserved = 0;
2986 pSMB->t2.Flags = 0;
2987 pSMB->t2.Timeout = 0;
2988 pSMB->t2.Reserved2 = 0;
2989 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2990 Fid) - 4);
2991 pSMB->t2.DataCount = 0;
2992 pSMB->t2.DataOffset = 0;
2993 pSMB->t2.SetupCount = 1;
2994 pSMB->t2.Reserved3 = 0;
2995 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2996 byte_count = params + 1 /* pad */ ;
2997 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2998 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2999 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3000 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003001 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003002 pSMB->hdr.smb_buf_length += byte_count;
3003 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003004
Steve French790fe572007-07-07 19:25:05 +00003005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3007 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003008 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003009 } else {
3010 /* decode response */
3011 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3012 if (rc || (pSMBr->ByteCount < 2))
3013 /* BB also check enough total bytes returned */
3014 /* If rc should we check for EOPNOSUPP and
3015 disable the srvino flag? or in caller? */
3016 rc = -EIO; /* bad smb */
3017 else {
3018 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3019 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3020 struct file_chattr_info *pfinfo;
3021 /* BB Do we need a cast or hash here ? */
3022 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003023 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003024 rc = -EIO;
3025 goto GetExtAttrOut;
3026 }
3027 pfinfo = (struct file_chattr_info *)
3028 (data_offset + (char *) &pSMBr->hdr.Protocol);
3029 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003030 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003031 }
3032 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003033GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003034 cifs_buf_release(pSMB);
3035 if (rc == -EAGAIN)
3036 goto GetExtAttrRetry;
3037 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003038}
3039
Steve Frenchf654bac2005-04-28 22:41:04 -07003040#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Steve French297647c2007-10-12 04:11:59 +00003042#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003043/* Get Security Descriptor (by handle) from remote server for a file or dir */
3044int
3045CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003046 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003047{
3048 int rc = 0;
3049 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003050 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003051 struct kvec iov[1];
3052
Joe Perchesb6b38f72010-04-21 03:50:45 +00003053 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003054
Steve French630f3f0c2007-10-25 21:17:17 +00003055 *pbuflen = 0;
3056 *acl_inf = NULL;
3057
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003058 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003059 8 /* parm len */, tcon, (void **) &pSMB);
3060 if (rc)
3061 return rc;
3062
3063 pSMB->MaxParameterCount = cpu_to_le32(4);
3064 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3065 pSMB->MaxSetupCount = 0;
3066 pSMB->Fid = fid; /* file handle always le */
3067 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3068 CIFS_ACL_DACL);
3069 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3070 pSMB->hdr.smb_buf_length += 11;
3071 iov[0].iov_base = (char *)pSMB;
3072 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3073
Steve Frencha761ac52007-10-18 21:45:27 +00003074 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003075 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003076 cifs_stats_inc(&tcon->num_acl_get);
3077 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003078 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003079 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003080 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003081 __u32 parm_len;
3082 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003083 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003084 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003085
3086/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003087 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003088 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003089 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003090 goto qsec_out;
3091 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3092
Joe Perchesb6b38f72010-04-21 03:50:45 +00003093 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003094
3095 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3096 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003097 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003098 goto qsec_out;
3099 }
3100
3101/* BB check that data area is minimum length and as big as acl_len */
3102
Steve Frenchaf6f4612007-10-16 18:40:37 +00003103 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003104 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003105 cERROR(1, "acl length %d does not match %d",
3106 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003107 if (*pbuflen > acl_len)
3108 *pbuflen = acl_len;
3109 }
Steve French0a4b92c2006-01-12 15:44:21 -08003110
Steve French630f3f0c2007-10-25 21:17:17 +00003111 /* check if buffer is big enough for the acl
3112 header followed by the smallest SID */
3113 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3114 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003115 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003116 rc = -EINVAL;
3117 *pbuflen = 0;
3118 } else {
3119 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3120 if (*acl_inf == NULL) {
3121 *pbuflen = 0;
3122 rc = -ENOMEM;
3123 }
3124 memcpy(*acl_inf, pdata, *pbuflen);
3125 }
Steve French0a4b92c2006-01-12 15:44:21 -08003126 }
3127qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003128 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003129 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003130 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003131 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003132/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003133 return rc;
3134}
Steve French97837582007-12-31 07:47:21 +00003135
3136int
3137CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3138 struct cifs_ntsd *pntsd, __u32 acllen)
3139{
3140 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3141 int rc = 0;
3142 int bytes_returned = 0;
3143 SET_SEC_DESC_REQ *pSMB = NULL;
3144 NTRANSACT_RSP *pSMBr = NULL;
3145
3146setCifsAclRetry:
3147 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3148 (void **) &pSMBr);
3149 if (rc)
3150 return (rc);
3151
3152 pSMB->MaxSetupCount = 0;
3153 pSMB->Reserved = 0;
3154
3155 param_count = 8;
3156 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3157 data_count = acllen;
3158 data_offset = param_offset + param_count;
3159 byte_count = 3 /* pad */ + param_count;
3160
3161 pSMB->DataCount = cpu_to_le32(data_count);
3162 pSMB->TotalDataCount = pSMB->DataCount;
3163 pSMB->MaxParameterCount = cpu_to_le32(4);
3164 pSMB->MaxDataCount = cpu_to_le32(16384);
3165 pSMB->ParameterCount = cpu_to_le32(param_count);
3166 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3167 pSMB->TotalParameterCount = pSMB->ParameterCount;
3168 pSMB->DataOffset = cpu_to_le32(data_offset);
3169 pSMB->SetupCount = 0;
3170 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3171 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3172
3173 pSMB->Fid = fid; /* file handle always le */
3174 pSMB->Reserved2 = 0;
3175 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3176
3177 if (pntsd && acllen) {
3178 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3179 (char *) pntsd,
3180 acllen);
3181 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3182
3183 } else
3184 pSMB->hdr.smb_buf_length += byte_count;
3185
3186 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3187 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3188
Joe Perchesb6b38f72010-04-21 03:50:45 +00003189 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003190 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003191 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003192 cifs_buf_release(pSMB);
3193
3194 if (rc == -EAGAIN)
3195 goto setCifsAclRetry;
3196
3197 return (rc);
3198}
3199
Steve French297647c2007-10-12 04:11:59 +00003200#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003201
Steve French6b8edfe2005-08-23 20:26:03 -07003202/* Legacy Query Path Information call for lookup to old servers such
3203 as Win9x/WinME */
3204int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003205 const unsigned char *searchName,
3206 FILE_ALL_INFO *pFinfo,
3207 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003208{
Steve Frenchad7a2922008-02-07 23:25:02 +00003209 QUERY_INFORMATION_REQ *pSMB;
3210 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003211 int rc = 0;
3212 int bytes_returned;
3213 int name_len;
3214
Joe Perchesb6b38f72010-04-21 03:50:45 +00003215 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003216QInfRetry:
3217 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003218 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003219 if (rc)
3220 return rc;
3221
3222 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3223 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003224 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3225 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003226 name_len++; /* trailing null */
3227 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003228 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003229 name_len = strnlen(searchName, PATH_MAX);
3230 name_len++; /* trailing null */
3231 strncpy(pSMB->FileName, searchName, name_len);
3232 }
3233 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003234 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003235 pSMB->hdr.smb_buf_length += (__u16) name_len;
3236 pSMB->ByteCount = cpu_to_le16(name_len);
3237
3238 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003239 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003240 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003241 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003242 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003243 struct timespec ts;
3244 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003245
3246 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003247 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003248 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003249 ts.tv_nsec = 0;
3250 ts.tv_sec = time;
3251 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003252 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003253 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3254 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003255 pFinfo->AllocationSize =
3256 cpu_to_le64(le32_to_cpu(pSMBr->size));
3257 pFinfo->EndOfFile = pFinfo->AllocationSize;
3258 pFinfo->Attributes =
3259 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003260 } else
3261 rc = -EIO; /* bad buffer passed in */
3262
3263 cifs_buf_release(pSMB);
3264
3265 if (rc == -EAGAIN)
3266 goto QInfRetry;
3267
3268 return rc;
3269}
3270
Jeff Laytonbcd53572010-02-12 07:44:16 -05003271int
3272CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3273 u16 netfid, FILE_ALL_INFO *pFindData)
3274{
3275 struct smb_t2_qfi_req *pSMB = NULL;
3276 struct smb_t2_qfi_rsp *pSMBr = NULL;
3277 int rc = 0;
3278 int bytes_returned;
3279 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003280
Jeff Laytonbcd53572010-02-12 07:44:16 -05003281QFileInfoRetry:
3282 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3283 (void **) &pSMBr);
3284 if (rc)
3285 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003286
Jeff Laytonbcd53572010-02-12 07:44:16 -05003287 params = 2 /* level */ + 2 /* fid */;
3288 pSMB->t2.TotalDataCount = 0;
3289 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3290 /* BB find exact max data count below from sess structure BB */
3291 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3292 pSMB->t2.MaxSetupCount = 0;
3293 pSMB->t2.Reserved = 0;
3294 pSMB->t2.Flags = 0;
3295 pSMB->t2.Timeout = 0;
3296 pSMB->t2.Reserved2 = 0;
3297 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3298 Fid) - 4);
3299 pSMB->t2.DataCount = 0;
3300 pSMB->t2.DataOffset = 0;
3301 pSMB->t2.SetupCount = 1;
3302 pSMB->t2.Reserved3 = 0;
3303 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3304 byte_count = params + 1 /* pad */ ;
3305 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3306 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3307 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3308 pSMB->Pad = 0;
3309 pSMB->Fid = netfid;
3310 pSMB->hdr.smb_buf_length += byte_count;
3311
3312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3314 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003315 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003316 } else { /* decode response */
3317 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3318
3319 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3320 rc = -EIO;
3321 else if (pSMBr->ByteCount < 40)
3322 rc = -EIO; /* bad smb */
3323 else if (pFindData) {
3324 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3325 memcpy((char *) pFindData,
3326 (char *) &pSMBr->hdr.Protocol +
3327 data_offset, sizeof(FILE_ALL_INFO));
3328 } else
3329 rc = -ENOMEM;
3330 }
3331 cifs_buf_release(pSMB);
3332 if (rc == -EAGAIN)
3333 goto QFileInfoRetry;
3334
3335 return rc;
3336}
Steve French6b8edfe2005-08-23 20:26:03 -07003337
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338int
3339CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3340 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003341 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003342 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003343 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344{
3345/* level 263 SMB_QUERY_FILE_ALL_INFO */
3346 TRANSACTION2_QPI_REQ *pSMB = NULL;
3347 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3348 int rc = 0;
3349 int bytes_returned;
3350 int name_len;
3351 __u16 params, byte_count;
3352
Joe Perchesb6b38f72010-04-21 03:50:45 +00003353/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354QPathInfoRetry:
3355 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3356 (void **) &pSMBr);
3357 if (rc)
3358 return rc;
3359
3360 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3361 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003362 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003363 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 name_len++; /* trailing null */
3365 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003366 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 name_len = strnlen(searchName, PATH_MAX);
3368 name_len++; /* trailing null */
3369 strncpy(pSMB->FileName, searchName, name_len);
3370 }
3371
Steve French50c2f752007-07-13 00:33:32 +00003372 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 pSMB->TotalDataCount = 0;
3374 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003375 /* BB find exact max SMB PDU from sess structure BB */
3376 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 pSMB->MaxSetupCount = 0;
3378 pSMB->Reserved = 0;
3379 pSMB->Flags = 0;
3380 pSMB->Timeout = 0;
3381 pSMB->Reserved2 = 0;
3382 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003383 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 pSMB->DataCount = 0;
3385 pSMB->DataOffset = 0;
3386 pSMB->SetupCount = 1;
3387 pSMB->Reserved3 = 0;
3388 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3389 byte_count = params + 1 /* pad */ ;
3390 pSMB->TotalParameterCount = cpu_to_le16(params);
3391 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003392 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003393 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3394 else
3395 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 pSMB->Reserved4 = 0;
3397 pSMB->hdr.smb_buf_length += byte_count;
3398 pSMB->ByteCount = cpu_to_le16(byte_count);
3399
3400 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3401 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3402 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003403 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 } else { /* decode response */
3405 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3406
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003407 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3408 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003409 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003411 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003412 rc = -EIO; /* 24 or 26 expected but we do not read
3413 last field */
3414 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003415 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003417
3418 /* On legacy responses we do not read the last field,
3419 EAsize, fortunately since it varies by subdialect and
3420 also note it differs on Set vs. Get, ie two bytes or 4
3421 bytes depending but we don't care here */
3422 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003423 size = sizeof(FILE_INFO_STANDARD);
3424 else
3425 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 memcpy((char *) pFindData,
3427 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003428 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 } else
3430 rc = -ENOMEM;
3431 }
3432 cifs_buf_release(pSMB);
3433 if (rc == -EAGAIN)
3434 goto QPathInfoRetry;
3435
3436 return rc;
3437}
3438
3439int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003440CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3441 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3442{
3443 struct smb_t2_qfi_req *pSMB = NULL;
3444 struct smb_t2_qfi_rsp *pSMBr = NULL;
3445 int rc = 0;
3446 int bytes_returned;
3447 __u16 params, byte_count;
3448
3449UnixQFileInfoRetry:
3450 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3451 (void **) &pSMBr);
3452 if (rc)
3453 return rc;
3454
3455 params = 2 /* level */ + 2 /* fid */;
3456 pSMB->t2.TotalDataCount = 0;
3457 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3458 /* BB find exact max data count below from sess structure BB */
3459 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3460 pSMB->t2.MaxSetupCount = 0;
3461 pSMB->t2.Reserved = 0;
3462 pSMB->t2.Flags = 0;
3463 pSMB->t2.Timeout = 0;
3464 pSMB->t2.Reserved2 = 0;
3465 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3466 Fid) - 4);
3467 pSMB->t2.DataCount = 0;
3468 pSMB->t2.DataOffset = 0;
3469 pSMB->t2.SetupCount = 1;
3470 pSMB->t2.Reserved3 = 0;
3471 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3472 byte_count = params + 1 /* pad */ ;
3473 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3474 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3475 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3476 pSMB->Pad = 0;
3477 pSMB->Fid = netfid;
3478 pSMB->hdr.smb_buf_length += byte_count;
3479
3480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3482 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003483 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003484 } else { /* decode response */
3485 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3486
3487 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003488 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003489 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003490 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003491 rc = -EIO; /* bad smb */
3492 } else {
3493 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3494 memcpy((char *) pFindData,
3495 (char *) &pSMBr->hdr.Protocol +
3496 data_offset,
3497 sizeof(FILE_UNIX_BASIC_INFO));
3498 }
3499 }
3500
3501 cifs_buf_release(pSMB);
3502 if (rc == -EAGAIN)
3503 goto UnixQFileInfoRetry;
3504
3505 return rc;
3506}
3507
3508int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3510 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003511 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003512 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513{
3514/* SMB_QUERY_FILE_UNIX_BASIC */
3515 TRANSACTION2_QPI_REQ *pSMB = NULL;
3516 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3517 int rc = 0;
3518 int bytes_returned = 0;
3519 int name_len;
3520 __u16 params, byte_count;
3521
Joe Perchesb6b38f72010-04-21 03:50:45 +00003522 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523UnixQPathInfoRetry:
3524 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3525 (void **) &pSMBr);
3526 if (rc)
3527 return rc;
3528
3529 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3530 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003531 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003532 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 name_len++; /* trailing null */
3534 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003535 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 name_len = strnlen(searchName, PATH_MAX);
3537 name_len++; /* trailing null */
3538 strncpy(pSMB->FileName, searchName, name_len);
3539 }
3540
Steve French50c2f752007-07-13 00:33:32 +00003541 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 pSMB->TotalDataCount = 0;
3543 pSMB->MaxParameterCount = cpu_to_le16(2);
3544 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003545 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 pSMB->MaxSetupCount = 0;
3547 pSMB->Reserved = 0;
3548 pSMB->Flags = 0;
3549 pSMB->Timeout = 0;
3550 pSMB->Reserved2 = 0;
3551 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003552 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 pSMB->DataCount = 0;
3554 pSMB->DataOffset = 0;
3555 pSMB->SetupCount = 1;
3556 pSMB->Reserved3 = 0;
3557 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3558 byte_count = params + 1 /* pad */ ;
3559 pSMB->TotalParameterCount = cpu_to_le16(params);
3560 pSMB->ParameterCount = pSMB->TotalParameterCount;
3561 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3562 pSMB->Reserved4 = 0;
3563 pSMB->hdr.smb_buf_length += byte_count;
3564 pSMB->ByteCount = cpu_to_le16(byte_count);
3565
3566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3568 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003569 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 } else { /* decode response */
3571 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3572
3573 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003574 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003575 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003576 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 rc = -EIO; /* bad smb */
3578 } else {
3579 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3580 memcpy((char *) pFindData,
3581 (char *) &pSMBr->hdr.Protocol +
3582 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003583 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 }
3585 }
3586 cifs_buf_release(pSMB);
3587 if (rc == -EAGAIN)
3588 goto UnixQPathInfoRetry;
3589
3590 return rc;
3591}
3592
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593/* xid, tcon, searchName and codepage are input parms, rest are returned */
3594int
3595CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003596 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003598 __u16 *pnetfid,
3599 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600{
3601/* level 257 SMB_ */
3602 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3603 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003604 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605 int rc = 0;
3606 int bytes_returned = 0;
3607 int name_len;
3608 __u16 params, byte_count;
3609
Joe Perchesb6b38f72010-04-21 03:50:45 +00003610 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
3612findFirstRetry:
3613 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3614 (void **) &pSMBr);
3615 if (rc)
3616 return rc;
3617
3618 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3619 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003620 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003621 PATH_MAX, nls_codepage, remap);
3622 /* We can not add the asterik earlier in case
3623 it got remapped to 0xF03A as if it were part of the
3624 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003626 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003627 pSMB->FileName[name_len+1] = 0;
3628 pSMB->FileName[name_len+2] = '*';
3629 pSMB->FileName[name_len+3] = 0;
3630 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3632 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003633 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 } else { /* BB add check for overrun of SMB buf BB */
3635 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003637 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 free buffer exit; BB */
3639 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003640 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003641 pSMB->FileName[name_len+1] = '*';
3642 pSMB->FileName[name_len+2] = 0;
3643 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 }
3645
3646 params = 12 + name_len /* includes null */ ;
3647 pSMB->TotalDataCount = 0; /* no EAs */
3648 pSMB->MaxParameterCount = cpu_to_le16(10);
3649 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3650 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3651 pSMB->MaxSetupCount = 0;
3652 pSMB->Reserved = 0;
3653 pSMB->Flags = 0;
3654 pSMB->Timeout = 0;
3655 pSMB->Reserved2 = 0;
3656 byte_count = params + 1 /* pad */ ;
3657 pSMB->TotalParameterCount = cpu_to_le16(params);
3658 pSMB->ParameterCount = pSMB->TotalParameterCount;
3659 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003660 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3661 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662 pSMB->DataCount = 0;
3663 pSMB->DataOffset = 0;
3664 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3665 pSMB->Reserved3 = 0;
3666 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3667 pSMB->SearchAttributes =
3668 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3669 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003670 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3671 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 CIFS_SEARCH_RETURN_RESUME);
3673 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3674
3675 /* BB what should we set StorageType to? Does it matter? BB */
3676 pSMB->SearchStorageType = 0;
3677 pSMB->hdr.smb_buf_length += byte_count;
3678 pSMB->ByteCount = cpu_to_le16(byte_count);
3679
3680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003682 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
Steve French88274812006-03-09 22:21:45 +00003684 if (rc) {/* BB add logic to retry regular search if Unix search
3685 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003687 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003688
Steve French88274812006-03-09 22:21:45 +00003689 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690
3691 /* BB eventually could optimize out free and realloc of buf */
3692 /* for this case */
3693 if (rc == -EAGAIN)
3694 goto findFirstRetry;
3695 } else { /* decode response */
3696 /* BB remember to free buffer if error BB */
3697 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003698 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003699 unsigned int lnoff;
3700
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003702 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 else
Steve French4b18f2a2008-04-29 00:06:05 +00003704 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
3706 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003707 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003708 psrch_inf->srch_entries_start =
3709 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3712 le16_to_cpu(pSMBr->t2.ParameterOffset));
3713
Steve French790fe572007-07-07 19:25:05 +00003714 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003715 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716 else
Steve French4b18f2a2008-04-29 00:06:05 +00003717 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
Steve French50c2f752007-07-13 00:33:32 +00003719 psrch_inf->entries_in_buffer =
3720 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003721 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003723 lnoff = le16_to_cpu(parms->LastNameOffset);
3724 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3725 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003726 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003727 psrch_inf->last_entry = NULL;
3728 return rc;
3729 }
3730
Steve French0752f152008-10-07 20:03:33 +00003731 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003732 lnoff;
3733
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 *pnetfid = parms->SearchHandle;
3735 } else {
3736 cifs_buf_release(pSMB);
3737 }
3738 }
3739
3740 return rc;
3741}
3742
3743int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003744 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745{
3746 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3747 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003748 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 char *response_data;
3750 int rc = 0;
3751 int bytes_returned, name_len;
3752 __u16 params, byte_count;
3753
Joe Perchesb6b38f72010-04-21 03:50:45 +00003754 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755
Steve French4b18f2a2008-04-29 00:06:05 +00003756 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 return -ENOENT;
3758
3759 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3760 (void **) &pSMBr);
3761 if (rc)
3762 return rc;
3763
Steve French50c2f752007-07-13 00:33:32 +00003764 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 byte_count = 0;
3766 pSMB->TotalDataCount = 0; /* no EAs */
3767 pSMB->MaxParameterCount = cpu_to_le16(8);
3768 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003769 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3770 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771 pSMB->MaxSetupCount = 0;
3772 pSMB->Reserved = 0;
3773 pSMB->Flags = 0;
3774 pSMB->Timeout = 0;
3775 pSMB->Reserved2 = 0;
3776 pSMB->ParameterOffset = cpu_to_le16(
3777 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3778 pSMB->DataCount = 0;
3779 pSMB->DataOffset = 0;
3780 pSMB->SetupCount = 1;
3781 pSMB->Reserved3 = 0;
3782 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3783 pSMB->SearchHandle = searchHandle; /* always kept as le */
3784 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003785 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3787 pSMB->ResumeKey = psrch_inf->resume_key;
3788 pSMB->SearchFlags =
3789 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3790
3791 name_len = psrch_inf->resume_name_len;
3792 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003793 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3795 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003796 /* 14 byte parm len above enough for 2 byte null terminator */
3797 pSMB->ResumeFileName[name_len] = 0;
3798 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 } else {
3800 rc = -EINVAL;
3801 goto FNext2_err_exit;
3802 }
3803 byte_count = params + 1 /* pad */ ;
3804 pSMB->TotalParameterCount = cpu_to_le16(params);
3805 pSMB->ParameterCount = pSMB->TotalParameterCount;
3806 pSMB->hdr.smb_buf_length += byte_count;
3807 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003808
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003811 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 if (rc) {
3813 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003814 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003815 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003816 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003818 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 } else { /* decode response */
3820 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003821
Steve French790fe572007-07-07 19:25:05 +00003822 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003823 unsigned int lnoff;
3824
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 /* BB fixme add lock for file (srch_info) struct here */
3826 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003827 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 else
Steve French4b18f2a2008-04-29 00:06:05 +00003829 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830 response_data = (char *) &pSMBr->hdr.Protocol +
3831 le16_to_cpu(pSMBr->t2.ParameterOffset);
3832 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3833 response_data = (char *)&pSMBr->hdr.Protocol +
3834 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003835 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003836 cifs_small_buf_release(
3837 psrch_inf->ntwrk_buf_start);
3838 else
3839 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 psrch_inf->srch_entries_start = response_data;
3841 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003842 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003843 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003844 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 else
Steve French4b18f2a2008-04-29 00:06:05 +00003846 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003847 psrch_inf->entries_in_buffer =
3848 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 psrch_inf->index_of_last_entry +=
3850 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003851 lnoff = le16_to_cpu(parms->LastNameOffset);
3852 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3853 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003854 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003855 psrch_inf->last_entry = NULL;
3856 return rc;
3857 } else
3858 psrch_inf->last_entry =
3859 psrch_inf->srch_entries_start + lnoff;
3860
Joe Perchesb6b38f72010-04-21 03:50:45 +00003861/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3862 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863
3864 /* BB fixme add unlock here */
3865 }
3866
3867 }
3868
3869 /* BB On error, should we leave previous search buf (and count and
3870 last entry fields) intact or free the previous one? */
3871
3872 /* Note: On -EAGAIN error only caller can retry on handle based calls
3873 since file handle passed in no longer valid */
3874FNext2_err_exit:
3875 if (rc != 0)
3876 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 return rc;
3878}
3879
3880int
Steve French50c2f752007-07-13 00:33:32 +00003881CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3882 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883{
3884 int rc = 0;
3885 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886
Joe Perchesb6b38f72010-04-21 03:50:45 +00003887 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3889
3890 /* no sense returning error if session restarted
3891 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003892 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 return 0;
3894 if (rc)
3895 return rc;
3896
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 pSMB->FileID = searchHandle;
3898 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003899 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003900 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003901 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003902
Steve Frencha4544342005-08-24 13:59:35 -07003903 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904
3905 /* Since session is dead, search handle closed on server already */
3906 if (rc == -EAGAIN)
3907 rc = 0;
3908
3909 return rc;
3910}
3911
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912int
3913CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003914 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003915 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003916 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917{
3918 int rc = 0;
3919 TRANSACTION2_QPI_REQ *pSMB = NULL;
3920 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3921 int name_len, bytes_returned;
3922 __u16 params, byte_count;
3923
Joe Perchesb6b38f72010-04-21 03:50:45 +00003924 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003925 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003926 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927
3928GetInodeNumberRetry:
3929 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003930 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 if (rc)
3932 return rc;
3933
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3935 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003936 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003937 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 name_len++; /* trailing null */
3939 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003940 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 name_len = strnlen(searchName, PATH_MAX);
3942 name_len++; /* trailing null */
3943 strncpy(pSMB->FileName, searchName, name_len);
3944 }
3945
3946 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3947 pSMB->TotalDataCount = 0;
3948 pSMB->MaxParameterCount = cpu_to_le16(2);
3949 /* BB find exact max data count below from sess structure BB */
3950 pSMB->MaxDataCount = cpu_to_le16(4000);
3951 pSMB->MaxSetupCount = 0;
3952 pSMB->Reserved = 0;
3953 pSMB->Flags = 0;
3954 pSMB->Timeout = 0;
3955 pSMB->Reserved2 = 0;
3956 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003957 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 pSMB->DataCount = 0;
3959 pSMB->DataOffset = 0;
3960 pSMB->SetupCount = 1;
3961 pSMB->Reserved3 = 0;
3962 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3963 byte_count = params + 1 /* pad */ ;
3964 pSMB->TotalParameterCount = cpu_to_le16(params);
3965 pSMB->ParameterCount = pSMB->TotalParameterCount;
3966 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3967 pSMB->Reserved4 = 0;
3968 pSMB->hdr.smb_buf_length += byte_count;
3969 pSMB->ByteCount = cpu_to_le16(byte_count);
3970
3971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3973 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003974 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 } else {
3976 /* decode response */
3977 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3978 if (rc || (pSMBr->ByteCount < 2))
3979 /* BB also check enough total bytes returned */
3980 /* If rc should we check for EOPNOSUPP and
3981 disable the srvino flag? or in caller? */
3982 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003983 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3985 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003986 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003988 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003989 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 rc = -EIO;
3991 goto GetInodeNumOut;
3992 }
3993 pfinfo = (struct file_internal_info *)
3994 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003995 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 }
3997 }
3998GetInodeNumOut:
3999 cifs_buf_release(pSMB);
4000 if (rc == -EAGAIN)
4001 goto GetInodeNumberRetry;
4002 return rc;
4003}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004
Igor Mammedovfec45852008-05-16 13:06:30 +04004005/* parses DFS refferal V3 structure
4006 * caller is responsible for freeing target_nodes
4007 * returns:
4008 * on success - 0
4009 * on failure - errno
4010 */
4011static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004012parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004013 unsigned int *num_of_nodes,
4014 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004015 const struct nls_table *nls_codepage, int remap,
4016 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004017{
4018 int i, rc = 0;
4019 char *data_end;
4020 bool is_unicode;
4021 struct dfs_referral_level_3 *ref;
4022
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004023 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4024 is_unicode = true;
4025 else
4026 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004027 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4028
4029 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004030 cERROR(1, "num_referrals: must be at least > 0,"
4031 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004032 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004033 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004034 }
4035
4036 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004037 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004038 cERROR(1, "Referrals of V%d version are not supported,"
4039 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004040 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004041 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004042 }
4043
4044 /* get the upper boundary of the resp buffer */
4045 data_end = (char *)(&(pSMBr->PathConsumed)) +
4046 le16_to_cpu(pSMBr->t2.DataCount);
4047
Steve Frenchf19159d2010-04-21 04:12:10 +00004048 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004049 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004050 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004051
4052 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4053 *num_of_nodes, GFP_KERNEL);
4054 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004055 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004056 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004057 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004058 }
4059
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004060 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004061 for (i = 0; i < *num_of_nodes; i++) {
4062 char *temp;
4063 int max_len;
4064 struct dfs_info3_param *node = (*target_nodes)+i;
4065
Steve French0e0d2cf2009-05-01 05:27:32 +00004066 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004067 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004068 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4069 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004070 if (tmp == NULL) {
4071 rc = -ENOMEM;
4072 goto parse_DFS_referrals_exit;
4073 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004074 cifsConvertToUCS((__le16 *) tmp, searchName,
4075 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004076 node->path_consumed = cifs_ucs2_bytes(tmp,
4077 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004078 nls_codepage);
4079 kfree(tmp);
4080 } else
4081 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4082
Igor Mammedovfec45852008-05-16 13:06:30 +04004083 node->server_type = le16_to_cpu(ref->ServerType);
4084 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4085
4086 /* copy DfsPath */
4087 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4088 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004089 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4090 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004091 if (!node->path_name) {
4092 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004093 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004094 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004095
4096 /* copy link target UNC */
4097 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4098 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004099 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4100 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004101 if (!node->node_name)
4102 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004103 }
4104
Steve Frencha1fe78f2008-05-16 18:48:38 +00004105parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004106 if (rc) {
4107 free_dfs_info_array(*target_nodes, *num_of_nodes);
4108 *target_nodes = NULL;
4109 *num_of_nodes = 0;
4110 }
4111 return rc;
4112}
4113
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114int
4115CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4116 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004117 struct dfs_info3_param **target_nodes,
4118 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004119 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120{
4121/* TRANS2_GET_DFS_REFERRAL */
4122 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4123 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 int rc = 0;
4125 int bytes_returned;
4126 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004128 *num_of_nodes = 0;
4129 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130
Joe Perchesb6b38f72010-04-21 03:50:45 +00004131 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 if (ses == NULL)
4133 return -ENODEV;
4134getDFSRetry:
4135 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4136 (void **) &pSMBr);
4137 if (rc)
4138 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004139
4140 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004141 but should never be null here anyway */
4142 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 pSMB->hdr.Tid = ses->ipc_tid;
4144 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004145 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004147 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
4150 if (ses->capabilities & CAP_UNICODE) {
4151 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4152 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004153 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004154 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 name_len++; /* trailing null */
4156 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004157 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 name_len = strnlen(searchName, PATH_MAX);
4159 name_len++; /* trailing null */
4160 strncpy(pSMB->RequestFileName, searchName, name_len);
4161 }
4162
Steve French790fe572007-07-07 19:25:05 +00004163 if (ses->server) {
4164 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004165 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4166 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4167 }
4168
Steve French50c2f752007-07-13 00:33:32 +00004169 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004170
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 params = 2 /* level */ + name_len /*includes null */ ;
4172 pSMB->TotalDataCount = 0;
4173 pSMB->DataCount = 0;
4174 pSMB->DataOffset = 0;
4175 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004176 /* BB find exact max SMB PDU from sess structure BB */
4177 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 pSMB->MaxSetupCount = 0;
4179 pSMB->Reserved = 0;
4180 pSMB->Flags = 0;
4181 pSMB->Timeout = 0;
4182 pSMB->Reserved2 = 0;
4183 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004184 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 pSMB->SetupCount = 1;
4186 pSMB->Reserved3 = 0;
4187 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4188 byte_count = params + 3 /* pad */ ;
4189 pSMB->ParameterCount = cpu_to_le16(params);
4190 pSMB->TotalParameterCount = pSMB->ParameterCount;
4191 pSMB->MaxReferralLevel = cpu_to_le16(3);
4192 pSMB->hdr.smb_buf_length += byte_count;
4193 pSMB->ByteCount = cpu_to_le16(byte_count);
4194
4195 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4196 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4197 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004198 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004199 goto GetDFSRefExit;
4200 }
4201 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004203 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004204 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004205 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004206 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004208
Joe Perchesb6b38f72010-04-21 03:50:45 +00004209 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Igor Mammedovfec45852008-05-16 13:06:30 +04004210 pSMBr->ByteCount,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004211 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004212
4213 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004214 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004215 target_nodes, nls_codepage, remap,
4216 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004217
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004219 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220
4221 if (rc == -EAGAIN)
4222 goto getDFSRetry;
4223
4224 return rc;
4225}
4226
Steve French20962432005-09-21 22:05:57 -07004227/* Query File System Info such as free space to old servers such as Win 9x */
4228int
4229SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4230{
4231/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4232 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4233 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4234 FILE_SYSTEM_ALLOC_INFO *response_data;
4235 int rc = 0;
4236 int bytes_returned = 0;
4237 __u16 params, byte_count;
4238
Joe Perchesb6b38f72010-04-21 03:50:45 +00004239 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004240oldQFSInfoRetry:
4241 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4242 (void **) &pSMBr);
4243 if (rc)
4244 return rc;
Steve French20962432005-09-21 22:05:57 -07004245
4246 params = 2; /* level */
4247 pSMB->TotalDataCount = 0;
4248 pSMB->MaxParameterCount = cpu_to_le16(2);
4249 pSMB->MaxDataCount = cpu_to_le16(1000);
4250 pSMB->MaxSetupCount = 0;
4251 pSMB->Reserved = 0;
4252 pSMB->Flags = 0;
4253 pSMB->Timeout = 0;
4254 pSMB->Reserved2 = 0;
4255 byte_count = params + 1 /* pad */ ;
4256 pSMB->TotalParameterCount = cpu_to_le16(params);
4257 pSMB->ParameterCount = pSMB->TotalParameterCount;
4258 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4259 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4260 pSMB->DataCount = 0;
4261 pSMB->DataOffset = 0;
4262 pSMB->SetupCount = 1;
4263 pSMB->Reserved3 = 0;
4264 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4265 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4266 pSMB->hdr.smb_buf_length += byte_count;
4267 pSMB->ByteCount = cpu_to_le16(byte_count);
4268
4269 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4270 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4271 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004272 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004273 } else { /* decode response */
4274 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4275
4276 if (rc || (pSMBr->ByteCount < 18))
4277 rc = -EIO; /* bad smb */
4278 else {
4279 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004280 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4281 pSMBr->ByteCount, data_offset);
Steve French20962432005-09-21 22:05:57 -07004282
Steve French50c2f752007-07-13 00:33:32 +00004283 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004284 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4285 FSData->f_bsize =
4286 le16_to_cpu(response_data->BytesPerSector) *
4287 le32_to_cpu(response_data->
4288 SectorsPerAllocationUnit);
4289 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004290 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004291 FSData->f_bfree = FSData->f_bavail =
4292 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004293 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4294 (unsigned long long)FSData->f_blocks,
4295 (unsigned long long)FSData->f_bfree,
4296 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004297 }
4298 }
4299 cifs_buf_release(pSMB);
4300
4301 if (rc == -EAGAIN)
4302 goto oldQFSInfoRetry;
4303
4304 return rc;
4305}
4306
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307int
Steve French737b7582005-04-28 22:41:06 -07004308CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309{
4310/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4311 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4312 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4313 FILE_SYSTEM_INFO *response_data;
4314 int rc = 0;
4315 int bytes_returned = 0;
4316 __u16 params, byte_count;
4317
Joe Perchesb6b38f72010-04-21 03:50:45 +00004318 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319QFSInfoRetry:
4320 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4321 (void **) &pSMBr);
4322 if (rc)
4323 return rc;
4324
4325 params = 2; /* level */
4326 pSMB->TotalDataCount = 0;
4327 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004328 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 pSMB->MaxSetupCount = 0;
4330 pSMB->Reserved = 0;
4331 pSMB->Flags = 0;
4332 pSMB->Timeout = 0;
4333 pSMB->Reserved2 = 0;
4334 byte_count = params + 1 /* pad */ ;
4335 pSMB->TotalParameterCount = cpu_to_le16(params);
4336 pSMB->ParameterCount = pSMB->TotalParameterCount;
4337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004338 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 pSMB->DataCount = 0;
4340 pSMB->DataOffset = 0;
4341 pSMB->SetupCount = 1;
4342 pSMB->Reserved3 = 0;
4343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4344 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4345 pSMB->hdr.smb_buf_length += byte_count;
4346 pSMB->ByteCount = cpu_to_le16(byte_count);
4347
4348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4350 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004351 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004353 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354
Steve French20962432005-09-21 22:05:57 -07004355 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 rc = -EIO; /* bad smb */
4357 else {
4358 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359
4360 response_data =
4361 (FILE_SYSTEM_INFO
4362 *) (((char *) &pSMBr->hdr.Protocol) +
4363 data_offset);
4364 FSData->f_bsize =
4365 le32_to_cpu(response_data->BytesPerSector) *
4366 le32_to_cpu(response_data->
4367 SectorsPerAllocationUnit);
4368 FSData->f_blocks =
4369 le64_to_cpu(response_data->TotalAllocationUnits);
4370 FSData->f_bfree = FSData->f_bavail =
4371 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004372 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4373 (unsigned long long)FSData->f_blocks,
4374 (unsigned long long)FSData->f_bfree,
4375 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 }
4377 }
4378 cifs_buf_release(pSMB);
4379
4380 if (rc == -EAGAIN)
4381 goto QFSInfoRetry;
4382
4383 return rc;
4384}
4385
4386int
Steve French737b7582005-04-28 22:41:06 -07004387CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388{
4389/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4390 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4391 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4392 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4393 int rc = 0;
4394 int bytes_returned = 0;
4395 __u16 params, byte_count;
4396
Joe Perchesb6b38f72010-04-21 03:50:45 +00004397 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398QFSAttributeRetry:
4399 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4400 (void **) &pSMBr);
4401 if (rc)
4402 return rc;
4403
4404 params = 2; /* level */
4405 pSMB->TotalDataCount = 0;
4406 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004407 /* BB find exact max SMB PDU from sess structure BB */
4408 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409 pSMB->MaxSetupCount = 0;
4410 pSMB->Reserved = 0;
4411 pSMB->Flags = 0;
4412 pSMB->Timeout = 0;
4413 pSMB->Reserved2 = 0;
4414 byte_count = params + 1 /* pad */ ;
4415 pSMB->TotalParameterCount = cpu_to_le16(params);
4416 pSMB->ParameterCount = pSMB->TotalParameterCount;
4417 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004418 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 pSMB->DataCount = 0;
4420 pSMB->DataOffset = 0;
4421 pSMB->SetupCount = 1;
4422 pSMB->Reserved3 = 0;
4423 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4424 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4425 pSMB->hdr.smb_buf_length += byte_count;
4426 pSMB->ByteCount = cpu_to_le16(byte_count);
4427
4428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4430 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004431 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 } else { /* decode response */
4433 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4434
Steve French50c2f752007-07-13 00:33:32 +00004435 if (rc || (pSMBr->ByteCount < 13)) {
4436 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 rc = -EIO; /* bad smb */
4438 } else {
4439 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4440 response_data =
4441 (FILE_SYSTEM_ATTRIBUTE_INFO
4442 *) (((char *) &pSMBr->hdr.Protocol) +
4443 data_offset);
4444 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004445 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 }
4447 }
4448 cifs_buf_release(pSMB);
4449
4450 if (rc == -EAGAIN)
4451 goto QFSAttributeRetry;
4452
4453 return rc;
4454}
4455
4456int
Steve French737b7582005-04-28 22:41:06 -07004457CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458{
4459/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4460 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4461 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4462 FILE_SYSTEM_DEVICE_INFO *response_data;
4463 int rc = 0;
4464 int bytes_returned = 0;
4465 __u16 params, byte_count;
4466
Joe Perchesb6b38f72010-04-21 03:50:45 +00004467 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468QFSDeviceRetry:
4469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4470 (void **) &pSMBr);
4471 if (rc)
4472 return rc;
4473
4474 params = 2; /* level */
4475 pSMB->TotalDataCount = 0;
4476 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004477 /* BB find exact max SMB PDU from sess structure BB */
4478 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 pSMB->MaxSetupCount = 0;
4480 pSMB->Reserved = 0;
4481 pSMB->Flags = 0;
4482 pSMB->Timeout = 0;
4483 pSMB->Reserved2 = 0;
4484 byte_count = params + 1 /* pad */ ;
4485 pSMB->TotalParameterCount = cpu_to_le16(params);
4486 pSMB->ParameterCount = pSMB->TotalParameterCount;
4487 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004488 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489
4490 pSMB->DataCount = 0;
4491 pSMB->DataOffset = 0;
4492 pSMB->SetupCount = 1;
4493 pSMB->Reserved3 = 0;
4494 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4495 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4496 pSMB->hdr.smb_buf_length += byte_count;
4497 pSMB->ByteCount = cpu_to_le16(byte_count);
4498
4499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4501 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004502 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 } else { /* decode response */
4504 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4505
Steve French630f3f0c2007-10-25 21:17:17 +00004506 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 rc = -EIO; /* bad smb */
4508 else {
4509 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4510 response_data =
Steve French737b7582005-04-28 22:41:06 -07004511 (FILE_SYSTEM_DEVICE_INFO *)
4512 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 data_offset);
4514 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004515 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 }
4517 }
4518 cifs_buf_release(pSMB);
4519
4520 if (rc == -EAGAIN)
4521 goto QFSDeviceRetry;
4522
4523 return rc;
4524}
4525
4526int
Steve French737b7582005-04-28 22:41:06 -07004527CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528{
4529/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4530 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4531 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4532 FILE_SYSTEM_UNIX_INFO *response_data;
4533 int rc = 0;
4534 int bytes_returned = 0;
4535 __u16 params, byte_count;
4536
Joe Perchesb6b38f72010-04-21 03:50:45 +00004537 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538QFSUnixRetry:
4539 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4540 (void **) &pSMBr);
4541 if (rc)
4542 return rc;
4543
4544 params = 2; /* level */
4545 pSMB->TotalDataCount = 0;
4546 pSMB->DataCount = 0;
4547 pSMB->DataOffset = 0;
4548 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004549 /* BB find exact max SMB PDU from sess structure BB */
4550 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551 pSMB->MaxSetupCount = 0;
4552 pSMB->Reserved = 0;
4553 pSMB->Flags = 0;
4554 pSMB->Timeout = 0;
4555 pSMB->Reserved2 = 0;
4556 byte_count = params + 1 /* pad */ ;
4557 pSMB->ParameterCount = cpu_to_le16(params);
4558 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004559 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4560 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 pSMB->SetupCount = 1;
4562 pSMB->Reserved3 = 0;
4563 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4564 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4565 pSMB->hdr.smb_buf_length += byte_count;
4566 pSMB->ByteCount = cpu_to_le16(byte_count);
4567
4568 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4569 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4570 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004571 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 } else { /* decode response */
4573 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4574
4575 if (rc || (pSMBr->ByteCount < 13)) {
4576 rc = -EIO; /* bad smb */
4577 } else {
4578 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4579 response_data =
4580 (FILE_SYSTEM_UNIX_INFO
4581 *) (((char *) &pSMBr->hdr.Protocol) +
4582 data_offset);
4583 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004584 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585 }
4586 }
4587 cifs_buf_release(pSMB);
4588
4589 if (rc == -EAGAIN)
4590 goto QFSUnixRetry;
4591
4592
4593 return rc;
4594}
4595
Jeremy Allisonac670552005-06-22 17:26:35 -07004596int
Steve French45abc6e2005-06-23 13:42:03 -05004597CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004598{
4599/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4600 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4601 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4602 int rc = 0;
4603 int bytes_returned = 0;
4604 __u16 params, param_offset, offset, byte_count;
4605
Joe Perchesb6b38f72010-04-21 03:50:45 +00004606 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004607SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004608 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4610 (void **) &pSMBr);
4611 if (rc)
4612 return rc;
4613
4614 params = 4; /* 2 bytes zero followed by info level. */
4615 pSMB->MaxSetupCount = 0;
4616 pSMB->Reserved = 0;
4617 pSMB->Flags = 0;
4618 pSMB->Timeout = 0;
4619 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004620 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4621 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004622 offset = param_offset + params;
4623
4624 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004625 /* BB find exact max SMB PDU from sess structure BB */
4626 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004627 pSMB->SetupCount = 1;
4628 pSMB->Reserved3 = 0;
4629 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4630 byte_count = 1 /* pad */ + params + 12;
4631
4632 pSMB->DataCount = cpu_to_le16(12);
4633 pSMB->ParameterCount = cpu_to_le16(params);
4634 pSMB->TotalDataCount = pSMB->DataCount;
4635 pSMB->TotalParameterCount = pSMB->ParameterCount;
4636 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4637 pSMB->DataOffset = cpu_to_le16(offset);
4638
4639 /* Params. */
4640 pSMB->FileNum = 0;
4641 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4642
4643 /* Data. */
4644 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4645 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4646 pSMB->ClientUnixCap = cpu_to_le64(cap);
4647
4648 pSMB->hdr.smb_buf_length += byte_count;
4649 pSMB->ByteCount = cpu_to_le16(byte_count);
4650
4651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4653 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004654 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004655 } else { /* decode response */
4656 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004657 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004658 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004659 }
4660 cifs_buf_release(pSMB);
4661
4662 if (rc == -EAGAIN)
4663 goto SETFSUnixRetry;
4664
4665 return rc;
4666}
4667
4668
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
4670int
4671CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004672 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673{
4674/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4675 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4676 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4677 FILE_SYSTEM_POSIX_INFO *response_data;
4678 int rc = 0;
4679 int bytes_returned = 0;
4680 __u16 params, byte_count;
4681
Joe Perchesb6b38f72010-04-21 03:50:45 +00004682 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683QFSPosixRetry:
4684 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4685 (void **) &pSMBr);
4686 if (rc)
4687 return rc;
4688
4689 params = 2; /* level */
4690 pSMB->TotalDataCount = 0;
4691 pSMB->DataCount = 0;
4692 pSMB->DataOffset = 0;
4693 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004694 /* BB find exact max SMB PDU from sess structure BB */
4695 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 pSMB->MaxSetupCount = 0;
4697 pSMB->Reserved = 0;
4698 pSMB->Flags = 0;
4699 pSMB->Timeout = 0;
4700 pSMB->Reserved2 = 0;
4701 byte_count = params + 1 /* pad */ ;
4702 pSMB->ParameterCount = cpu_to_le16(params);
4703 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004704 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4705 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 pSMB->SetupCount = 1;
4707 pSMB->Reserved3 = 0;
4708 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4709 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4710 pSMB->hdr.smb_buf_length += byte_count;
4711 pSMB->ByteCount = cpu_to_le16(byte_count);
4712
4713 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4714 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4715 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004716 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 } else { /* decode response */
4718 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4719
4720 if (rc || (pSMBr->ByteCount < 13)) {
4721 rc = -EIO; /* bad smb */
4722 } else {
4723 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4724 response_data =
4725 (FILE_SYSTEM_POSIX_INFO
4726 *) (((char *) &pSMBr->hdr.Protocol) +
4727 data_offset);
4728 FSData->f_bsize =
4729 le32_to_cpu(response_data->BlockSize);
4730 FSData->f_blocks =
4731 le64_to_cpu(response_data->TotalBlocks);
4732 FSData->f_bfree =
4733 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004734 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 FSData->f_bavail = FSData->f_bfree;
4736 } else {
4737 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004738 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 }
Steve French790fe572007-07-07 19:25:05 +00004740 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004742 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004743 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004745 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 }
4747 }
4748 cifs_buf_release(pSMB);
4749
4750 if (rc == -EAGAIN)
4751 goto QFSPosixRetry;
4752
4753 return rc;
4754}
4755
4756
Steve French50c2f752007-07-13 00:33:32 +00004757/* We can not use write of zero bytes trick to
4758 set file size due to need for large file support. Also note that
4759 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 routine which is only needed to work around a sharing violation bug
4761 in Samba which this routine can run into */
4762
4763int
4764CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004765 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004766 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767{
4768 struct smb_com_transaction2_spi_req *pSMB = NULL;
4769 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4770 struct file_end_of_file_info *parm_data;
4771 int name_len;
4772 int rc = 0;
4773 int bytes_returned = 0;
4774 __u16 params, byte_count, data_count, param_offset, offset;
4775
Joe Perchesb6b38f72010-04-21 03:50:45 +00004776 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777SetEOFRetry:
4778 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4779 (void **) &pSMBr);
4780 if (rc)
4781 return rc;
4782
4783 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4784 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004785 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004786 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 name_len++; /* trailing null */
4788 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004789 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 name_len = strnlen(fileName, PATH_MAX);
4791 name_len++; /* trailing null */
4792 strncpy(pSMB->FileName, fileName, name_len);
4793 }
4794 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004795 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004797 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 pSMB->MaxSetupCount = 0;
4799 pSMB->Reserved = 0;
4800 pSMB->Flags = 0;
4801 pSMB->Timeout = 0;
4802 pSMB->Reserved2 = 0;
4803 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004804 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004806 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004807 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4808 pSMB->InformationLevel =
4809 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4810 else
4811 pSMB->InformationLevel =
4812 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4813 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4815 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004816 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817 else
4818 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004819 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 }
4821
4822 parm_data =
4823 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4824 offset);
4825 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4826 pSMB->DataOffset = cpu_to_le16(offset);
4827 pSMB->SetupCount = 1;
4828 pSMB->Reserved3 = 0;
4829 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4830 byte_count = 3 /* pad */ + params + data_count;
4831 pSMB->DataCount = cpu_to_le16(data_count);
4832 pSMB->TotalDataCount = pSMB->DataCount;
4833 pSMB->ParameterCount = cpu_to_le16(params);
4834 pSMB->TotalParameterCount = pSMB->ParameterCount;
4835 pSMB->Reserved4 = 0;
4836 pSMB->hdr.smb_buf_length += byte_count;
4837 parm_data->FileSize = cpu_to_le64(size);
4838 pSMB->ByteCount = cpu_to_le16(byte_count);
4839 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4840 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004841 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004842 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843
4844 cifs_buf_release(pSMB);
4845
4846 if (rc == -EAGAIN)
4847 goto SetEOFRetry;
4848
4849 return rc;
4850}
4851
4852int
Steve French50c2f752007-07-13 00:33:32 +00004853CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004854 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855{
4856 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 char *data_offset;
4858 struct file_end_of_file_info *parm_data;
4859 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860 __u16 params, param_offset, offset, byte_count, count;
4861
Joe Perchesb6b38f72010-04-21 03:50:45 +00004862 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4863 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004864 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4865
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 if (rc)
4867 return rc;
4868
4869 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4870 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004871
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 params = 6;
4873 pSMB->MaxSetupCount = 0;
4874 pSMB->Reserved = 0;
4875 pSMB->Flags = 0;
4876 pSMB->Timeout = 0;
4877 pSMB->Reserved2 = 0;
4878 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4879 offset = param_offset + params;
4880
Steve French50c2f752007-07-13 00:33:32 +00004881 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882
4883 count = sizeof(struct file_end_of_file_info);
4884 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004885 /* BB find exact max SMB PDU from sess structure BB */
4886 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 pSMB->SetupCount = 1;
4888 pSMB->Reserved3 = 0;
4889 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4890 byte_count = 3 /* pad */ + params + count;
4891 pSMB->DataCount = cpu_to_le16(count);
4892 pSMB->ParameterCount = cpu_to_le16(params);
4893 pSMB->TotalDataCount = pSMB->DataCount;
4894 pSMB->TotalParameterCount = pSMB->ParameterCount;
4895 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4896 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004897 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4898 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 pSMB->DataOffset = cpu_to_le16(offset);
4900 parm_data->FileSize = cpu_to_le64(size);
4901 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004902 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4904 pSMB->InformationLevel =
4905 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4906 else
4907 pSMB->InformationLevel =
4908 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004909 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4911 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004912 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 else
4914 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004915 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 }
4917 pSMB->Reserved4 = 0;
4918 pSMB->hdr.smb_buf_length += byte_count;
4919 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004920 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004921 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004922 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 }
4924
Steve French50c2f752007-07-13 00:33:32 +00004925 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 since file handle passed in no longer valid */
4927
4928 return rc;
4929}
4930
Steve French50c2f752007-07-13 00:33:32 +00004931/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 an open handle, rather than by pathname - this is awkward due to
4933 potential access conflicts on the open, but it is unavoidable for these
4934 old servers since the only other choice is to go from 100 nanosecond DCE
4935 time and resort to the original setpathinfo level which takes the ancient
4936 DOS time format with 2 second granularity */
4937int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004938CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4939 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940{
4941 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942 char *data_offset;
4943 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944 __u16 params, param_offset, offset, byte_count, count;
4945
Joe Perchesb6b38f72010-04-21 03:50:45 +00004946 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07004947 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4948
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 if (rc)
4950 return rc;
4951
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004952 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4953 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004954
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 params = 6;
4956 pSMB->MaxSetupCount = 0;
4957 pSMB->Reserved = 0;
4958 pSMB->Flags = 0;
4959 pSMB->Timeout = 0;
4960 pSMB->Reserved2 = 0;
4961 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4962 offset = param_offset + params;
4963
Steve French50c2f752007-07-13 00:33:32 +00004964 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004965
Steve French26f57362007-08-30 22:09:15 +00004966 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004968 /* BB find max SMB PDU from sess */
4969 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970 pSMB->SetupCount = 1;
4971 pSMB->Reserved3 = 0;
4972 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4973 byte_count = 3 /* pad */ + params + count;
4974 pSMB->DataCount = cpu_to_le16(count);
4975 pSMB->ParameterCount = cpu_to_le16(params);
4976 pSMB->TotalDataCount = pSMB->DataCount;
4977 pSMB->TotalParameterCount = pSMB->ParameterCount;
4978 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4979 pSMB->DataOffset = cpu_to_le16(offset);
4980 pSMB->Fid = fid;
4981 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4982 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4983 else
4984 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4985 pSMB->Reserved4 = 0;
4986 pSMB->hdr.smb_buf_length += byte_count;
4987 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004988 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004989 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004990 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004991 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992
Steve French50c2f752007-07-13 00:33:32 +00004993 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994 since file handle passed in no longer valid */
4995
4996 return rc;
4997}
4998
Jeff Layton6d22f092008-09-23 11:48:35 -04004999int
5000CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5001 bool delete_file, __u16 fid, __u32 pid_of_opener)
5002{
5003 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5004 char *data_offset;
5005 int rc = 0;
5006 __u16 params, param_offset, offset, byte_count, count;
5007
Joe Perchesb6b38f72010-04-21 03:50:45 +00005008 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005009 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5010
5011 if (rc)
5012 return rc;
5013
5014 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5015 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5016
5017 params = 6;
5018 pSMB->MaxSetupCount = 0;
5019 pSMB->Reserved = 0;
5020 pSMB->Flags = 0;
5021 pSMB->Timeout = 0;
5022 pSMB->Reserved2 = 0;
5023 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5024 offset = param_offset + params;
5025
5026 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5027
5028 count = 1;
5029 pSMB->MaxParameterCount = cpu_to_le16(2);
5030 /* BB find max SMB PDU from sess */
5031 pSMB->MaxDataCount = cpu_to_le16(1000);
5032 pSMB->SetupCount = 1;
5033 pSMB->Reserved3 = 0;
5034 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5035 byte_count = 3 /* pad */ + params + count;
5036 pSMB->DataCount = cpu_to_le16(count);
5037 pSMB->ParameterCount = cpu_to_le16(params);
5038 pSMB->TotalDataCount = pSMB->DataCount;
5039 pSMB->TotalParameterCount = pSMB->ParameterCount;
5040 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5041 pSMB->DataOffset = cpu_to_le16(offset);
5042 pSMB->Fid = fid;
5043 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5044 pSMB->Reserved4 = 0;
5045 pSMB->hdr.smb_buf_length += byte_count;
5046 pSMB->ByteCount = cpu_to_le16(byte_count);
5047 *data_offset = delete_file ? 1 : 0;
5048 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5049 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005050 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005051
5052 return rc;
5053}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054
5055int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005056CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5057 const char *fileName, const FILE_BASIC_INFO *data,
5058 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059{
5060 TRANSACTION2_SPI_REQ *pSMB = NULL;
5061 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5062 int name_len;
5063 int rc = 0;
5064 int bytes_returned = 0;
5065 char *data_offset;
5066 __u16 params, param_offset, offset, byte_count, count;
5067
Joe Perchesb6b38f72010-04-21 03:50:45 +00005068 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069
5070SetTimesRetry:
5071 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5072 (void **) &pSMBr);
5073 if (rc)
5074 return rc;
5075
5076 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5077 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005078 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005079 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 name_len++; /* trailing null */
5081 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005082 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 name_len = strnlen(fileName, PATH_MAX);
5084 name_len++; /* trailing null */
5085 strncpy(pSMB->FileName, fileName, name_len);
5086 }
5087
5088 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005089 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005091 /* BB find max SMB PDU from sess structure BB */
5092 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 pSMB->MaxSetupCount = 0;
5094 pSMB->Reserved = 0;
5095 pSMB->Flags = 0;
5096 pSMB->Timeout = 0;
5097 pSMB->Reserved2 = 0;
5098 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005099 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100 offset = param_offset + params;
5101 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5102 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5103 pSMB->DataOffset = cpu_to_le16(offset);
5104 pSMB->SetupCount = 1;
5105 pSMB->Reserved3 = 0;
5106 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5107 byte_count = 3 /* pad */ + params + count;
5108
5109 pSMB->DataCount = cpu_to_le16(count);
5110 pSMB->ParameterCount = cpu_to_le16(params);
5111 pSMB->TotalDataCount = pSMB->DataCount;
5112 pSMB->TotalParameterCount = pSMB->ParameterCount;
5113 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5114 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5115 else
5116 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5117 pSMB->Reserved4 = 0;
5118 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005119 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 pSMB->ByteCount = cpu_to_le16(byte_count);
5121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005123 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005124 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125
5126 cifs_buf_release(pSMB);
5127
5128 if (rc == -EAGAIN)
5129 goto SetTimesRetry;
5130
5131 return rc;
5132}
5133
5134/* Can not be used to set time stamps yet (due to old DOS time format) */
5135/* Can be used to set attributes */
5136#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5137 handling it anyway and NT4 was what we thought it would be needed for
5138 Do not delete it until we prove whether needed for Win9x though */
5139int
5140CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5141 __u16 dos_attrs, const struct nls_table *nls_codepage)
5142{
5143 SETATTR_REQ *pSMB = NULL;
5144 SETATTR_RSP *pSMBr = NULL;
5145 int rc = 0;
5146 int bytes_returned;
5147 int name_len;
5148
Joe Perchesb6b38f72010-04-21 03:50:45 +00005149 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150
5151SetAttrLgcyRetry:
5152 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5153 (void **) &pSMBr);
5154 if (rc)
5155 return rc;
5156
5157 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5158 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005159 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 PATH_MAX, nls_codepage);
5161 name_len++; /* trailing null */
5162 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005163 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 name_len = strnlen(fileName, PATH_MAX);
5165 name_len++; /* trailing null */
5166 strncpy(pSMB->fileName, fileName, name_len);
5167 }
5168 pSMB->attr = cpu_to_le16(dos_attrs);
5169 pSMB->BufferFormat = 0x04;
5170 pSMB->hdr.smb_buf_length += name_len + 1;
5171 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005174 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005175 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176
5177 cifs_buf_release(pSMB);
5178
5179 if (rc == -EAGAIN)
5180 goto SetAttrLgcyRetry;
5181
5182 return rc;
5183}
5184#endif /* temporarily unneeded SetAttr legacy function */
5185
Jeff Layton654cf142009-07-09 20:02:49 -04005186static void
5187cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5188 const struct cifs_unix_set_info_args *args)
5189{
5190 u64 mode = args->mode;
5191
5192 /*
5193 * Samba server ignores set of file size to zero due to bugs in some
5194 * older clients, but we should be precise - we use SetFileSize to
5195 * set file size and do not want to truncate file size to zero
5196 * accidently as happened on one Samba server beta by putting
5197 * zero instead of -1 here
5198 */
5199 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5200 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5201 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5202 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5203 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5204 data_offset->Uid = cpu_to_le64(args->uid);
5205 data_offset->Gid = cpu_to_le64(args->gid);
5206 /* better to leave device as zero when it is */
5207 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5208 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5209 data_offset->Permissions = cpu_to_le64(mode);
5210
5211 if (S_ISREG(mode))
5212 data_offset->Type = cpu_to_le32(UNIX_FILE);
5213 else if (S_ISDIR(mode))
5214 data_offset->Type = cpu_to_le32(UNIX_DIR);
5215 else if (S_ISLNK(mode))
5216 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5217 else if (S_ISCHR(mode))
5218 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5219 else if (S_ISBLK(mode))
5220 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5221 else if (S_ISFIFO(mode))
5222 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5223 else if (S_ISSOCK(mode))
5224 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5225}
5226
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005228CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5229 const struct cifs_unix_set_info_args *args,
5230 u16 fid, u32 pid_of_opener)
5231{
5232 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5233 FILE_UNIX_BASIC_INFO *data_offset;
5234 int rc = 0;
5235 u16 params, param_offset, offset, byte_count, count;
5236
Joe Perchesb6b38f72010-04-21 03:50:45 +00005237 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005238 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5239
5240 if (rc)
5241 return rc;
5242
5243 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5244 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5245
5246 params = 6;
5247 pSMB->MaxSetupCount = 0;
5248 pSMB->Reserved = 0;
5249 pSMB->Flags = 0;
5250 pSMB->Timeout = 0;
5251 pSMB->Reserved2 = 0;
5252 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5253 offset = param_offset + params;
5254
5255 data_offset = (FILE_UNIX_BASIC_INFO *)
5256 ((char *)(&pSMB->hdr.Protocol) + offset);
5257 count = sizeof(FILE_UNIX_BASIC_INFO);
5258
5259 pSMB->MaxParameterCount = cpu_to_le16(2);
5260 /* BB find max SMB PDU from sess */
5261 pSMB->MaxDataCount = cpu_to_le16(1000);
5262 pSMB->SetupCount = 1;
5263 pSMB->Reserved3 = 0;
5264 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5265 byte_count = 3 /* pad */ + params + count;
5266 pSMB->DataCount = cpu_to_le16(count);
5267 pSMB->ParameterCount = cpu_to_le16(params);
5268 pSMB->TotalDataCount = pSMB->DataCount;
5269 pSMB->TotalParameterCount = pSMB->ParameterCount;
5270 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5271 pSMB->DataOffset = cpu_to_le16(offset);
5272 pSMB->Fid = fid;
5273 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5274 pSMB->Reserved4 = 0;
5275 pSMB->hdr.smb_buf_length += byte_count;
5276 pSMB->ByteCount = cpu_to_le16(byte_count);
5277
5278 cifs_fill_unix_set_info(data_offset, args);
5279
5280 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5281 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005282 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005283
5284 /* Note: On -EAGAIN error only caller can retry on handle based calls
5285 since file handle passed in no longer valid */
5286
5287 return rc;
5288}
5289
5290int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005291CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5292 const struct cifs_unix_set_info_args *args,
5293 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294{
5295 TRANSACTION2_SPI_REQ *pSMB = NULL;
5296 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5297 int name_len;
5298 int rc = 0;
5299 int bytes_returned = 0;
5300 FILE_UNIX_BASIC_INFO *data_offset;
5301 __u16 params, param_offset, offset, count, byte_count;
5302
Joe Perchesb6b38f72010-04-21 03:50:45 +00005303 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304setPermsRetry:
5305 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5306 (void **) &pSMBr);
5307 if (rc)
5308 return rc;
5309
5310 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5311 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005312 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005313 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 name_len++; /* trailing null */
5315 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005316 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 name_len = strnlen(fileName, PATH_MAX);
5318 name_len++; /* trailing null */
5319 strncpy(pSMB->FileName, fileName, name_len);
5320 }
5321
5322 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005323 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005325 /* BB find max SMB PDU from sess structure BB */
5326 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327 pSMB->MaxSetupCount = 0;
5328 pSMB->Reserved = 0;
5329 pSMB->Flags = 0;
5330 pSMB->Timeout = 0;
5331 pSMB->Reserved2 = 0;
5332 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005333 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 offset = param_offset + params;
5335 data_offset =
5336 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5337 offset);
5338 memset(data_offset, 0, count);
5339 pSMB->DataOffset = cpu_to_le16(offset);
5340 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5341 pSMB->SetupCount = 1;
5342 pSMB->Reserved3 = 0;
5343 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5344 byte_count = 3 /* pad */ + params + count;
5345 pSMB->ParameterCount = cpu_to_le16(params);
5346 pSMB->DataCount = cpu_to_le16(count);
5347 pSMB->TotalParameterCount = pSMB->ParameterCount;
5348 pSMB->TotalDataCount = pSMB->DataCount;
5349 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5350 pSMB->Reserved4 = 0;
5351 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005352
Jeff Layton654cf142009-07-09 20:02:49 -04005353 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354
5355 pSMB->ByteCount = cpu_to_le16(byte_count);
5356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005358 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005359 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360
Steve French0d817bc2008-05-22 02:02:03 +00005361 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 if (rc == -EAGAIN)
5363 goto setPermsRetry;
5364 return rc;
5365}
5366
Steve French50c2f752007-07-13 00:33:32 +00005367int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005368 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005369 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005370 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005371{
5372 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005373 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5374 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005375 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 int bytes_returned;
5377
Joe Perchesb6b38f72010-04-21 03:50:45 +00005378 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005380 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 if (rc)
5382 return rc;
5383
5384 pSMB->TotalParameterCount = 0 ;
5385 pSMB->TotalDataCount = 0;
5386 pSMB->MaxParameterCount = cpu_to_le32(2);
5387 /* BB find exact data count max from sess structure BB */
5388 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005389/* BB VERIFY verify which is correct for above BB */
5390 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5391 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5392
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 pSMB->MaxSetupCount = 4;
5394 pSMB->Reserved = 0;
5395 pSMB->ParameterOffset = 0;
5396 pSMB->DataCount = 0;
5397 pSMB->DataOffset = 0;
5398 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5399 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5400 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005401 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5403 pSMB->Reserved2 = 0;
5404 pSMB->CompletionFilter = cpu_to_le32(filter);
5405 pSMB->Fid = netfid; /* file handle always le */
5406 pSMB->ByteCount = 0;
5407
5408 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005409 (struct smb_hdr *)pSMBr, &bytes_returned,
5410 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005412 cFYI(1, "Error in Notify = %d", rc);
Steve Frenchff5dbd92005-08-24 17:10:36 -07005413 } else {
5414 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005415 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005416 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005417 sizeof(struct dir_notify_req),
5418 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005419 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005420 dnotify_req->Pid = pSMB->hdr.Pid;
5421 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5422 dnotify_req->Mid = pSMB->hdr.Mid;
5423 dnotify_req->Tid = pSMB->hdr.Tid;
5424 dnotify_req->Uid = pSMB->hdr.Uid;
5425 dnotify_req->netfid = netfid;
5426 dnotify_req->pfile = pfile;
5427 dnotify_req->filter = filter;
5428 dnotify_req->multishot = multishot;
5429 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005430 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005431 &GlobalDnotifyReqList);
5432 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005433 } else
Steve French47c786e2005-10-11 20:03:18 -07005434 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435 }
5436 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005437 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438}
Jeff Layton31c05192010-02-10 16:18:26 -05005439
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005441/*
5442 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5443 * function used by listxattr and getxattr type calls. When ea_name is set,
5444 * it looks for that attribute name and stuffs that value into the EAData
5445 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5446 * buffer. In both cases, the return value is either the length of the
5447 * resulting data or a negative error code. If EAData is a NULL pointer then
5448 * the data isn't copied to it, but the length is returned.
5449 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450ssize_t
5451CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005452 const unsigned char *searchName, const unsigned char *ea_name,
5453 char *EAData, size_t buf_size,
5454 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455{
5456 /* BB assumes one setup word */
5457 TRANSACTION2_QPI_REQ *pSMB = NULL;
5458 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5459 int rc = 0;
5460 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005461 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005462 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005463 struct fea *temp_fea;
5464 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005465 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005466 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467
Joe Perchesb6b38f72010-04-21 03:50:45 +00005468 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469QAllEAsRetry:
5470 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5471 (void **) &pSMBr);
5472 if (rc)
5473 return rc;
5474
5475 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005476 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005477 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005478 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005479 list_len++; /* trailing null */
5480 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005482 list_len = strnlen(searchName, PATH_MAX);
5483 list_len++; /* trailing null */
5484 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 }
5486
Jeff Layton6e462b92010-02-10 16:18:26 -05005487 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 pSMB->TotalDataCount = 0;
5489 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005490 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005491 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 pSMB->MaxSetupCount = 0;
5493 pSMB->Reserved = 0;
5494 pSMB->Flags = 0;
5495 pSMB->Timeout = 0;
5496 pSMB->Reserved2 = 0;
5497 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005498 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 pSMB->DataCount = 0;
5500 pSMB->DataOffset = 0;
5501 pSMB->SetupCount = 1;
5502 pSMB->Reserved3 = 0;
5503 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5504 byte_count = params + 1 /* pad */ ;
5505 pSMB->TotalParameterCount = cpu_to_le16(params);
5506 pSMB->ParameterCount = pSMB->TotalParameterCount;
5507 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5508 pSMB->Reserved4 = 0;
5509 pSMB->hdr.smb_buf_length += byte_count;
5510 pSMB->ByteCount = cpu_to_le16(byte_count);
5511
5512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5513 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5514 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005515 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005516 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005518
5519
5520 /* BB also check enough total bytes returned */
5521 /* BB we need to improve the validity checking
5522 of these trans2 responses */
5523
5524 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5525 if (rc || (pSMBr->ByteCount < 4)) {
5526 rc = -EIO; /* bad smb */
5527 goto QAllEAsOut;
5528 }
5529
5530 /* check that length of list is not more than bcc */
5531 /* check that each entry does not go beyond length
5532 of list */
5533 /* check that each element of each entry does not
5534 go beyond end of list */
5535 /* validate_trans2_offsets() */
5536 /* BB check if start of smb + data_offset > &bcc+ bcc */
5537
5538 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5539 ea_response_data = (struct fealist *)
5540 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5541
Jeff Layton6e462b92010-02-10 16:18:26 -05005542 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005543 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005544 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005545 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005546 goto QAllEAsOut;
5547 }
5548
Jeff Layton0cd126b2010-02-10 16:18:26 -05005549 /* make sure list_len doesn't go past end of SMB */
5550 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5551 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005552 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005553 rc = -EIO;
5554 goto QAllEAsOut;
5555 }
5556
Jeff Laytonf0d38682010-02-10 16:18:26 -05005557 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005558 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005559 temp_fea = ea_response_data->list;
5560 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005561 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005562 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005563 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005564
Jeff Layton6e462b92010-02-10 16:18:26 -05005565 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005566 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005567 /* make sure we can read name_len and value_len */
5568 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005569 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005570 rc = -EIO;
5571 goto QAllEAsOut;
5572 }
5573
5574 name_len = temp_fea->name_len;
5575 value_len = le16_to_cpu(temp_fea->value_len);
5576 list_len -= name_len + 1 + value_len;
5577 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005578 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005579 rc = -EIO;
5580 goto QAllEAsOut;
5581 }
5582
Jeff Layton31c05192010-02-10 16:18:26 -05005583 if (ea_name) {
5584 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5585 temp_ptr += name_len + 1;
5586 rc = value_len;
5587 if (buf_size == 0)
5588 goto QAllEAsOut;
5589 if ((size_t)value_len > buf_size) {
5590 rc = -ERANGE;
5591 goto QAllEAsOut;
5592 }
5593 memcpy(EAData, temp_ptr, value_len);
5594 goto QAllEAsOut;
5595 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005596 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005597 /* account for prefix user. and trailing null */
5598 rc += (5 + 1 + name_len);
5599 if (rc < (int) buf_size) {
5600 memcpy(EAData, "user.", 5);
5601 EAData += 5;
5602 memcpy(EAData, temp_ptr, name_len);
5603 EAData += name_len;
5604 /* null terminate name */
5605 *EAData = 0;
5606 ++EAData;
5607 } else if (buf_size == 0) {
5608 /* skip copy - calc size only */
5609 } else {
5610 /* stop before overrun buffer */
5611 rc = -ERANGE;
5612 break;
5613 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005614 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005615 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005616 temp_fea = (struct fea *)temp_ptr;
5617 }
5618
Jeff Layton31c05192010-02-10 16:18:26 -05005619 /* didn't find the named attribute */
5620 if (ea_name)
5621 rc = -ENODATA;
5622
Jeff Laytonf0d38682010-02-10 16:18:26 -05005623QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005624 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 if (rc == -EAGAIN)
5626 goto QAllEAsRetry;
5627
5628 return (ssize_t)rc;
5629}
5630
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631int
5632CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005633 const char *ea_name, const void *ea_value,
5634 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5635 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636{
5637 struct smb_com_transaction2_spi_req *pSMB = NULL;
5638 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5639 struct fealist *parm_data;
5640 int name_len;
5641 int rc = 0;
5642 int bytes_returned = 0;
5643 __u16 params, param_offset, byte_count, offset, count;
5644
Joe Perchesb6b38f72010-04-21 03:50:45 +00005645 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646SetEARetry:
5647 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5648 (void **) &pSMBr);
5649 if (rc)
5650 return rc;
5651
5652 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5653 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005654 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005655 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 name_len++; /* trailing null */
5657 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005658 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 name_len = strnlen(fileName, PATH_MAX);
5660 name_len++; /* trailing null */
5661 strncpy(pSMB->FileName, fileName, name_len);
5662 }
5663
5664 params = 6 + name_len;
5665
5666 /* done calculating parms using name_len of file name,
5667 now use name_len to calculate length of ea name
5668 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005669 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 name_len = 0;
5671 else
Steve French50c2f752007-07-13 00:33:32 +00005672 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00005674 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005676 /* BB find max SMB PDU from sess */
5677 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005678 pSMB->MaxSetupCount = 0;
5679 pSMB->Reserved = 0;
5680 pSMB->Flags = 0;
5681 pSMB->Timeout = 0;
5682 pSMB->Reserved2 = 0;
5683 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005684 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685 offset = param_offset + params;
5686 pSMB->InformationLevel =
5687 cpu_to_le16(SMB_SET_FILE_EA);
5688
5689 parm_data =
5690 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5691 offset);
5692 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5693 pSMB->DataOffset = cpu_to_le16(offset);
5694 pSMB->SetupCount = 1;
5695 pSMB->Reserved3 = 0;
5696 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5697 byte_count = 3 /* pad */ + params + count;
5698 pSMB->DataCount = cpu_to_le16(count);
5699 parm_data->list_len = cpu_to_le32(count);
5700 parm_data->list[0].EA_flags = 0;
5701 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005702 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005704 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005705 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706 parm_data->list[0].name[name_len] = 0;
5707 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5708 /* caller ensures that ea_value_len is less than 64K but
5709 we need to ensure that it fits within the smb */
5710
Steve French50c2f752007-07-13 00:33:32 +00005711 /*BB add length check to see if it would fit in
5712 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005713 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5714 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005715 memcpy(parm_data->list[0].name+name_len+1,
5716 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
5718 pSMB->TotalDataCount = pSMB->DataCount;
5719 pSMB->ParameterCount = cpu_to_le16(params);
5720 pSMB->TotalParameterCount = pSMB->ParameterCount;
5721 pSMB->Reserved4 = 0;
5722 pSMB->hdr.smb_buf_length += byte_count;
5723 pSMB->ByteCount = cpu_to_le16(byte_count);
5724 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5725 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005726 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005727 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728
5729 cifs_buf_release(pSMB);
5730
5731 if (rc == -EAGAIN)
5732 goto SetEARetry;
5733
5734 return rc;
5735}
5736
5737#endif