blob: f213b8ae43c1f89b96e9a3b7fb1cdd54bf373ea4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchd185cda2009-04-30 17:45:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084/* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000086static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000089 struct list_head *tmp;
90 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92/* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000095 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000096 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040097 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 }
99 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
Jeff Layton9162ab22009-09-03 12:07:17 -0400104/* reconnect the socket, tcon, and smb session if needed */
105static int
106cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
107{
108 int rc = 0;
109 struct cifsSesInfo *ses;
110 struct TCP_Server_Info *server;
111 struct nls_table *nls_codepage;
112
113 /*
114 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
115 * tcp and smb session status done differently for those three - in the
116 * calling routine
117 */
118 if (!tcon)
119 return 0;
120
121 ses = tcon->ses;
122 server = ses->server;
123
124 /*
125 * only tree disconnect, open, and write, (and ulogoff which does not
126 * have tcon) are allowed as we start force umount
127 */
128 if (tcon->tidStatus == CifsExiting) {
129 if (smb_command != SMB_COM_WRITE_ANDX &&
130 smb_command != SMB_COM_OPEN_ANDX &&
131 smb_command != SMB_COM_TREE_DISCONNECT) {
132 cFYI(1, ("can not send cmd %d while umounting",
133 smb_command));
134 return -ENODEV;
135 }
136 }
137
138 if (ses->status == CifsExiting)
139 return -EIO;
140
141 /*
142 * Give demultiplex thread up to 10 seconds to reconnect, should be
143 * greater than cifs socket timeout which is 7 seconds
144 */
145 while (server->tcpStatus == CifsNeedReconnect) {
146 wait_event_interruptible_timeout(server->response_q,
147 (server->tcpStatus == CifsGood), 10 * HZ);
148
149 /* is TCP session is reestablished now ?*/
150 if (server->tcpStatus != CifsNeedReconnect)
151 break;
152
153 /*
154 * on "soft" mounts we wait once. Hard mounts keep
155 * retrying until process is killed or server comes
156 * back on-line
157 */
158 if (!tcon->retry || ses->status == CifsExiting) {
159 cFYI(1, ("gave up waiting on reconnect in smb_init"));
160 return -EHOSTDOWN;
161 }
162 }
163
164 if (!ses->need_reconnect && !tcon->need_reconnect)
165 return 0;
166
167 nls_codepage = load_nls_default();
168
169 /*
170 * need to prevent multiple threads trying to simultaneously
171 * reconnect the same SMB session
172 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000173 mutex_lock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400174 if (ses->need_reconnect)
175 rc = cifs_setup_session(0, ses, nls_codepage);
176
177 /* do we need to reconnect tcon? */
178 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000179 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400180 goto out;
181 }
182
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000185 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400186 cFYI(1, ("reconnect tcon rc = %d", rc));
187
188 if (rc)
189 goto out;
190
191 /*
192 * FIXME: check if wsize needs updated due to negotiated smb buffer
193 * size shrinking
194 */
195 atomic_inc(&tconInfoReconnectCount);
196
197 /* tell server Unix caps we support */
198 if (ses->capabilities & CAP_UNIX)
199 reset_cifs_unix_caps(0, tcon, NULL, NULL);
200
201 /*
202 * Removed call to reopen open files here. It is safer (and faster) to
203 * reopen files one at a time as needed in read and write.
204 *
205 * FIXME: what about file locks? don't we need to reclaim them ASAP?
206 */
207
208out:
209 /*
210 * Check if handle based operation so we know whether we can continue
211 * or not without returning to caller to reset file handle
212 */
213 switch (smb_command) {
214 case SMB_COM_READ_ANDX:
215 case SMB_COM_WRITE_ANDX:
216 case SMB_COM_CLOSE:
217 case SMB_COM_FIND_CLOSE2:
218 case SMB_COM_LOCKING_ANDX:
219 rc = -EAGAIN;
220 }
221
222 unload_nls(nls_codepage);
223 return rc;
224}
225
Steve Frenchad7a2922008-02-07 23:25:02 +0000226/* Allocate and return pointer to an SMB request buffer, and set basic
227 SMB information in the SMB header. If the return code is zero, this
228 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229static int
230small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000231 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
233 int rc = 0;
234
Jeff Layton9162ab22009-09-03 12:07:17 -0400235 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000236 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return rc;
238
239 *request_buf = cifs_small_buf_get();
240 if (*request_buf == NULL) {
241 /* BB should we add a retry in here if not a writepage? */
242 return -ENOMEM;
243 }
244
Steve French63135e02007-07-17 17:34:02 +0000245 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000246 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Steve French790fe572007-07-07 19:25:05 +0000248 if (tcon != NULL)
249 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700250
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000252}
253
Steve French12b3b8f2006-02-09 21:12:47 +0000254int
Steve French50c2f752007-07-13 00:33:32 +0000255small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000256 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000257{
258 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000259 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000260
Steve French5815449d2006-02-14 01:36:20 +0000261 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000262 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000263 return rc;
264
Steve French04fdabe2006-02-10 05:52:50 +0000265 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000266 buffer->Mid = GetNextMid(ses->server);
267 if (ses->capabilities & CAP_UNICODE)
268 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000269 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000270 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
271
272 /* uid, tid can stay at zero as set in header assemble */
273
Steve French50c2f752007-07-13 00:33:32 +0000274 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000275 this function is used after 1st of session setup requests */
276
277 return rc;
278}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280/* If the return code is zero, this function must fill in request_buf pointer */
281static int
282smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
283 void **request_buf /* returned */ ,
284 void **response_buf /* returned */ )
285{
286 int rc = 0;
287
Jeff Layton9162ab22009-09-03 12:07:17 -0400288 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000289 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 return rc;
291
292 *request_buf = cifs_buf_get();
293 if (*request_buf == NULL) {
294 /* BB should we add a retry in here if not a writepage? */
295 return -ENOMEM;
296 }
297 /* Although the original thought was we needed the response buf for */
298 /* potential retries of smb operations it turns out we can determine */
299 /* from the mid flags when the request buffer can be resent without */
300 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000301 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000302 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000305 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Steve French790fe572007-07-07 19:25:05 +0000307 if (tcon != NULL)
308 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700309
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 return rc;
311}
312
Steve French50c2f752007-07-13 00:33:32 +0000313static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314{
315 int rc = -EINVAL;
316 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000317 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 /* check for plausible wct, bcc and t2 data and parm sizes */
320 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000321 if (pSMB->hdr.WordCount >= 10) {
322 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
324 /* check that bcc is at least as big as parms + data */
325 /* check that bcc is less than negotiated smb buffer */
326 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000327 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000328 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000329 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000331 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700332 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000334 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000335 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
337 return 0;
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 }
340 }
341 }
Steve French50c2f752007-07-13 00:33:32 +0000342 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 sizeof(struct smb_t2_rsp) + 16);
344 return rc;
345}
346int
347CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
348{
349 NEGOTIATE_REQ *pSMB;
350 NEGOTIATE_RSP *pSMBr;
351 int rc = 0;
352 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000353 int i;
Steve French50c2f752007-07-13 00:33:32 +0000354 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000356 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100357 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Steve French790fe572007-07-07 19:25:05 +0000359 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 server = ses->server;
361 else {
362 rc = -EIO;
363 return rc;
364 }
365 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
366 (void **) &pSMB, (void **) &pSMBr);
367 if (rc)
368 return rc;
Steve French750d1152006-06-27 06:28:30 +0000369
370 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000371 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000372 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000373 else /* if override flags set only sign/seal OR them with global auth */
374 secFlags = extended_security | ses->overrideSecFlg;
375
Steve French762e5ab2007-06-28 18:41:42 +0000376 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000377
Steve French1982c342005-08-17 12:38:22 -0700378 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000379 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000380
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000381 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000382 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000383 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
384 cFYI(1, ("Kerberos only mechanism, enable extended security"));
385 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
386 }
Steve Frenchac683922009-05-06 04:16:04 +0000387#ifdef CONFIG_CIFS_EXPERIMENTAL
388 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
389 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
390 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
391 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
392 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
393 }
394#endif
Steve French50c2f752007-07-13 00:33:32 +0000395
Steve French39798772006-05-31 22:40:51 +0000396 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000397 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000398 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
399 count += strlen(protocols[i].name) + 1;
400 /* null at end of source and target buffers anyway */
401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 pSMB->hdr.smb_buf_length += count;
403 pSMB->ByteCount = cpu_to_le16(count);
404
405 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
406 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000407 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000408 goto neg_err_exit;
409
Al Viro733f99a2006-10-14 16:48:26 +0100410 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000411 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000412 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000413 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000414 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000415 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000416 could not negotiate a common dialect */
417 rc = -EOPNOTSUPP;
418 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000419#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000420 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100421 && ((dialect == LANMAN_PROT)
422 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000423 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000424 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000425
Steve French790fe572007-07-07 19:25:05 +0000426 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000427 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000428 server->secType = LANMAN;
429 else {
430 cERROR(1, ("mount failed weak security disabled"
431 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000432 rc = -EOPNOTSUPP;
433 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000434 }
Steve French254e55e2006-06-04 05:53:15 +0000435 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
436 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
437 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000438 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000439 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000440 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
441 /* even though we do not use raw we might as well set this
442 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000443 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000444 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000445 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
446 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000447 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000448 server->capabilities = CAP_MPX_MODE;
449 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000450 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000451 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000452 /* OS/2 often does not set timezone therefore
453 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000454 * Could deviate slightly from the right zone.
455 * Smallest defined timezone difference is 15 minutes
456 * (i.e. Nepal). Rounding up/down is done to match
457 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000458 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000459 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000460 struct timespec ts, utc;
461 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400462 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
463 rsp->SrvTime.Time, 0);
Steve French50c2f752007-07-13 00:33:32 +0000464 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
465 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000466 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000467 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000468 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000469 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000470 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000471 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000472 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000473 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000474 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000475 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000476 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000477 server->timeAdj = (int)tmp;
478 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000479 }
Steve French790fe572007-07-07 19:25:05 +0000480 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000481
Steve French39798772006-05-31 22:40:51 +0000482
Steve French254e55e2006-06-04 05:53:15 +0000483 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000484 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000485
Steve French50c2f752007-07-13 00:33:32 +0000486 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000487 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000488 memcpy(server->cryptKey, rsp->EncryptionKey,
489 CIFS_CRYPTO_KEY_SIZE);
490 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
491 rc = -EIO; /* need cryptkey unless plain text */
492 goto neg_err_exit;
493 }
Steve French39798772006-05-31 22:40:51 +0000494
Steve French790fe572007-07-07 19:25:05 +0000495 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000496 /* we will not end up setting signing flags - as no signing
497 was in LANMAN and server did not return the flags on */
498 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000499#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000500 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000501 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000502 "with CIFS_WEAK_PW_HASH support"));
Dan Carpenter8212cf72010-03-15 11:22:26 +0300503 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000504#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000505 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000506 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000507 /* unknown wct */
508 rc = -EOPNOTSUPP;
509 goto neg_err_exit;
510 }
511 /* else wct == 17 NTLM */
512 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000513 if ((server->secMode & SECMODE_USER) == 0)
514 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000515
Steve French790fe572007-07-07 19:25:05 +0000516 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000517#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000518 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000519#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000520 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000521 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000522
Steve French790fe572007-07-07 19:25:05 +0000523 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000524 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000525 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000526 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000527 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000528 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000529 else if (secFlags & CIFSSEC_MAY_KRB5)
530 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000531 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000532 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000533 else if (secFlags & CIFSSEC_MAY_LANMAN)
534 server->secType = LANMAN;
535/* #ifdef CONFIG_CIFS_EXPERIMENTAL
536 else if (secFlags & CIFSSEC_MAY_PLNTXT)
537 server->secType = ??
538#endif */
539 else {
540 rc = -EOPNOTSUPP;
541 cERROR(1, ("Invalid security type"));
542 goto neg_err_exit;
543 }
544 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000545
Steve French254e55e2006-06-04 05:53:15 +0000546 /* one byte, so no need to convert this or EncryptionKeyLen from
547 little endian */
548 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
549 /* probably no need to store and check maxvcs */
550 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000552 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000553 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000554 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
555 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000556 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
557 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000558 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
559 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
560 CIFS_CRYPTO_KEY_SIZE);
561 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
562 && (pSMBr->EncryptionKeyLength == 0)) {
563 /* decode security blob */
564 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
565 rc = -EIO; /* no crypt key only if plain text pwd */
566 goto neg_err_exit;
567 }
568
569 /* BB might be helpful to save off the domain of server here */
570
Steve French50c2f752007-07-13 00:33:32 +0000571 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000572 (server->capabilities & CAP_EXTENDED_SECURITY)) {
573 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000574 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000576 goto neg_err_exit;
577 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500578 read_lock(&cifs_tcp_ses_lock);
579 if (server->srv_count > 1) {
580 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000581 if (memcmp(server->server_GUID,
582 pSMBr->u.extended_response.
583 GUID, 16) != 0) {
584 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000585 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000586 pSMBr->u.extended_response.GUID,
587 16);
588 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500589 } else {
590 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000591 memcpy(server->server_GUID,
592 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500593 }
Jeff Laytone187e442007-10-16 17:10:44 +0000594
595 if (count == 16) {
596 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000597 } else {
598 rc = decode_negTokenInit(pSMBr->u.extended_response.
599 SecurityBlob,
600 count - 16,
601 &server->secType);
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 }
Steve French254e55e2006-06-04 05:53:15 +0000607 } else
608 server->capabilities &= ~CAP_EXTENDED_SECURITY;
609
Steve French6344a422006-06-12 04:18:35 +0000610#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000611signing_check:
Steve French6344a422006-06-12 04:18:35 +0000612#endif
Steve French762e5ab2007-06-28 18:41:42 +0000613 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
614 /* MUST_SIGN already includes the MAY_SIGN FLAG
615 so if this is zero it means that signing is disabled */
616 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000617 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000618 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000619 "packet signing to be enabled in "
620 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000621 rc = -EOPNOTSUPP;
622 }
Steve French50c2f752007-07-13 00:33:32 +0000623 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000624 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000625 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
626 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000627 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000628 if ((server->secMode &
629 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
630 cERROR(1,
631 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000632 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000633 } else
634 server->secMode |= SECMODE_SIGN_REQUIRED;
635 } else {
636 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000637 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000638 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000639 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 }
Steve French50c2f752007-07-13 00:33:32 +0000641
642neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700643 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000644
Steve French790fe572007-07-07 19:25:05 +0000645 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 return rc;
647}
648
649int
650CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
651{
652 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500656
657 /* BB: do we need to check this? These should never be NULL. */
658 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
659 return -EIO;
660
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500662 * No need to return error on this operation if tid invalidated and
663 * closed on server already e.g. due to tcp session crashing. Also,
664 * the tcon is no longer on the list, so no need to take lock before
665 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 */
Steve French268875b2009-06-25 00:29:21 +0000667 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000668 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Steve French50c2f752007-07-13 00:33:32 +0000670 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700671 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500672 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return rc;
Steve French133672e2007-11-13 22:41:37 +0000674
675 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700677 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
Steve French50c2f752007-07-13 00:33:32 +0000679 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500680 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (rc == -EAGAIN)
682 rc = 0;
683
684 return rc;
685}
686
687int
688CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
689{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 LOGOFF_ANDX_REQ *pSMB;
691 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
693 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500694
695 /*
696 * BB: do we need to check validity of ses and server? They should
697 * always be valid since we have an active reference. If not, that
698 * should probably be a BUG()
699 */
700 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 return -EIO;
702
Steve Frenchd7b619c2010-02-25 05:36:46 +0000703 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000704 if (ses->need_reconnect)
705 goto session_already_dead; /* no need to send SMBlogoff if uid
706 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
708 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000709 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 return rc;
711 }
712
Steve French3b795212008-11-13 19:45:32 +0000713 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700714
Steve French3b795212008-11-13 19:45:32 +0000715 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
717 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 pSMB->hdr.Uid = ses->Suid;
720
721 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000722 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000723session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000724 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000727 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 error */
729 if (rc == -EAGAIN)
730 rc = 0;
731 return rc;
732}
733
734int
Steve French2d785a52007-07-15 01:48:57 +0000735CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
736 __u16 type, const struct nls_table *nls_codepage, int remap)
737{
738 TRANSACTION2_SPI_REQ *pSMB = NULL;
739 TRANSACTION2_SPI_RSP *pSMBr = NULL;
740 struct unlink_psx_rq *pRqD;
741 int name_len;
742 int rc = 0;
743 int bytes_returned = 0;
744 __u16 params, param_offset, offset, byte_count;
745
746 cFYI(1, ("In POSIX delete"));
747PsxDelete:
748 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
749 (void **) &pSMBr);
750 if (rc)
751 return rc;
752
753 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
754 name_len =
755 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
756 PATH_MAX, nls_codepage, remap);
757 name_len++; /* trailing null */
758 name_len *= 2;
759 } else { /* BB add path length overrun check */
760 name_len = strnlen(fileName, PATH_MAX);
761 name_len++; /* trailing null */
762 strncpy(pSMB->FileName, fileName, name_len);
763 }
764
765 params = 6 + name_len;
766 pSMB->MaxParameterCount = cpu_to_le16(2);
767 pSMB->MaxDataCount = 0; /* BB double check this with jra */
768 pSMB->MaxSetupCount = 0;
769 pSMB->Reserved = 0;
770 pSMB->Flags = 0;
771 pSMB->Timeout = 0;
772 pSMB->Reserved2 = 0;
773 param_offset = offsetof(struct smb_com_transaction2_spi_req,
774 InformationLevel) - 4;
775 offset = param_offset + params;
776
777 /* Setup pointer to Request Data (inode type) */
778 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
779 pRqD->type = cpu_to_le16(type);
780 pSMB->ParameterOffset = cpu_to_le16(param_offset);
781 pSMB->DataOffset = cpu_to_le16(offset);
782 pSMB->SetupCount = 1;
783 pSMB->Reserved3 = 0;
784 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
785 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
786
787 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
788 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
789 pSMB->ParameterCount = cpu_to_le16(params);
790 pSMB->TotalParameterCount = pSMB->ParameterCount;
791 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
792 pSMB->Reserved4 = 0;
793 pSMB->hdr.smb_buf_length += byte_count;
794 pSMB->ByteCount = cpu_to_le16(byte_count);
795 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
796 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000797 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000798 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000799 cifs_buf_release(pSMB);
800
801 cifs_stats_inc(&tcon->num_deletes);
802
803 if (rc == -EAGAIN)
804 goto PsxDelete;
805
806 return rc;
807}
808
809int
Steve French737b7582005-04-28 22:41:06 -0700810CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
811 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 DELETE_FILE_REQ *pSMB = NULL;
814 DELETE_FILE_RSP *pSMBr = NULL;
815 int rc = 0;
816 int bytes_returned;
817 int name_len;
818
819DelFileRetry:
820 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
821 (void **) &pSMBr);
822 if (rc)
823 return rc;
824
825 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
826 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000827 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700828 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 name_len++; /* trailing null */
830 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700831 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 name_len = strnlen(fileName, PATH_MAX);
833 name_len++; /* trailing null */
834 strncpy(pSMB->fileName, fileName, name_len);
835 }
836 pSMB->SearchAttributes =
837 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
838 pSMB->BufferFormat = 0x04;
839 pSMB->hdr.smb_buf_length += name_len + 1;
840 pSMB->ByteCount = cpu_to_le16(name_len + 1);
841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
842 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700843 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000844 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
847 cifs_buf_release(pSMB);
848 if (rc == -EAGAIN)
849 goto DelFileRetry;
850
851 return rc;
852}
853
854int
Steve French50c2f752007-07-13 00:33:32 +0000855CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700856 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857{
858 DELETE_DIRECTORY_REQ *pSMB = NULL;
859 DELETE_DIRECTORY_RSP *pSMBr = NULL;
860 int rc = 0;
861 int bytes_returned;
862 int name_len;
863
864 cFYI(1, ("In CIFSSMBRmDir"));
865RmDirRetry:
866 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
867 (void **) &pSMBr);
868 if (rc)
869 return rc;
870
871 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700872 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
873 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 name_len++; /* trailing null */
875 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700876 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 name_len = strnlen(dirName, PATH_MAX);
878 name_len++; /* trailing null */
879 strncpy(pSMB->DirName, dirName, name_len);
880 }
881
882 pSMB->BufferFormat = 0x04;
883 pSMB->hdr.smb_buf_length += name_len + 1;
884 pSMB->ByteCount = cpu_to_le16(name_len + 1);
885 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
886 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700887 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000888 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 cifs_buf_release(pSMB);
892 if (rc == -EAGAIN)
893 goto RmDirRetry;
894 return rc;
895}
896
897int
898CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700899 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
901 int rc = 0;
902 CREATE_DIRECTORY_REQ *pSMB = NULL;
903 CREATE_DIRECTORY_RSP *pSMBr = NULL;
904 int bytes_returned;
905 int name_len;
906
907 cFYI(1, ("In CIFSSMBMkDir"));
908MkDirRetry:
909 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
910 (void **) &pSMBr);
911 if (rc)
912 return rc;
913
914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000915 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700916 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 name_len++; /* trailing null */
918 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700919 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 name_len = strnlen(name, PATH_MAX);
921 name_len++; /* trailing null */
922 strncpy(pSMB->DirName, name, name_len);
923 }
924
925 pSMB->BufferFormat = 0x04;
926 pSMB->hdr.smb_buf_length += name_len + 1;
927 pSMB->ByteCount = cpu_to_le16(name_len + 1);
928 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
929 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700930 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000931 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -0700933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 cifs_buf_release(pSMB);
935 if (rc == -EAGAIN)
936 goto MkDirRetry;
937 return rc;
938}
939
Steve French2dd29d32007-04-23 22:07:35 +0000940int
941CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000942 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000943 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000944 const struct nls_table *nls_codepage, int remap)
945{
946 TRANSACTION2_SPI_REQ *pSMB = NULL;
947 TRANSACTION2_SPI_RSP *pSMBr = NULL;
948 int name_len;
949 int rc = 0;
950 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +0000951 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +0000952 OPEN_PSX_REQ *pdata;
953 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +0000954
955 cFYI(1, ("In POSIX Create"));
956PsxCreat:
957 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
958 (void **) &pSMBr);
959 if (rc)
960 return rc;
961
962 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
963 name_len =
964 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
965 PATH_MAX, nls_codepage, remap);
966 name_len++; /* trailing null */
967 name_len *= 2;
968 } else { /* BB improve the check for buffer overruns BB */
969 name_len = strnlen(name, PATH_MAX);
970 name_len++; /* trailing null */
971 strncpy(pSMB->FileName, name, name_len);
972 }
973
974 params = 6 + name_len;
975 count = sizeof(OPEN_PSX_REQ);
976 pSMB->MaxParameterCount = cpu_to_le16(2);
977 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
978 pSMB->MaxSetupCount = 0;
979 pSMB->Reserved = 0;
980 pSMB->Flags = 0;
981 pSMB->Timeout = 0;
982 pSMB->Reserved2 = 0;
983 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000984 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000985 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +0000986 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000987 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +0000988 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000989 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000990 pdata->OpenFlags = cpu_to_le32(*pOplock);
991 pSMB->ParameterOffset = cpu_to_le16(param_offset);
992 pSMB->DataOffset = cpu_to_le16(offset);
993 pSMB->SetupCount = 1;
994 pSMB->Reserved3 = 0;
995 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
996 byte_count = 3 /* pad */ + params + count;
997
998 pSMB->DataCount = cpu_to_le16(count);
999 pSMB->ParameterCount = cpu_to_le16(params);
1000 pSMB->TotalDataCount = pSMB->DataCount;
1001 pSMB->TotalParameterCount = pSMB->ParameterCount;
1002 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1003 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001004 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001005 pSMB->ByteCount = cpu_to_le16(byte_count);
1006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1008 if (rc) {
1009 cFYI(1, ("Posix create returned %d", rc));
1010 goto psx_create_err;
1011 }
1012
Steve French790fe572007-07-07 19:25:05 +00001013 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001014 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1015
1016 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1017 rc = -EIO; /* bad smb */
1018 goto psx_create_err;
1019 }
1020
1021 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001022 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001023 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001024
Steve French2dd29d32007-04-23 22:07:35 +00001025 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001026 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001027 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1028 /* Let caller know file was created so we can set the mode. */
1029 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001030 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001031 *pOplock |= CIFS_CREATE_ACTION;
1032 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001033 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1034 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001035 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001036 } else {
Steve French790fe572007-07-07 19:25:05 +00001037 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001038 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001039 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001040 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001041 goto psx_create_err;
1042 }
Steve French50c2f752007-07-13 00:33:32 +00001043 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001044 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001045 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001046 }
Steve French2dd29d32007-04-23 22:07:35 +00001047
1048psx_create_err:
1049 cifs_buf_release(pSMB);
1050
Steve French65bc98b2009-07-10 15:27:25 +00001051 if (posix_flags & SMB_O_DIRECTORY)
1052 cifs_stats_inc(&tcon->num_posixmkdirs);
1053 else
1054 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001055
1056 if (rc == -EAGAIN)
1057 goto PsxCreat;
1058
Steve French50c2f752007-07-13 00:33:32 +00001059 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001060}
1061
Steve Frencha9d02ad2005-08-24 23:06:05 -07001062static __u16 convert_disposition(int disposition)
1063{
1064 __u16 ofun = 0;
1065
1066 switch (disposition) {
1067 case FILE_SUPERSEDE:
1068 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1069 break;
1070 case FILE_OPEN:
1071 ofun = SMBOPEN_OAPPEND;
1072 break;
1073 case FILE_CREATE:
1074 ofun = SMBOPEN_OCREATE;
1075 break;
1076 case FILE_OPEN_IF:
1077 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1078 break;
1079 case FILE_OVERWRITE:
1080 ofun = SMBOPEN_OTRUNC;
1081 break;
1082 case FILE_OVERWRITE_IF:
1083 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1084 break;
1085 default:
Steve French790fe572007-07-07 19:25:05 +00001086 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001087 ofun = SMBOPEN_OAPPEND; /* regular open */
1088 }
1089 return ofun;
1090}
1091
Jeff Layton35fc37d2008-05-14 10:22:03 -07001092static int
1093access_flags_to_smbopen_mode(const int access_flags)
1094{
1095 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1096
1097 if (masked_flags == GENERIC_READ)
1098 return SMBOPEN_READ;
1099 else if (masked_flags == GENERIC_WRITE)
1100 return SMBOPEN_WRITE;
1101
1102 /* just go for read/write */
1103 return SMBOPEN_READWRITE;
1104}
1105
Steve Frencha9d02ad2005-08-24 23:06:05 -07001106int
1107SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1108 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001109 const int access_flags, const int create_options, __u16 *netfid,
1110 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001111 const struct nls_table *nls_codepage, int remap)
1112{
1113 int rc = -EACCES;
1114 OPENX_REQ *pSMB = NULL;
1115 OPENX_RSP *pSMBr = NULL;
1116 int bytes_returned;
1117 int name_len;
1118 __u16 count;
1119
1120OldOpenRetry:
1121 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1122 (void **) &pSMBr);
1123 if (rc)
1124 return rc;
1125
1126 pSMB->AndXCommand = 0xFF; /* none */
1127
1128 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1129 count = 1; /* account for one byte pad to word boundary */
1130 name_len =
1131 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1132 fileName, PATH_MAX, nls_codepage, remap);
1133 name_len++; /* trailing null */
1134 name_len *= 2;
1135 } else { /* BB improve check for buffer overruns BB */
1136 count = 0; /* no pad */
1137 name_len = strnlen(fileName, PATH_MAX);
1138 name_len++; /* trailing null */
1139 strncpy(pSMB->fileName, fileName, name_len);
1140 }
1141 if (*pOplock & REQ_OPLOCK)
1142 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001143 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001144 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001145
Steve Frencha9d02ad2005-08-24 23:06:05 -07001146 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001147 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001148 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1149 /* set file as system file if special file such
1150 as fifo and server expecting SFU style and
1151 no Unix extensions */
1152
Steve French790fe572007-07-07 19:25:05 +00001153 if (create_options & CREATE_OPTION_SPECIAL)
1154 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001155 else /* BB FIXME BB */
1156 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001157
Jeff Layton67750fb2008-05-09 22:28:02 +00001158 if (create_options & CREATE_OPTION_READONLY)
1159 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001160
1161 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001162/* pSMB->CreateOptions = cpu_to_le32(create_options &
1163 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001165
1166 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001167 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001168 count += name_len;
1169 pSMB->hdr.smb_buf_length += count;
1170
1171 pSMB->ByteCount = cpu_to_le16(count);
1172 /* long_op set to 1 to allow for oplock break timeouts */
1173 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001174 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175 cifs_stats_inc(&tcon->num_opens);
1176 if (rc) {
1177 cFYI(1, ("Error in Open = %d", rc));
1178 } else {
1179 /* BB verify if wct == 15 */
1180
Steve French582d21e2008-05-13 04:54:12 +00001181/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001182
1183 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1184 /* Let caller know file was created so we can set the mode. */
1185 /* Do we care about the CreateAction in any other cases? */
1186 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001187/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001188 *pOplock |= CIFS_CREATE_ACTION; */
1189 /* BB FIXME END */
1190
Steve French790fe572007-07-07 19:25:05 +00001191 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001192 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1193 pfile_info->LastAccessTime = 0; /* BB fixme */
1194 pfile_info->LastWriteTime = 0; /* BB fixme */
1195 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001196 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001197 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001198 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001199 pfile_info->AllocationSize =
1200 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1201 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001202 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001203 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001204 }
1205 }
1206
1207 cifs_buf_release(pSMB);
1208 if (rc == -EAGAIN)
1209 goto OldOpenRetry;
1210 return rc;
1211}
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213int
1214CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1215 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001216 const int access_flags, const int create_options, __u16 *netfid,
1217 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001218 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219{
1220 int rc = -EACCES;
1221 OPEN_REQ *pSMB = NULL;
1222 OPEN_RSP *pSMBr = NULL;
1223 int bytes_returned;
1224 int name_len;
1225 __u16 count;
1226
1227openRetry:
1228 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1229 (void **) &pSMBr);
1230 if (rc)
1231 return rc;
1232
1233 pSMB->AndXCommand = 0xFF; /* none */
1234
1235 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1236 count = 1; /* account for one byte pad to word boundary */
1237 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001238 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001239 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 name_len++; /* trailing null */
1241 name_len *= 2;
1242 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001243 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 count = 0; /* no pad */
1245 name_len = strnlen(fileName, PATH_MAX);
1246 name_len++; /* trailing null */
1247 pSMB->NameLength = cpu_to_le16(name_len);
1248 strncpy(pSMB->fileName, fileName, name_len);
1249 }
1250 if (*pOplock & REQ_OPLOCK)
1251 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001252 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1255 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001256 /* set file as system file if special file such
1257 as fifo and server expecting SFU style and
1258 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001259 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001260 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1261 else
1262 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 /* XP does not handle ATTR_POSIX_SEMANTICS */
1265 /* but it helps speed up case sensitive checks for other
1266 servers such as Samba */
1267 if (tcon->ses->capabilities & CAP_UNIX)
1268 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1269
Jeff Layton67750fb2008-05-09 22:28:02 +00001270 if (create_options & CREATE_OPTION_READONLY)
1271 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1274 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001275 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001276 /* BB Expirement with various impersonation levels and verify */
1277 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 pSMB->SecurityFlags =
1279 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1280
1281 count += name_len;
1282 pSMB->hdr.smb_buf_length += count;
1283
1284 pSMB->ByteCount = cpu_to_le16(count);
1285 /* long_op set to 1 to allow for oplock break timeouts */
1286 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001287 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001288 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 if (rc) {
1290 cFYI(1, ("Error in Open = %d", rc));
1291 } else {
Steve French09d1db52005-04-28 22:41:08 -07001292 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1294 /* Let caller know file was created so we can set the mode. */
1295 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001296 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001297 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001298 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001299 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1300 36 /* CreationTime to Attributes */);
1301 /* the file_info buf is endian converted by caller */
1302 pfile_info->AllocationSize = pSMBr->AllocationSize;
1303 pfile_info->EndOfFile = pSMBr->EndOfFile;
1304 pfile_info->NumberOfLinks = cpu_to_le32(1);
1305 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001308
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 cifs_buf_release(pSMB);
1310 if (rc == -EAGAIN)
1311 goto openRetry;
1312 return rc;
1313}
1314
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315int
Steve French50c2f752007-07-13 00:33:32 +00001316CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1317 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1318 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
1320 int rc = -EACCES;
1321 READ_REQ *pSMB = NULL;
1322 READ_RSP *pSMBr = NULL;
1323 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001324 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001325 int resp_buf_type = 0;
1326 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Steve French790fe572007-07-07 19:25:05 +00001328 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1329 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001330 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001331 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001332 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001333 if ((lseek >> 32) > 0) {
1334 /* can not handle this big offset for old */
1335 return -EIO;
1336 }
1337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338
1339 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001340 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 if (rc)
1342 return rc;
1343
1344 /* tcon and ses pointer are checked in smb_init */
1345 if (tcon->ses->server == NULL)
1346 return -ECONNABORTED;
1347
Steve Frenchec637e32005-12-12 20:53:18 -08001348 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 pSMB->Fid = netfid;
1350 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001351 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001352 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001353
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 pSMB->Remaining = 0;
1355 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1356 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001357 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001358 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1359 else {
1360 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001361 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001362 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001363 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001364 }
Steve Frenchec637e32005-12-12 20:53:18 -08001365
1366 iov[0].iov_base = (char *)pSMB;
1367 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001368 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001369 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001370 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001371 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (rc) {
1373 cERROR(1, ("Send error in read = %d", rc));
1374 } else {
1375 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1376 data_length = data_length << 16;
1377 data_length += le16_to_cpu(pSMBr->DataLength);
1378 *nbytes = data_length;
1379
1380 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001381 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001383 cFYI(1, ("bad length %d for count %d",
1384 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 rc = -EIO;
1386 *nbytes = 0;
1387 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001388 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001389 le16_to_cpu(pSMBr->DataOffset);
1390/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001391 cERROR(1,("Faulting on read rc = %d",rc));
1392 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001393 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001394 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001395 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 }
1397 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Steve French4b8f9302006-02-26 16:41:18 +00001399/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001400 if (*buf) {
1401 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001402 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001403 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001404 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001405 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001406 /* return buffer to caller to free */
1407 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001408 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001409 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001410 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001411 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001412 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001413
1414 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 since file handle passed in no longer valid */
1416 return rc;
1417}
1418
Steve Frenchec637e32005-12-12 20:53:18 -08001419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420int
1421CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1422 const int netfid, const unsigned int count,
1423 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001424 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425{
1426 int rc = -EACCES;
1427 WRITE_REQ *pSMB = NULL;
1428 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001429 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 __u32 bytes_sent;
1431 __u16 byte_count;
1432
Steve Frencha24e2d72010-04-03 17:20:21 +00001433 *nbytes = 0;
1434
Steve French61de8002008-10-30 20:15:22 +00001435 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001436 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001437 return -ECONNABORTED;
1438
Steve French790fe572007-07-07 19:25:05 +00001439 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001440 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001441 else {
Steve French1c955182005-08-30 20:58:07 -07001442 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001443 if ((offset >> 32) > 0) {
1444 /* can not handle big offset for old srv */
1445 return -EIO;
1446 }
1447 }
Steve French1c955182005-08-30 20:58:07 -07001448
1449 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 (void **) &pSMBr);
1451 if (rc)
1452 return rc;
1453 /* tcon and ses pointer are checked in smb_init */
1454 if (tcon->ses->server == NULL)
1455 return -ECONNABORTED;
1456
1457 pSMB->AndXCommand = 0xFF; /* none */
1458 pSMB->Fid = netfid;
1459 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001460 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001461 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001462
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 pSMB->Reserved = 0xFFFFFFFF;
1464 pSMB->WriteMode = 0;
1465 pSMB->Remaining = 0;
1466
Steve French50c2f752007-07-13 00:33:32 +00001467 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 can send more if LARGE_WRITE_X capability returned by the server and if
1469 our buffer is big enough or if we convert to iovecs on socket writes
1470 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001471 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1473 } else {
1474 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1475 & ~0xFF;
1476 }
1477
1478 if (bytes_sent > count)
1479 bytes_sent = count;
1480 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001481 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001482 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001483 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001484 else if (ubuf) {
1485 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 cifs_buf_release(pSMB);
1487 return -EFAULT;
1488 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001489 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 /* No buffer */
1491 cifs_buf_release(pSMB);
1492 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001493 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001494 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001495 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001496 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001497 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001498
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1500 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001501 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001502
Steve French790fe572007-07-07 19:25:05 +00001503 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001504 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001505 else { /* old style write has byte count 4 bytes earlier
1506 so 4 bytes pad */
1507 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001508 (struct smb_com_writex_req *)pSMB;
1509 pSMBW->ByteCount = cpu_to_le16(byte_count);
1510 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511
1512 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1513 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001514 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 if (rc) {
1516 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 } else {
1518 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1519 *nbytes = (*nbytes) << 16;
1520 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301521
1522 /*
1523 * Mask off high 16 bits when bytes written as returned by the
1524 * server is greater than bytes requested by the client. Some
1525 * OS/2 servers are known to set incorrect CountHigh values.
1526 */
1527 if (*nbytes > count)
1528 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 }
1530
1531 cifs_buf_release(pSMB);
1532
Steve French50c2f752007-07-13 00:33:32 +00001533 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 since file handle passed in no longer valid */
1535
1536 return rc;
1537}
1538
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001539int
1540CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001542 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1543 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544{
1545 int rc = -EACCES;
1546 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001547 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001548 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001549 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001551 *nbytes = 0;
1552
Steve French790fe572007-07-07 19:25:05 +00001553 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001554
Steve French4c3130e2008-12-09 00:28:16 +00001555 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001556 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001557 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001558 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001559 if ((offset >> 32) > 0) {
1560 /* can not handle big offset for old srv */
1561 return -EIO;
1562 }
1563 }
Steve French8cc64c62005-10-03 13:49:43 -07001564 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 if (rc)
1566 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 /* tcon and ses pointer are checked in smb_init */
1568 if (tcon->ses->server == NULL)
1569 return -ECONNABORTED;
1570
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001571 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 pSMB->Fid = netfid;
1573 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001574 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001575 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 pSMB->Reserved = 0xFFFFFFFF;
1577 pSMB->WriteMode = 0;
1578 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001579
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001581 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
Steve French3e844692005-10-03 13:37:24 -07001583 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1584 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001585 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001586 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001587 pSMB->hdr.smb_buf_length += count+1;
1588 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001589 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1590 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001591 pSMB->ByteCount = cpu_to_le16(count + 1);
1592 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001593 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001594 (struct smb_com_writex_req *)pSMB;
1595 pSMBW->ByteCount = cpu_to_le16(count + 5);
1596 }
Steve French3e844692005-10-03 13:37:24 -07001597 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001598 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001599 iov[0].iov_len = smb_hdr_len + 4;
1600 else /* wct == 12 pad bigger by four bytes */
1601 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001602
Steve French3e844692005-10-03 13:37:24 -07001603
Steve Frenchec637e32005-12-12 20:53:18 -08001604 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001605 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001606 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001608 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001609 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001610 /* presumably this can not happen, but best to be safe */
1611 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001612 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001613 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001614 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1615 *nbytes = (*nbytes) << 16;
1616 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301617
1618 /*
1619 * Mask off high 16 bits when bytes written as returned by the
1620 * server is greater than bytes requested by the client. OS/2
1621 * servers are known to set incorrect CountHigh values.
1622 */
1623 if (*nbytes > count)
1624 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626
Steve French4b8f9302006-02-26 16:41:18 +00001627/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001628 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001629 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001630 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001631 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632
Steve French50c2f752007-07-13 00:33:32 +00001633 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 since file handle passed in no longer valid */
1635
1636 return rc;
1637}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001638
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640int
1641CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1642 const __u16 smb_file_id, const __u64 len,
1643 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001644 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645{
1646 int rc = 0;
1647 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001648/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 int bytes_returned;
1650 int timeout = 0;
1651 __u16 count;
1652
Steve French4b18f2a2008-04-29 00:06:05 +00001653 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001654 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1655
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 if (rc)
1657 return rc;
1658
Steve French790fe572007-07-07 19:25:05 +00001659 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001660 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001662 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001663 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1665 } else {
1666 pSMB->Timeout = 0;
1667 }
1668
1669 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1670 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1671 pSMB->LockType = lockType;
1672 pSMB->AndXCommand = 0xFF; /* none */
1673 pSMB->Fid = smb_file_id; /* netfid stays le */
1674
Steve French790fe572007-07-07 19:25:05 +00001675 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1677 /* BB where to store pid high? */
1678 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1679 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1680 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1681 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1682 count = sizeof(LOCKING_ANDX_RANGE);
1683 } else {
1684 /* oplock break */
1685 count = 0;
1686 }
1687 pSMB->hdr.smb_buf_length += count;
1688 pSMB->ByteCount = cpu_to_le16(count);
1689
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001690 if (waitFlag) {
1691 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001692 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001693 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001694 } else {
Steve French133672e2007-11-13 22:41:37 +00001695 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1696 timeout);
1697 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001698 }
Steve Frencha4544342005-08-24 13:59:35 -07001699 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001700 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702
Steve French50c2f752007-07-13 00:33:32 +00001703 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 since file handle passed in no longer valid */
1705 return rc;
1706}
1707
1708int
Steve French08547b02006-02-28 22:39:25 +00001709CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1710 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001711 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001712 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001713{
1714 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1715 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001716 struct cifs_posix_lock *parm_data;
1717 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001718 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001719 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001720 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001721 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001722 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001723
1724 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001725
Steve French790fe572007-07-07 19:25:05 +00001726 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001727 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001728
Steve French08547b02006-02-28 22:39:25 +00001729 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1730
1731 if (rc)
1732 return rc;
1733
1734 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1735
Steve French50c2f752007-07-13 00:33:32 +00001736 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001737 pSMB->MaxSetupCount = 0;
1738 pSMB->Reserved = 0;
1739 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001740 pSMB->Reserved2 = 0;
1741 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1742 offset = param_offset + params;
1743
Steve French08547b02006-02-28 22:39:25 +00001744 count = sizeof(struct cifs_posix_lock);
1745 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001746 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001747 pSMB->SetupCount = 1;
1748 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001749 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001750 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1751 else
1752 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1753 byte_count = 3 /* pad */ + params + count;
1754 pSMB->DataCount = cpu_to_le16(count);
1755 pSMB->ParameterCount = cpu_to_le16(params);
1756 pSMB->TotalDataCount = pSMB->DataCount;
1757 pSMB->TotalParameterCount = pSMB->ParameterCount;
1758 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001759 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001760 (((char *) &pSMB->hdr.Protocol) + offset);
1761
1762 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001763 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001764 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001765 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001766 pSMB->Timeout = cpu_to_le32(-1);
1767 } else
1768 pSMB->Timeout = 0;
1769
Steve French08547b02006-02-28 22:39:25 +00001770 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001771 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001772 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001773
1774 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001775 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001776 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1777 pSMB->Reserved4 = 0;
1778 pSMB->hdr.smb_buf_length += byte_count;
1779 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001780 if (waitFlag) {
1781 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1782 (struct smb_hdr *) pSMBr, &bytes_returned);
1783 } else {
Steve French133672e2007-11-13 22:41:37 +00001784 iov[0].iov_base = (char *)pSMB;
1785 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1786 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1787 &resp_buf_type, timeout);
1788 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1789 not try to free it twice below on exit */
1790 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001791 }
1792
Steve French08547b02006-02-28 22:39:25 +00001793 if (rc) {
1794 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001795 } else if (get_flag) {
1796 /* lock structure can be returned on get */
1797 __u16 data_offset;
1798 __u16 data_count;
1799 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001800
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001801 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1802 rc = -EIO; /* bad smb */
1803 goto plk_err_exit;
1804 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001805 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1806 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001807 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001808 rc = -EIO;
1809 goto plk_err_exit;
1810 }
1811 parm_data = (struct cifs_posix_lock *)
1812 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001813 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001814 pLockData->fl_type = F_UNLCK;
1815 }
Steve French50c2f752007-07-13 00:33:32 +00001816
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001817plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001818 if (pSMB)
1819 cifs_small_buf_release(pSMB);
1820
Steve French133672e2007-11-13 22:41:37 +00001821 if (resp_buf_type == CIFS_SMALL_BUFFER)
1822 cifs_small_buf_release(iov[0].iov_base);
1823 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1824 cifs_buf_release(iov[0].iov_base);
1825
Steve French08547b02006-02-28 22:39:25 +00001826 /* Note: On -EAGAIN error only caller can retry on handle based calls
1827 since file handle passed in no longer valid */
1828
1829 return rc;
1830}
1831
1832
1833int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1835{
1836 int rc = 0;
1837 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 cFYI(1, ("In CIFSSMBClose"));
1839
1840/* do not retry on dead session on close */
1841 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001842 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 return 0;
1844 if (rc)
1845 return rc;
1846
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001848 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001850 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001851 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001853 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 /* EINTR is expected when user ctl-c to kill app */
1855 cERROR(1, ("Send error in Close = %d", rc));
1856 }
1857 }
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001860 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 rc = 0;
1862
1863 return rc;
1864}
1865
1866int
Steve Frenchb298f222009-02-21 21:17:43 +00001867CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1868{
1869 int rc = 0;
1870 FLUSH_REQ *pSMB = NULL;
1871 cFYI(1, ("In CIFSSMBFlush"));
1872
1873 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1874 if (rc)
1875 return rc;
1876
1877 pSMB->FileID = (__u16) smb_file_id;
1878 pSMB->ByteCount = 0;
1879 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1880 cifs_stats_inc(&tcon->num_flushes);
1881 if (rc)
1882 cERROR(1, ("Send error in Flush = %d", rc));
1883
1884 return rc;
1885}
1886
1887int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1889 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001890 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891{
1892 int rc = 0;
1893 RENAME_REQ *pSMB = NULL;
1894 RENAME_RSP *pSMBr = NULL;
1895 int bytes_returned;
1896 int name_len, name_len2;
1897 __u16 count;
1898
1899 cFYI(1, ("In CIFSSMBRename"));
1900renameRetry:
1901 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1902 (void **) &pSMBr);
1903 if (rc)
1904 return rc;
1905
1906 pSMB->BufferFormat = 0x04;
1907 pSMB->SearchAttributes =
1908 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1909 ATTR_DIRECTORY);
1910
1911 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1912 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001913 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001914 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 name_len++; /* trailing null */
1916 name_len *= 2;
1917 pSMB->OldFileName[name_len] = 0x04; /* pad */
1918 /* protocol requires ASCII signature byte on Unicode string */
1919 pSMB->OldFileName[name_len + 1] = 0x00;
1920 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001921 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001922 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1924 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001925 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 name_len = strnlen(fromName, PATH_MAX);
1927 name_len++; /* trailing null */
1928 strncpy(pSMB->OldFileName, fromName, name_len);
1929 name_len2 = strnlen(toName, PATH_MAX);
1930 name_len2++; /* trailing null */
1931 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1932 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1933 name_len2++; /* trailing null */
1934 name_len2++; /* signature byte */
1935 }
1936
1937 count = 1 /* 1st signature byte */ + name_len + name_len2;
1938 pSMB->hdr.smb_buf_length += count;
1939 pSMB->ByteCount = cpu_to_le16(count);
1940
1941 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1942 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001943 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001944 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 cifs_buf_release(pSMB);
1948
1949 if (rc == -EAGAIN)
1950 goto renameRetry;
1951
1952 return rc;
1953}
1954
Steve French50c2f752007-07-13 00:33:32 +00001955int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001956 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001957 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958{
1959 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1960 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001961 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 char *data_offset;
1963 char dummy_string[30];
1964 int rc = 0;
1965 int bytes_returned = 0;
1966 int len_of_str;
1967 __u16 params, param_offset, offset, count, byte_count;
1968
1969 cFYI(1, ("Rename to File by handle"));
1970 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1971 (void **) &pSMBr);
1972 if (rc)
1973 return rc;
1974
1975 params = 6;
1976 pSMB->MaxSetupCount = 0;
1977 pSMB->Reserved = 0;
1978 pSMB->Flags = 0;
1979 pSMB->Timeout = 0;
1980 pSMB->Reserved2 = 0;
1981 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1982 offset = param_offset + params;
1983
1984 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1985 rename_info = (struct set_file_rename *) data_offset;
1986 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001987 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 pSMB->SetupCount = 1;
1989 pSMB->Reserved3 = 0;
1990 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1991 byte_count = 3 /* pad */ + params;
1992 pSMB->ParameterCount = cpu_to_le16(params);
1993 pSMB->TotalParameterCount = pSMB->ParameterCount;
1994 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1995 pSMB->DataOffset = cpu_to_le16(offset);
1996 /* construct random name ".cifs_tmp<inodenum><mid>" */
1997 rename_info->overwrite = cpu_to_le32(1);
1998 rename_info->root_fid = 0;
1999 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002000 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002001 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2002 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002003 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002005 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002006 target_name, PATH_MAX, nls_codepage,
2007 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 }
2009 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002010 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 byte_count += count;
2012 pSMB->DataCount = cpu_to_le16(count);
2013 pSMB->TotalDataCount = pSMB->DataCount;
2014 pSMB->Fid = netfid;
2015 pSMB->InformationLevel =
2016 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2017 pSMB->Reserved4 = 0;
2018 pSMB->hdr.smb_buf_length += byte_count;
2019 pSMB->ByteCount = cpu_to_le16(byte_count);
2020 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002021 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002022 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002023 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002024 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002025
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 cifs_buf_release(pSMB);
2027
2028 /* Note: On -EAGAIN error only caller can retry on handle based calls
2029 since file handle passed in no longer valid */
2030
2031 return rc;
2032}
2033
2034int
Steve French50c2f752007-07-13 00:33:32 +00002035CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2036 const __u16 target_tid, const char *toName, const int flags,
2037 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038{
2039 int rc = 0;
2040 COPY_REQ *pSMB = NULL;
2041 COPY_RSP *pSMBr = NULL;
2042 int bytes_returned;
2043 int name_len, name_len2;
2044 __u16 count;
2045
2046 cFYI(1, ("In CIFSSMBCopy"));
2047copyRetry:
2048 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2049 (void **) &pSMBr);
2050 if (rc)
2051 return rc;
2052
2053 pSMB->BufferFormat = 0x04;
2054 pSMB->Tid2 = target_tid;
2055
2056 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2057
2058 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002059 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002060 fromName, PATH_MAX, nls_codepage,
2061 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 name_len++; /* trailing null */
2063 name_len *= 2;
2064 pSMB->OldFileName[name_len] = 0x04; /* pad */
2065 /* protocol requires ASCII signature byte on Unicode string */
2066 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002067 name_len2 =
2068 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002069 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2071 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002072 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 name_len = strnlen(fromName, PATH_MAX);
2074 name_len++; /* trailing null */
2075 strncpy(pSMB->OldFileName, fromName, name_len);
2076 name_len2 = strnlen(toName, PATH_MAX);
2077 name_len2++; /* trailing null */
2078 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2079 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2080 name_len2++; /* trailing null */
2081 name_len2++; /* signature byte */
2082 }
2083
2084 count = 1 /* 1st signature byte */ + name_len + name_len2;
2085 pSMB->hdr.smb_buf_length += count;
2086 pSMB->ByteCount = cpu_to_le16(count);
2087
2088 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2090 if (rc) {
2091 cFYI(1, ("Send error in copy = %d with %d files copied",
2092 rc, le16_to_cpu(pSMBr->CopyCount)));
2093 }
Steve French0d817bc2008-05-22 02:02:03 +00002094 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096 if (rc == -EAGAIN)
2097 goto copyRetry;
2098
2099 return rc;
2100}
2101
2102int
2103CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2104 const char *fromName, const char *toName,
2105 const struct nls_table *nls_codepage)
2106{
2107 TRANSACTION2_SPI_REQ *pSMB = NULL;
2108 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2109 char *data_offset;
2110 int name_len;
2111 int name_len_target;
2112 int rc = 0;
2113 int bytes_returned = 0;
2114 __u16 params, param_offset, offset, byte_count;
2115
2116 cFYI(1, ("In Symlink Unix style"));
2117createSymLinkRetry:
2118 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2119 (void **) &pSMBr);
2120 if (rc)
2121 return rc;
2122
2123 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2124 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002125 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 /* find define for this maxpathcomponent */
2127 , nls_codepage);
2128 name_len++; /* trailing null */
2129 name_len *= 2;
2130
Steve French50c2f752007-07-13 00:33:32 +00002131 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 name_len = strnlen(fromName, PATH_MAX);
2133 name_len++; /* trailing null */
2134 strncpy(pSMB->FileName, fromName, name_len);
2135 }
2136 params = 6 + name_len;
2137 pSMB->MaxSetupCount = 0;
2138 pSMB->Reserved = 0;
2139 pSMB->Flags = 0;
2140 pSMB->Timeout = 0;
2141 pSMB->Reserved2 = 0;
2142 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002143 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 offset = param_offset + params;
2145
2146 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2147 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2148 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002149 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 /* find define for this maxpathcomponent */
2151 , nls_codepage);
2152 name_len_target++; /* trailing null */
2153 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002154 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 name_len_target = strnlen(toName, PATH_MAX);
2156 name_len_target++; /* trailing null */
2157 strncpy(data_offset, toName, name_len_target);
2158 }
2159
2160 pSMB->MaxParameterCount = cpu_to_le16(2);
2161 /* BB find exact max on data count below from sess */
2162 pSMB->MaxDataCount = cpu_to_le16(1000);
2163 pSMB->SetupCount = 1;
2164 pSMB->Reserved3 = 0;
2165 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2166 byte_count = 3 /* pad */ + params + name_len_target;
2167 pSMB->DataCount = cpu_to_le16(name_len_target);
2168 pSMB->ParameterCount = cpu_to_le16(params);
2169 pSMB->TotalDataCount = pSMB->DataCount;
2170 pSMB->TotalParameterCount = pSMB->ParameterCount;
2171 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2172 pSMB->DataOffset = cpu_to_le16(offset);
2173 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2174 pSMB->Reserved4 = 0;
2175 pSMB->hdr.smb_buf_length += byte_count;
2176 pSMB->ByteCount = cpu_to_le16(byte_count);
2177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002179 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002180 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002181 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
Steve French0d817bc2008-05-22 02:02:03 +00002183 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184
2185 if (rc == -EAGAIN)
2186 goto createSymLinkRetry;
2187
2188 return rc;
2189}
2190
2191int
2192CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2193 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002194 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195{
2196 TRANSACTION2_SPI_REQ *pSMB = NULL;
2197 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2198 char *data_offset;
2199 int name_len;
2200 int name_len_target;
2201 int rc = 0;
2202 int bytes_returned = 0;
2203 __u16 params, param_offset, offset, byte_count;
2204
2205 cFYI(1, ("In Create Hard link Unix style"));
2206createHardLinkRetry:
2207 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2208 (void **) &pSMBr);
2209 if (rc)
2210 return rc;
2211
2212 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002213 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002214 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 name_len++; /* trailing null */
2216 name_len *= 2;
2217
Steve French50c2f752007-07-13 00:33:32 +00002218 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 name_len = strnlen(toName, PATH_MAX);
2220 name_len++; /* trailing null */
2221 strncpy(pSMB->FileName, toName, name_len);
2222 }
2223 params = 6 + name_len;
2224 pSMB->MaxSetupCount = 0;
2225 pSMB->Reserved = 0;
2226 pSMB->Flags = 0;
2227 pSMB->Timeout = 0;
2228 pSMB->Reserved2 = 0;
2229 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002230 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 offset = param_offset + params;
2232
2233 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2235 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002236 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002237 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 name_len_target++; /* trailing null */
2239 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002240 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 name_len_target = strnlen(fromName, PATH_MAX);
2242 name_len_target++; /* trailing null */
2243 strncpy(data_offset, fromName, name_len_target);
2244 }
2245
2246 pSMB->MaxParameterCount = cpu_to_le16(2);
2247 /* BB find exact max on data count below from sess*/
2248 pSMB->MaxDataCount = cpu_to_le16(1000);
2249 pSMB->SetupCount = 1;
2250 pSMB->Reserved3 = 0;
2251 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2252 byte_count = 3 /* pad */ + params + name_len_target;
2253 pSMB->ParameterCount = cpu_to_le16(params);
2254 pSMB->TotalParameterCount = pSMB->ParameterCount;
2255 pSMB->DataCount = cpu_to_le16(name_len_target);
2256 pSMB->TotalDataCount = pSMB->DataCount;
2257 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2258 pSMB->DataOffset = cpu_to_le16(offset);
2259 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2260 pSMB->Reserved4 = 0;
2261 pSMB->hdr.smb_buf_length += byte_count;
2262 pSMB->ByteCount = cpu_to_le16(byte_count);
2263 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2264 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002265 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002266 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268
2269 cifs_buf_release(pSMB);
2270 if (rc == -EAGAIN)
2271 goto createHardLinkRetry;
2272
2273 return rc;
2274}
2275
2276int
2277CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2278 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002279 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280{
2281 int rc = 0;
2282 NT_RENAME_REQ *pSMB = NULL;
2283 RENAME_RSP *pSMBr = NULL;
2284 int bytes_returned;
2285 int name_len, name_len2;
2286 __u16 count;
2287
2288 cFYI(1, ("In CIFSCreateHardLink"));
2289winCreateHardLinkRetry:
2290
2291 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2292 (void **) &pSMBr);
2293 if (rc)
2294 return rc;
2295
2296 pSMB->SearchAttributes =
2297 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2298 ATTR_DIRECTORY);
2299 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2300 pSMB->ClusterCount = 0;
2301
2302 pSMB->BufferFormat = 0x04;
2303
2304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2305 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002306 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002307 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 name_len++; /* trailing null */
2309 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002310
2311 /* protocol specifies ASCII buffer format (0x04) for unicode */
2312 pSMB->OldFileName[name_len] = 0x04;
2313 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002315 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002316 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2318 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002319 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 name_len = strnlen(fromName, PATH_MAX);
2321 name_len++; /* trailing null */
2322 strncpy(pSMB->OldFileName, fromName, name_len);
2323 name_len2 = strnlen(toName, PATH_MAX);
2324 name_len2++; /* trailing null */
2325 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2326 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2327 name_len2++; /* trailing null */
2328 name_len2++; /* signature byte */
2329 }
2330
2331 count = 1 /* string type byte */ + name_len + name_len2;
2332 pSMB->hdr.smb_buf_length += count;
2333 pSMB->ByteCount = cpu_to_le16(count);
2334
2335 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2336 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002337 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002338 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002340
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 cifs_buf_release(pSMB);
2342 if (rc == -EAGAIN)
2343 goto winCreateHardLinkRetry;
2344
2345 return rc;
2346}
2347
2348int
2349CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002350 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 const struct nls_table *nls_codepage)
2352{
2353/* SMB_QUERY_FILE_UNIX_LINK */
2354 TRANSACTION2_QPI_REQ *pSMB = NULL;
2355 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2356 int rc = 0;
2357 int bytes_returned;
2358 int name_len;
2359 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002360 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
2362 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2363
2364querySymLinkRetry:
2365 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2366 (void **) &pSMBr);
2367 if (rc)
2368 return rc;
2369
2370 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2371 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002372 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2373 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 name_len++; /* trailing null */
2375 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002376 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 name_len = strnlen(searchName, PATH_MAX);
2378 name_len++; /* trailing null */
2379 strncpy(pSMB->FileName, searchName, name_len);
2380 }
2381
2382 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2383 pSMB->TotalDataCount = 0;
2384 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002385 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 pSMB->MaxSetupCount = 0;
2387 pSMB->Reserved = 0;
2388 pSMB->Flags = 0;
2389 pSMB->Timeout = 0;
2390 pSMB->Reserved2 = 0;
2391 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002392 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 pSMB->DataCount = 0;
2394 pSMB->DataOffset = 0;
2395 pSMB->SetupCount = 1;
2396 pSMB->Reserved3 = 0;
2397 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2398 byte_count = params + 1 /* pad */ ;
2399 pSMB->TotalParameterCount = cpu_to_le16(params);
2400 pSMB->ParameterCount = pSMB->TotalParameterCount;
2401 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2402 pSMB->Reserved4 = 0;
2403 pSMB->hdr.smb_buf_length += byte_count;
2404 pSMB->ByteCount = cpu_to_le16(byte_count);
2405
2406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2408 if (rc) {
2409 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2410 } else {
2411 /* decode response */
2412
2413 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002415 if (rc || (pSMBr->ByteCount < 2))
2416 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002418 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002419 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420
Jeff Layton460b9692009-04-30 07:17:56 -04002421 data_start = ((char *) &pSMBr->hdr.Protocol) +
2422 le16_to_cpu(pSMBr->t2.DataOffset);
2423
Steve French0e0d2cf2009-05-01 05:27:32 +00002424 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2425 is_unicode = true;
2426 else
2427 is_unicode = false;
2428
Steve French737b7582005-04-28 22:41:06 -07002429 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002430 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002431 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002432 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002433 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
2435 }
2436 cifs_buf_release(pSMB);
2437 if (rc == -EAGAIN)
2438 goto querySymLinkRetry;
2439 return rc;
2440}
2441
Parag Warudkarc9489772007-10-23 18:09:48 +00002442#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002443/* Initialize NT TRANSACT SMB into small smb request buffer.
2444 This assumes that all NT TRANSACTS that we init here have
2445 total parm and data under about 400 bytes (to fit in small cifs
2446 buffer size), which is the case so far, it easily fits. NB:
2447 Setup words themselves and ByteCount
2448 MaxSetupCount (size of returned setup area) and
2449 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002450static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002451smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002452 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002453 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002454{
2455 int rc;
2456 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002457 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002458
2459 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2460 (void **)&pSMB);
2461 if (rc)
2462 return rc;
2463 *ret_buf = (void *)pSMB;
2464 pSMB->Reserved = 0;
2465 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2466 pSMB->TotalDataCount = 0;
2467 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2468 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2469 pSMB->ParameterCount = pSMB->TotalParameterCount;
2470 pSMB->DataCount = pSMB->TotalDataCount;
2471 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2472 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2473 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2474 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2475 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2476 pSMB->SubCommand = cpu_to_le16(sub_command);
2477 return 0;
2478}
2479
2480static int
Steve French50c2f752007-07-13 00:33:32 +00002481validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002482 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002483{
Steve French50c2f752007-07-13 00:33:32 +00002484 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002485 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002486 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002487
Steve French630f3f02007-10-25 21:17:17 +00002488 *pdatalen = 0;
2489 *pparmlen = 0;
2490
Steve French790fe572007-07-07 19:25:05 +00002491 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002492 return -EINVAL;
2493
2494 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2495
2496 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002497 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002498 (char *)&pSMBr->ByteCount;
2499
Steve French0a4b92c2006-01-12 15:44:21 -08002500 data_offset = le32_to_cpu(pSMBr->DataOffset);
2501 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002502 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002503 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2504
2505 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2506 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2507
2508 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002509 if (*ppparm > end_of_smb) {
2510 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002511 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002512 } else if (parm_count + *ppparm > end_of_smb) {
2513 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002514 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002515 } else if (*ppdata > end_of_smb) {
2516 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002517 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002518 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002519 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002520 *ppdata, data_count, (data_count + *ppdata),
2521 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002522 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002523 } else if (parm_count + data_count > pSMBr->ByteCount) {
2524 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002525 return -EINVAL;
2526 }
Steve French630f3f02007-10-25 21:17:17 +00002527 *pdatalen = data_count;
2528 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002529 return 0;
2530}
2531
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532int
2533CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2534 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002535 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 const struct nls_table *nls_codepage)
2537{
2538 int rc = 0;
2539 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002540 struct smb_com_transaction_ioctl_req *pSMB;
2541 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
2543 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2544 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2545 (void **) &pSMBr);
2546 if (rc)
2547 return rc;
2548
2549 pSMB->TotalParameterCount = 0 ;
2550 pSMB->TotalDataCount = 0;
2551 pSMB->MaxParameterCount = cpu_to_le32(2);
2552 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002553 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2554 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 pSMB->MaxSetupCount = 4;
2556 pSMB->Reserved = 0;
2557 pSMB->ParameterOffset = 0;
2558 pSMB->DataCount = 0;
2559 pSMB->DataOffset = 0;
2560 pSMB->SetupCount = 4;
2561 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2562 pSMB->ParameterCount = pSMB->TotalParameterCount;
2563 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2564 pSMB->IsFsctl = 1; /* FSCTL */
2565 pSMB->IsRootFlag = 0;
2566 pSMB->Fid = fid; /* file handle always le */
2567 pSMB->ByteCount = 0;
2568
2569 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2570 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2571 if (rc) {
2572 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2573 } else { /* decode response */
2574 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2575 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002576 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 /* BB also check enough total bytes returned */
2578 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002579 goto qreparse_out;
2580 }
2581 if (data_count && (data_count < 2048)) {
2582 char *end_of_smb = 2 /* sizeof byte count */ +
2583 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
Steve Frenchafe48c32009-05-02 05:25:46 +00002585 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002586 (struct reparse_data *)
2587 ((char *)&pSMBr->hdr.Protocol
2588 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002589 if ((char *)reparse_buf >= end_of_smb) {
2590 rc = -EIO;
2591 goto qreparse_out;
2592 }
2593 if ((reparse_buf->LinkNamesBuf +
2594 reparse_buf->TargetNameOffset +
2595 reparse_buf->TargetNameLen) > end_of_smb) {
2596 cFYI(1, ("reparse buf beyond SMB"));
2597 rc = -EIO;
2598 goto qreparse_out;
2599 }
Steve French50c2f752007-07-13 00:33:32 +00002600
Steve Frenchafe48c32009-05-02 05:25:46 +00002601 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2602 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002603 (reparse_buf->LinkNamesBuf +
2604 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002605 buflen,
2606 reparse_buf->TargetNameLen,
2607 nls_codepage, 0);
2608 } else { /* ASCII names */
2609 strncpy(symlinkinfo,
2610 reparse_buf->LinkNamesBuf +
2611 reparse_buf->TargetNameOffset,
2612 min_t(const int, buflen,
2613 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002615 } else {
2616 rc = -EIO;
2617 cFYI(1, ("Invalid return data count on "
2618 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002620 symlinkinfo[buflen] = 0; /* just in case so the caller
2621 does not go off the end of the buffer */
2622 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 }
Steve French989c7e52009-05-02 05:32:20 +00002624
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002626 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628 /* Note: On -EAGAIN error only caller can retry on handle based calls
2629 since file handle passed in no longer valid */
2630
2631 return rc;
2632}
Steve Frenchafe48c32009-05-02 05:25:46 +00002633#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634
2635#ifdef CONFIG_CIFS_POSIX
2636
2637/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002638static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2639 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640{
2641 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002642 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2643 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2644 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2646
2647 return;
2648}
2649
2650/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002651static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2652 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653{
2654 int size = 0;
2655 int i;
2656 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002657 struct cifs_posix_ace *pACE;
2658 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2659 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
2661 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2662 return -EOPNOTSUPP;
2663
Steve French790fe572007-07-07 19:25:05 +00002664 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 count = le16_to_cpu(cifs_acl->access_entry_count);
2666 pACE = &cifs_acl->ace_array[0];
2667 size = sizeof(struct cifs_posix_acl);
2668 size += sizeof(struct cifs_posix_ace) * count;
2669 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002670 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002671 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2672 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 return -EINVAL;
2674 }
Steve French790fe572007-07-07 19:25:05 +00002675 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 count = le16_to_cpu(cifs_acl->access_entry_count);
2677 size = sizeof(struct cifs_posix_acl);
2678 size += sizeof(struct cifs_posix_ace) * count;
2679/* skip past access ACEs to get to default ACEs */
2680 pACE = &cifs_acl->ace_array[count];
2681 count = le16_to_cpu(cifs_acl->default_entry_count);
2682 size += sizeof(struct cifs_posix_ace) * count;
2683 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002684 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 return -EINVAL;
2686 } else {
2687 /* illegal type */
2688 return -EINVAL;
2689 }
2690
2691 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002692 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002693 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002694 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 return -ERANGE;
2696 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002697 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002698 for (i = 0; i < count ; i++) {
2699 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2700 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 }
2702 }
2703 return size;
2704}
2705
Steve French50c2f752007-07-13 00:33:32 +00002706static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2707 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708{
2709 __u16 rc = 0; /* 0 = ACL converted ok */
2710
Steve Frenchff7feac2005-11-15 16:45:16 -08002711 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2712 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002714 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 /* Probably no need to le convert -1 on any arch but can not hurt */
2716 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002717 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002718 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002719 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 return rc;
2721}
2722
2723/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002724static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2725 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726{
2727 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002728 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2729 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 int count;
2731 int i;
2732
Steve French790fe572007-07-07 19:25:05 +00002733 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 return 0;
2735
2736 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002737 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002738 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002739 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002740 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002741 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002742 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 return 0;
2744 }
2745 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002746 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002747 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002748 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002749 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 else {
Steve French50c2f752007-07-13 00:33:32 +00002751 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 return 0;
2753 }
Steve French50c2f752007-07-13 00:33:32 +00002754 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2756 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002757 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 /* ACE not converted */
2759 break;
2760 }
2761 }
Steve French790fe572007-07-07 19:25:05 +00002762 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2764 rc += sizeof(struct cifs_posix_acl);
2765 /* BB add check to make sure ACL does not overflow SMB */
2766 }
2767 return rc;
2768}
2769
2770int
2771CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002772 const unsigned char *searchName,
2773 char *acl_inf, const int buflen, const int acl_type,
2774 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775{
2776/* SMB_QUERY_POSIX_ACL */
2777 TRANSACTION2_QPI_REQ *pSMB = NULL;
2778 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2779 int rc = 0;
2780 int bytes_returned;
2781 int name_len;
2782 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002783
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2785
2786queryAclRetry:
2787 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2788 (void **) &pSMBr);
2789 if (rc)
2790 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002791
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2793 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002794 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002795 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 name_len++; /* trailing null */
2797 name_len *= 2;
2798 pSMB->FileName[name_len] = 0;
2799 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002800 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 name_len = strnlen(searchName, PATH_MAX);
2802 name_len++; /* trailing null */
2803 strncpy(pSMB->FileName, searchName, name_len);
2804 }
2805
2806 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2807 pSMB->TotalDataCount = 0;
2808 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002809 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 pSMB->MaxDataCount = cpu_to_le16(4000);
2811 pSMB->MaxSetupCount = 0;
2812 pSMB->Reserved = 0;
2813 pSMB->Flags = 0;
2814 pSMB->Timeout = 0;
2815 pSMB->Reserved2 = 0;
2816 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002817 offsetof(struct smb_com_transaction2_qpi_req,
2818 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 pSMB->DataCount = 0;
2820 pSMB->DataOffset = 0;
2821 pSMB->SetupCount = 1;
2822 pSMB->Reserved3 = 0;
2823 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2824 byte_count = params + 1 /* pad */ ;
2825 pSMB->TotalParameterCount = cpu_to_le16(params);
2826 pSMB->ParameterCount = pSMB->TotalParameterCount;
2827 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2828 pSMB->Reserved4 = 0;
2829 pSMB->hdr.smb_buf_length += byte_count;
2830 pSMB->ByteCount = cpu_to_le16(byte_count);
2831
2832 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2833 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002834 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 if (rc) {
2836 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2837 } else {
2838 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002839
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2841 if (rc || (pSMBr->ByteCount < 2))
2842 /* BB also check enough total bytes returned */
2843 rc = -EIO; /* bad smb */
2844 else {
2845 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2846 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2847 rc = cifs_copy_posix_acl(acl_inf,
2848 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002849 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 }
2851 }
2852 cifs_buf_release(pSMB);
2853 if (rc == -EAGAIN)
2854 goto queryAclRetry;
2855 return rc;
2856}
2857
2858int
2859CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002860 const unsigned char *fileName,
2861 const char *local_acl, const int buflen,
2862 const int acl_type,
2863 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864{
2865 struct smb_com_transaction2_spi_req *pSMB = NULL;
2866 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2867 char *parm_data;
2868 int name_len;
2869 int rc = 0;
2870 int bytes_returned = 0;
2871 __u16 params, byte_count, data_count, param_offset, offset;
2872
2873 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2874setAclRetry:
2875 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002876 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 if (rc)
2878 return rc;
2879 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2880 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002881 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002882 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 name_len++; /* trailing null */
2884 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002885 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 name_len = strnlen(fileName, PATH_MAX);
2887 name_len++; /* trailing null */
2888 strncpy(pSMB->FileName, fileName, name_len);
2889 }
2890 params = 6 + name_len;
2891 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002892 /* BB find max SMB size from sess */
2893 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 pSMB->MaxSetupCount = 0;
2895 pSMB->Reserved = 0;
2896 pSMB->Flags = 0;
2897 pSMB->Timeout = 0;
2898 pSMB->Reserved2 = 0;
2899 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002900 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 offset = param_offset + params;
2902 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2903 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2904
2905 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002906 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907
Steve French790fe572007-07-07 19:25:05 +00002908 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909 rc = -EOPNOTSUPP;
2910 goto setACLerrorExit;
2911 }
2912 pSMB->DataOffset = cpu_to_le16(offset);
2913 pSMB->SetupCount = 1;
2914 pSMB->Reserved3 = 0;
2915 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2916 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2917 byte_count = 3 /* pad */ + params + data_count;
2918 pSMB->DataCount = cpu_to_le16(data_count);
2919 pSMB->TotalDataCount = pSMB->DataCount;
2920 pSMB->ParameterCount = cpu_to_le16(params);
2921 pSMB->TotalParameterCount = pSMB->ParameterCount;
2922 pSMB->Reserved4 = 0;
2923 pSMB->hdr.smb_buf_length += byte_count;
2924 pSMB->ByteCount = cpu_to_le16(byte_count);
2925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002927 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929
2930setACLerrorExit:
2931 cifs_buf_release(pSMB);
2932 if (rc == -EAGAIN)
2933 goto setAclRetry;
2934 return rc;
2935}
2936
Steve Frenchf654bac2005-04-28 22:41:04 -07002937/* BB fix tabs in this function FIXME BB */
2938int
2939CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002940 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002941{
Steve French50c2f752007-07-13 00:33:32 +00002942 int rc = 0;
2943 struct smb_t2_qfi_req *pSMB = NULL;
2944 struct smb_t2_qfi_rsp *pSMBr = NULL;
2945 int bytes_returned;
2946 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002947
Steve French790fe572007-07-07 19:25:05 +00002948 cFYI(1, ("In GetExtAttr"));
2949 if (tcon == NULL)
2950 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002951
2952GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002953 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2954 (void **) &pSMBr);
2955 if (rc)
2956 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002957
Steve Frenchad7a2922008-02-07 23:25:02 +00002958 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002959 pSMB->t2.TotalDataCount = 0;
2960 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2961 /* BB find exact max data count below from sess structure BB */
2962 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2963 pSMB->t2.MaxSetupCount = 0;
2964 pSMB->t2.Reserved = 0;
2965 pSMB->t2.Flags = 0;
2966 pSMB->t2.Timeout = 0;
2967 pSMB->t2.Reserved2 = 0;
2968 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2969 Fid) - 4);
2970 pSMB->t2.DataCount = 0;
2971 pSMB->t2.DataOffset = 0;
2972 pSMB->t2.SetupCount = 1;
2973 pSMB->t2.Reserved3 = 0;
2974 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2975 byte_count = params + 1 /* pad */ ;
2976 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2977 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2978 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2979 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002980 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002981 pSMB->hdr.smb_buf_length += byte_count;
2982 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002983
Steve French790fe572007-07-07 19:25:05 +00002984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2986 if (rc) {
2987 cFYI(1, ("error %d in GetExtAttr", rc));
2988 } else {
2989 /* decode response */
2990 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2991 if (rc || (pSMBr->ByteCount < 2))
2992 /* BB also check enough total bytes returned */
2993 /* If rc should we check for EOPNOSUPP and
2994 disable the srvino flag? or in caller? */
2995 rc = -EIO; /* bad smb */
2996 else {
2997 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2998 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2999 struct file_chattr_info *pfinfo;
3000 /* BB Do we need a cast or hash here ? */
3001 if (count != 16) {
3002 cFYI(1, ("Illegal size ret in GetExtAttr"));
3003 rc = -EIO;
3004 goto GetExtAttrOut;
3005 }
3006 pfinfo = (struct file_chattr_info *)
3007 (data_offset + (char *) &pSMBr->hdr.Protocol);
3008 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003009 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003010 }
3011 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003012GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003013 cifs_buf_release(pSMB);
3014 if (rc == -EAGAIN)
3015 goto GetExtAttrRetry;
3016 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003017}
3018
Steve Frenchf654bac2005-04-28 22:41:04 -07003019#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020
Steve French297647c2007-10-12 04:11:59 +00003021#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003022/* Get Security Descriptor (by handle) from remote server for a file or dir */
3023int
3024CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003025 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003026{
3027 int rc = 0;
3028 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003029 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003030 struct kvec iov[1];
3031
3032 cFYI(1, ("GetCifsACL"));
3033
Steve French630f3f02007-10-25 21:17:17 +00003034 *pbuflen = 0;
3035 *acl_inf = NULL;
3036
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003037 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003038 8 /* parm len */, tcon, (void **) &pSMB);
3039 if (rc)
3040 return rc;
3041
3042 pSMB->MaxParameterCount = cpu_to_le32(4);
3043 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3044 pSMB->MaxSetupCount = 0;
3045 pSMB->Fid = fid; /* file handle always le */
3046 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3047 CIFS_ACL_DACL);
3048 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3049 pSMB->hdr.smb_buf_length += 11;
3050 iov[0].iov_base = (char *)pSMB;
3051 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3052
Steve Frencha761ac52007-10-18 21:45:27 +00003053 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003054 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003055 cifs_stats_inc(&tcon->num_acl_get);
3056 if (rc) {
3057 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3058 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003059 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003060 __u32 parm_len;
3061 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003062 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003063 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003064
3065/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003066 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003067 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003068 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003069 goto qsec_out;
3070 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3071
Steve French630f3f02007-10-25 21:17:17 +00003072 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003073
3074 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3075 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003076 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003077 goto qsec_out;
3078 }
3079
3080/* BB check that data area is minimum length and as big as acl_len */
3081
Steve Frenchaf6f4612007-10-16 18:40:37 +00003082 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003083 if (acl_len != *pbuflen) {
3084 cERROR(1, ("acl length %d does not match %d",
3085 acl_len, *pbuflen));
3086 if (*pbuflen > acl_len)
3087 *pbuflen = acl_len;
3088 }
Steve French0a4b92c2006-01-12 15:44:21 -08003089
Steve French630f3f02007-10-25 21:17:17 +00003090 /* check if buffer is big enough for the acl
3091 header followed by the smallest SID */
3092 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3093 (*pbuflen >= 64 * 1024)) {
3094 cERROR(1, ("bad acl length %d", *pbuflen));
3095 rc = -EINVAL;
3096 *pbuflen = 0;
3097 } else {
3098 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3099 if (*acl_inf == NULL) {
3100 *pbuflen = 0;
3101 rc = -ENOMEM;
3102 }
3103 memcpy(*acl_inf, pdata, *pbuflen);
3104 }
Steve French0a4b92c2006-01-12 15:44:21 -08003105 }
3106qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003107 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003108 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003109 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003110 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003111/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003112 return rc;
3113}
Steve French97837582007-12-31 07:47:21 +00003114
3115int
3116CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3117 struct cifs_ntsd *pntsd, __u32 acllen)
3118{
3119 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3120 int rc = 0;
3121 int bytes_returned = 0;
3122 SET_SEC_DESC_REQ *pSMB = NULL;
3123 NTRANSACT_RSP *pSMBr = NULL;
3124
3125setCifsAclRetry:
3126 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3127 (void **) &pSMBr);
3128 if (rc)
3129 return (rc);
3130
3131 pSMB->MaxSetupCount = 0;
3132 pSMB->Reserved = 0;
3133
3134 param_count = 8;
3135 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3136 data_count = acllen;
3137 data_offset = param_offset + param_count;
3138 byte_count = 3 /* pad */ + param_count;
3139
3140 pSMB->DataCount = cpu_to_le32(data_count);
3141 pSMB->TotalDataCount = pSMB->DataCount;
3142 pSMB->MaxParameterCount = cpu_to_le32(4);
3143 pSMB->MaxDataCount = cpu_to_le32(16384);
3144 pSMB->ParameterCount = cpu_to_le32(param_count);
3145 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3146 pSMB->TotalParameterCount = pSMB->ParameterCount;
3147 pSMB->DataOffset = cpu_to_le32(data_offset);
3148 pSMB->SetupCount = 0;
3149 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3150 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3151
3152 pSMB->Fid = fid; /* file handle always le */
3153 pSMB->Reserved2 = 0;
3154 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3155
3156 if (pntsd && acllen) {
3157 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3158 (char *) pntsd,
3159 acllen);
3160 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3161
3162 } else
3163 pSMB->hdr.smb_buf_length += byte_count;
3164
3165 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3166 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3167
3168 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3169 if (rc)
3170 cFYI(1, ("Set CIFS ACL returned %d", rc));
3171 cifs_buf_release(pSMB);
3172
3173 if (rc == -EAGAIN)
3174 goto setCifsAclRetry;
3175
3176 return (rc);
3177}
3178
Steve French297647c2007-10-12 04:11:59 +00003179#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003180
Steve French6b8edfe2005-08-23 20:26:03 -07003181/* Legacy Query Path Information call for lookup to old servers such
3182 as Win9x/WinME */
3183int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003184 const unsigned char *searchName,
3185 FILE_ALL_INFO *pFinfo,
3186 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003187{
Steve Frenchad7a2922008-02-07 23:25:02 +00003188 QUERY_INFORMATION_REQ *pSMB;
3189 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003190 int rc = 0;
3191 int bytes_returned;
3192 int name_len;
3193
Steve French50c2f752007-07-13 00:33:32 +00003194 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003195QInfRetry:
3196 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003197 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003198 if (rc)
3199 return rc;
3200
3201 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3202 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003203 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3204 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003205 name_len++; /* trailing null */
3206 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003207 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003208 name_len = strnlen(searchName, PATH_MAX);
3209 name_len++; /* trailing null */
3210 strncpy(pSMB->FileName, searchName, name_len);
3211 }
3212 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003213 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003214 pSMB->hdr.smb_buf_length += (__u16) name_len;
3215 pSMB->ByteCount = cpu_to_le16(name_len);
3216
3217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003219 if (rc) {
3220 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003221 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003222 struct timespec ts;
3223 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003224
3225 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003226 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003227 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003228 ts.tv_nsec = 0;
3229 ts.tv_sec = time;
3230 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003231 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003232 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3233 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003234 pFinfo->AllocationSize =
3235 cpu_to_le64(le32_to_cpu(pSMBr->size));
3236 pFinfo->EndOfFile = pFinfo->AllocationSize;
3237 pFinfo->Attributes =
3238 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003239 } else
3240 rc = -EIO; /* bad buffer passed in */
3241
3242 cifs_buf_release(pSMB);
3243
3244 if (rc == -EAGAIN)
3245 goto QInfRetry;
3246
3247 return rc;
3248}
3249
Jeff Laytonbcd53572010-02-12 07:44:16 -05003250int
3251CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3252 u16 netfid, FILE_ALL_INFO *pFindData)
3253{
3254 struct smb_t2_qfi_req *pSMB = NULL;
3255 struct smb_t2_qfi_rsp *pSMBr = NULL;
3256 int rc = 0;
3257 int bytes_returned;
3258 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003259
Jeff Laytonbcd53572010-02-12 07:44:16 -05003260QFileInfoRetry:
3261 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3262 (void **) &pSMBr);
3263 if (rc)
3264 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003265
Jeff Laytonbcd53572010-02-12 07:44:16 -05003266 params = 2 /* level */ + 2 /* fid */;
3267 pSMB->t2.TotalDataCount = 0;
3268 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3269 /* BB find exact max data count below from sess structure BB */
3270 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3271 pSMB->t2.MaxSetupCount = 0;
3272 pSMB->t2.Reserved = 0;
3273 pSMB->t2.Flags = 0;
3274 pSMB->t2.Timeout = 0;
3275 pSMB->t2.Reserved2 = 0;
3276 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3277 Fid) - 4);
3278 pSMB->t2.DataCount = 0;
3279 pSMB->t2.DataOffset = 0;
3280 pSMB->t2.SetupCount = 1;
3281 pSMB->t2.Reserved3 = 0;
3282 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3283 byte_count = params + 1 /* pad */ ;
3284 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3285 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3286 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3287 pSMB->Pad = 0;
3288 pSMB->Fid = netfid;
3289 pSMB->hdr.smb_buf_length += byte_count;
3290
3291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3292 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3293 if (rc) {
3294 cFYI(1, ("Send error in QPathInfo = %d", rc));
3295 } else { /* decode response */
3296 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3297
3298 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3299 rc = -EIO;
3300 else if (pSMBr->ByteCount < 40)
3301 rc = -EIO; /* bad smb */
3302 else if (pFindData) {
3303 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3304 memcpy((char *) pFindData,
3305 (char *) &pSMBr->hdr.Protocol +
3306 data_offset, sizeof(FILE_ALL_INFO));
3307 } else
3308 rc = -ENOMEM;
3309 }
3310 cifs_buf_release(pSMB);
3311 if (rc == -EAGAIN)
3312 goto QFileInfoRetry;
3313
3314 return rc;
3315}
Steve French6b8edfe2005-08-23 20:26:03 -07003316
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317int
3318CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3319 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003320 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003321 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003322 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323{
3324/* level 263 SMB_QUERY_FILE_ALL_INFO */
3325 TRANSACTION2_QPI_REQ *pSMB = NULL;
3326 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3327 int rc = 0;
3328 int bytes_returned;
3329 int name_len;
3330 __u16 params, byte_count;
3331
3332/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3333QPathInfoRetry:
3334 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3335 (void **) &pSMBr);
3336 if (rc)
3337 return rc;
3338
3339 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3340 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003341 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003342 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 name_len++; /* trailing null */
3344 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003345 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 name_len = strnlen(searchName, PATH_MAX);
3347 name_len++; /* trailing null */
3348 strncpy(pSMB->FileName, searchName, name_len);
3349 }
3350
Steve French50c2f752007-07-13 00:33:32 +00003351 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 pSMB->TotalDataCount = 0;
3353 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003354 /* BB find exact max SMB PDU from sess structure BB */
3355 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 pSMB->MaxSetupCount = 0;
3357 pSMB->Reserved = 0;
3358 pSMB->Flags = 0;
3359 pSMB->Timeout = 0;
3360 pSMB->Reserved2 = 0;
3361 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003362 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 pSMB->DataCount = 0;
3364 pSMB->DataOffset = 0;
3365 pSMB->SetupCount = 1;
3366 pSMB->Reserved3 = 0;
3367 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3368 byte_count = params + 1 /* pad */ ;
3369 pSMB->TotalParameterCount = cpu_to_le16(params);
3370 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003371 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003372 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3373 else
3374 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 pSMB->Reserved4 = 0;
3376 pSMB->hdr.smb_buf_length += byte_count;
3377 pSMB->ByteCount = cpu_to_le16(byte_count);
3378
3379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3380 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3381 if (rc) {
3382 cFYI(1, ("Send error in QPathInfo = %d", rc));
3383 } else { /* decode response */
3384 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3385
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003386 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3387 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003388 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003390 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003391 rc = -EIO; /* 24 or 26 expected but we do not read
3392 last field */
3393 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003394 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003396
3397 /* On legacy responses we do not read the last field,
3398 EAsize, fortunately since it varies by subdialect and
3399 also note it differs on Set vs. Get, ie two bytes or 4
3400 bytes depending but we don't care here */
3401 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003402 size = sizeof(FILE_INFO_STANDARD);
3403 else
3404 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 memcpy((char *) pFindData,
3406 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003407 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 } else
3409 rc = -ENOMEM;
3410 }
3411 cifs_buf_release(pSMB);
3412 if (rc == -EAGAIN)
3413 goto QPathInfoRetry;
3414
3415 return rc;
3416}
3417
3418int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003419CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3420 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3421{
3422 struct smb_t2_qfi_req *pSMB = NULL;
3423 struct smb_t2_qfi_rsp *pSMBr = NULL;
3424 int rc = 0;
3425 int bytes_returned;
3426 __u16 params, byte_count;
3427
3428UnixQFileInfoRetry:
3429 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3430 (void **) &pSMBr);
3431 if (rc)
3432 return rc;
3433
3434 params = 2 /* level */ + 2 /* fid */;
3435 pSMB->t2.TotalDataCount = 0;
3436 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3437 /* BB find exact max data count below from sess structure BB */
3438 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3439 pSMB->t2.MaxSetupCount = 0;
3440 pSMB->t2.Reserved = 0;
3441 pSMB->t2.Flags = 0;
3442 pSMB->t2.Timeout = 0;
3443 pSMB->t2.Reserved2 = 0;
3444 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3445 Fid) - 4);
3446 pSMB->t2.DataCount = 0;
3447 pSMB->t2.DataOffset = 0;
3448 pSMB->t2.SetupCount = 1;
3449 pSMB->t2.Reserved3 = 0;
3450 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3451 byte_count = params + 1 /* pad */ ;
3452 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3453 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3454 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3455 pSMB->Pad = 0;
3456 pSMB->Fid = netfid;
3457 pSMB->hdr.smb_buf_length += byte_count;
3458
3459 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3460 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3461 if (rc) {
3462 cFYI(1, ("Send error in QPathInfo = %d", rc));
3463 } else { /* decode response */
3464 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3465
3466 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3467 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3468 "Unix Extensions can be disabled on mount "
3469 "by specifying the nosfu mount option."));
3470 rc = -EIO; /* bad smb */
3471 } else {
3472 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3473 memcpy((char *) pFindData,
3474 (char *) &pSMBr->hdr.Protocol +
3475 data_offset,
3476 sizeof(FILE_UNIX_BASIC_INFO));
3477 }
3478 }
3479
3480 cifs_buf_release(pSMB);
3481 if (rc == -EAGAIN)
3482 goto UnixQFileInfoRetry;
3483
3484 return rc;
3485}
3486
3487int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3489 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003490 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003491 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492{
3493/* SMB_QUERY_FILE_UNIX_BASIC */
3494 TRANSACTION2_QPI_REQ *pSMB = NULL;
3495 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3496 int rc = 0;
3497 int bytes_returned = 0;
3498 int name_len;
3499 __u16 params, byte_count;
3500
3501 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3502UnixQPathInfoRetry:
3503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3504 (void **) &pSMBr);
3505 if (rc)
3506 return rc;
3507
3508 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3509 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003510 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003511 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 name_len++; /* trailing null */
3513 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003514 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 name_len = strnlen(searchName, PATH_MAX);
3516 name_len++; /* trailing null */
3517 strncpy(pSMB->FileName, searchName, name_len);
3518 }
3519
Steve French50c2f752007-07-13 00:33:32 +00003520 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 pSMB->TotalDataCount = 0;
3522 pSMB->MaxParameterCount = cpu_to_le16(2);
3523 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003524 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525 pSMB->MaxSetupCount = 0;
3526 pSMB->Reserved = 0;
3527 pSMB->Flags = 0;
3528 pSMB->Timeout = 0;
3529 pSMB->Reserved2 = 0;
3530 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003531 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 pSMB->DataCount = 0;
3533 pSMB->DataOffset = 0;
3534 pSMB->SetupCount = 1;
3535 pSMB->Reserved3 = 0;
3536 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3537 byte_count = params + 1 /* pad */ ;
3538 pSMB->TotalParameterCount = cpu_to_le16(params);
3539 pSMB->ParameterCount = pSMB->TotalParameterCount;
3540 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3541 pSMB->Reserved4 = 0;
3542 pSMB->hdr.smb_buf_length += byte_count;
3543 pSMB->ByteCount = cpu_to_le16(byte_count);
3544
3545 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3546 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3547 if (rc) {
3548 cFYI(1, ("Send error in QPathInfo = %d", rc));
3549 } else { /* decode response */
3550 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3551
3552 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003553 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3554 "Unix Extensions can be disabled on mount "
3555 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556 rc = -EIO; /* bad smb */
3557 } else {
3558 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3559 memcpy((char *) pFindData,
3560 (char *) &pSMBr->hdr.Protocol +
3561 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003562 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 }
3564 }
3565 cifs_buf_release(pSMB);
3566 if (rc == -EAGAIN)
3567 goto UnixQPathInfoRetry;
3568
3569 return rc;
3570}
3571
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572/* xid, tcon, searchName and codepage are input parms, rest are returned */
3573int
3574CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003575 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003577 __u16 *pnetfid,
3578 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579{
3580/* level 257 SMB_ */
3581 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3582 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003583 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 int rc = 0;
3585 int bytes_returned = 0;
3586 int name_len;
3587 __u16 params, byte_count;
3588
Steve French50c2f752007-07-13 00:33:32 +00003589 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
3591findFirstRetry:
3592 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3593 (void **) &pSMBr);
3594 if (rc)
3595 return rc;
3596
3597 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3598 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003599 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003600 PATH_MAX, nls_codepage, remap);
3601 /* We can not add the asterik earlier in case
3602 it got remapped to 0xF03A as if it were part of the
3603 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003605 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003606 pSMB->FileName[name_len+1] = 0;
3607 pSMB->FileName[name_len+2] = '*';
3608 pSMB->FileName[name_len+3] = 0;
3609 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3611 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003612 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 } else { /* BB add check for overrun of SMB buf BB */
3614 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003616 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003617 free buffer exit; BB */
3618 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003619 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003620 pSMB->FileName[name_len+1] = '*';
3621 pSMB->FileName[name_len+2] = 0;
3622 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 }
3624
3625 params = 12 + name_len /* includes null */ ;
3626 pSMB->TotalDataCount = 0; /* no EAs */
3627 pSMB->MaxParameterCount = cpu_to_le16(10);
3628 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3629 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3630 pSMB->MaxSetupCount = 0;
3631 pSMB->Reserved = 0;
3632 pSMB->Flags = 0;
3633 pSMB->Timeout = 0;
3634 pSMB->Reserved2 = 0;
3635 byte_count = params + 1 /* pad */ ;
3636 pSMB->TotalParameterCount = cpu_to_le16(params);
3637 pSMB->ParameterCount = pSMB->TotalParameterCount;
3638 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003639 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3640 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 pSMB->DataCount = 0;
3642 pSMB->DataOffset = 0;
3643 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3644 pSMB->Reserved3 = 0;
3645 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3646 pSMB->SearchAttributes =
3647 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3648 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003649 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3650 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 CIFS_SEARCH_RETURN_RESUME);
3652 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3653
3654 /* BB what should we set StorageType to? Does it matter? BB */
3655 pSMB->SearchStorageType = 0;
3656 pSMB->hdr.smb_buf_length += byte_count;
3657 pSMB->ByteCount = cpu_to_le16(byte_count);
3658
3659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003661 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
Steve French88274812006-03-09 22:21:45 +00003663 if (rc) {/* BB add logic to retry regular search if Unix search
3664 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 /* BB Add code to handle unsupported level rc */
3666 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003667
Steve French88274812006-03-09 22:21:45 +00003668 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669
3670 /* BB eventually could optimize out free and realloc of buf */
3671 /* for this case */
3672 if (rc == -EAGAIN)
3673 goto findFirstRetry;
3674 } else { /* decode response */
3675 /* BB remember to free buffer if error BB */
3676 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003677 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003678 unsigned int lnoff;
3679
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003681 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 else
Steve French4b18f2a2008-04-29 00:06:05 +00003683 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684
3685 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003686 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003687 psrch_inf->srch_entries_start =
3688 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3691 le16_to_cpu(pSMBr->t2.ParameterOffset));
3692
Steve French790fe572007-07-07 19:25:05 +00003693 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003694 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 else
Steve French4b18f2a2008-04-29 00:06:05 +00003696 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697
Steve French50c2f752007-07-13 00:33:32 +00003698 psrch_inf->entries_in_buffer =
3699 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003700 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003702 lnoff = le16_to_cpu(parms->LastNameOffset);
3703 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3704 lnoff) {
3705 cERROR(1, ("ignoring corrupt resume name"));
3706 psrch_inf->last_entry = NULL;
3707 return rc;
3708 }
3709
Steve French0752f152008-10-07 20:03:33 +00003710 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003711 lnoff;
3712
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 *pnetfid = parms->SearchHandle;
3714 } else {
3715 cifs_buf_release(pSMB);
3716 }
3717 }
3718
3719 return rc;
3720}
3721
3722int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003723 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724{
3725 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3726 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003727 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 char *response_data;
3729 int rc = 0;
3730 int bytes_returned, name_len;
3731 __u16 params, byte_count;
3732
3733 cFYI(1, ("In FindNext"));
3734
Steve French4b18f2a2008-04-29 00:06:05 +00003735 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 return -ENOENT;
3737
3738 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3739 (void **) &pSMBr);
3740 if (rc)
3741 return rc;
3742
Steve French50c2f752007-07-13 00:33:32 +00003743 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 byte_count = 0;
3745 pSMB->TotalDataCount = 0; /* no EAs */
3746 pSMB->MaxParameterCount = cpu_to_le16(8);
3747 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003748 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3749 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 pSMB->MaxSetupCount = 0;
3751 pSMB->Reserved = 0;
3752 pSMB->Flags = 0;
3753 pSMB->Timeout = 0;
3754 pSMB->Reserved2 = 0;
3755 pSMB->ParameterOffset = cpu_to_le16(
3756 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3757 pSMB->DataCount = 0;
3758 pSMB->DataOffset = 0;
3759 pSMB->SetupCount = 1;
3760 pSMB->Reserved3 = 0;
3761 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3762 pSMB->SearchHandle = searchHandle; /* always kept as le */
3763 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003764 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3766 pSMB->ResumeKey = psrch_inf->resume_key;
3767 pSMB->SearchFlags =
3768 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3769
3770 name_len = psrch_inf->resume_name_len;
3771 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003772 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3774 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003775 /* 14 byte parm len above enough for 2 byte null terminator */
3776 pSMB->ResumeFileName[name_len] = 0;
3777 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 } else {
3779 rc = -EINVAL;
3780 goto FNext2_err_exit;
3781 }
3782 byte_count = params + 1 /* pad */ ;
3783 pSMB->TotalParameterCount = cpu_to_le16(params);
3784 pSMB->ParameterCount = pSMB->TotalParameterCount;
3785 pSMB->hdr.smb_buf_length += byte_count;
3786 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003787
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3789 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003790 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 if (rc) {
3792 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003793 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003794 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003795 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796 } else
3797 cFYI(1, ("FindNext returned = %d", rc));
3798 } else { /* decode response */
3799 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003800
Steve French790fe572007-07-07 19:25:05 +00003801 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003802 unsigned int lnoff;
3803
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 /* BB fixme add lock for file (srch_info) struct here */
3805 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003806 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003807 else
Steve French4b18f2a2008-04-29 00:06:05 +00003808 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 response_data = (char *) &pSMBr->hdr.Protocol +
3810 le16_to_cpu(pSMBr->t2.ParameterOffset);
3811 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3812 response_data = (char *)&pSMBr->hdr.Protocol +
3813 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003814 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003815 cifs_small_buf_release(
3816 psrch_inf->ntwrk_buf_start);
3817 else
3818 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 psrch_inf->srch_entries_start = response_data;
3820 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003821 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003822 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003823 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 else
Steve French4b18f2a2008-04-29 00:06:05 +00003825 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003826 psrch_inf->entries_in_buffer =
3827 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828 psrch_inf->index_of_last_entry +=
3829 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003830 lnoff = le16_to_cpu(parms->LastNameOffset);
3831 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3832 lnoff) {
3833 cERROR(1, ("ignoring corrupt resume name"));
3834 psrch_inf->last_entry = NULL;
3835 return rc;
3836 } else
3837 psrch_inf->last_entry =
3838 psrch_inf->srch_entries_start + lnoff;
3839
Steve French50c2f752007-07-13 00:33:32 +00003840/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3841 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842
3843 /* BB fixme add unlock here */
3844 }
3845
3846 }
3847
3848 /* BB On error, should we leave previous search buf (and count and
3849 last entry fields) intact or free the previous one? */
3850
3851 /* Note: On -EAGAIN error only caller can retry on handle based calls
3852 since file handle passed in no longer valid */
3853FNext2_err_exit:
3854 if (rc != 0)
3855 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 return rc;
3857}
3858
3859int
Steve French50c2f752007-07-13 00:33:32 +00003860CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3861 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862{
3863 int rc = 0;
3864 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
3866 cFYI(1, ("In CIFSSMBFindClose"));
3867 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3868
3869 /* no sense returning error if session restarted
3870 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003871 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 return 0;
3873 if (rc)
3874 return rc;
3875
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 pSMB->FileID = searchHandle;
3877 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003878 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003879 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003881
Steve Frencha4544342005-08-24 13:59:35 -07003882 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883
3884 /* Since session is dead, search handle closed on server already */
3885 if (rc == -EAGAIN)
3886 rc = 0;
3887
3888 return rc;
3889}
3890
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891int
3892CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003893 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003894 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003895 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896{
3897 int rc = 0;
3898 TRANSACTION2_QPI_REQ *pSMB = NULL;
3899 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3900 int name_len, bytes_returned;
3901 __u16 params, byte_count;
3902
Steve French50c2f752007-07-13 00:33:32 +00003903 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003904 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003905 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
3907GetInodeNumberRetry:
3908 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003909 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 if (rc)
3911 return rc;
3912
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3914 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003915 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003916 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917 name_len++; /* trailing null */
3918 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003919 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 name_len = strnlen(searchName, PATH_MAX);
3921 name_len++; /* trailing null */
3922 strncpy(pSMB->FileName, searchName, name_len);
3923 }
3924
3925 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3926 pSMB->TotalDataCount = 0;
3927 pSMB->MaxParameterCount = cpu_to_le16(2);
3928 /* BB find exact max data count below from sess structure BB */
3929 pSMB->MaxDataCount = cpu_to_le16(4000);
3930 pSMB->MaxSetupCount = 0;
3931 pSMB->Reserved = 0;
3932 pSMB->Flags = 0;
3933 pSMB->Timeout = 0;
3934 pSMB->Reserved2 = 0;
3935 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003936 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 pSMB->DataCount = 0;
3938 pSMB->DataOffset = 0;
3939 pSMB->SetupCount = 1;
3940 pSMB->Reserved3 = 0;
3941 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3942 byte_count = params + 1 /* pad */ ;
3943 pSMB->TotalParameterCount = cpu_to_le16(params);
3944 pSMB->ParameterCount = pSMB->TotalParameterCount;
3945 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3946 pSMB->Reserved4 = 0;
3947 pSMB->hdr.smb_buf_length += byte_count;
3948 pSMB->ByteCount = cpu_to_le16(byte_count);
3949
3950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3952 if (rc) {
3953 cFYI(1, ("error %d in QueryInternalInfo", rc));
3954 } else {
3955 /* decode response */
3956 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3957 if (rc || (pSMBr->ByteCount < 2))
3958 /* BB also check enough total bytes returned */
3959 /* If rc should we check for EOPNOSUPP and
3960 disable the srvino flag? or in caller? */
3961 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003962 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3964 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003965 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003967 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3969 rc = -EIO;
3970 goto GetInodeNumOut;
3971 }
3972 pfinfo = (struct file_internal_info *)
3973 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003974 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 }
3976 }
3977GetInodeNumOut:
3978 cifs_buf_release(pSMB);
3979 if (rc == -EAGAIN)
3980 goto GetInodeNumberRetry;
3981 return rc;
3982}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
Igor Mammedovfec45852008-05-16 13:06:30 +04003984/* parses DFS refferal V3 structure
3985 * caller is responsible for freeing target_nodes
3986 * returns:
3987 * on success - 0
3988 * on failure - errno
3989 */
3990static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003991parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003992 unsigned int *num_of_nodes,
3993 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003994 const struct nls_table *nls_codepage, int remap,
3995 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003996{
3997 int i, rc = 0;
3998 char *data_end;
3999 bool is_unicode;
4000 struct dfs_referral_level_3 *ref;
4001
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004002 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4003 is_unicode = true;
4004 else
4005 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004006 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4007
4008 if (*num_of_nodes < 1) {
4009 cERROR(1, ("num_referrals: must be at least > 0,"
4010 "but we get num_referrals = %d\n", *num_of_nodes));
4011 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004012 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004013 }
4014
4015 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004016 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004017 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01004018 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04004019 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004020 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004021 }
4022
4023 /* get the upper boundary of the resp buffer */
4024 data_end = (char *)(&(pSMBr->PathConsumed)) +
4025 le16_to_cpu(pSMBr->t2.DataCount);
4026
4027 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
4028 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00004029 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04004030
4031 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4032 *num_of_nodes, GFP_KERNEL);
4033 if (*target_nodes == NULL) {
4034 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
4035 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004036 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004037 }
4038
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004039 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004040 for (i = 0; i < *num_of_nodes; i++) {
4041 char *temp;
4042 int max_len;
4043 struct dfs_info3_param *node = (*target_nodes)+i;
4044
Steve French0e0d2cf2009-05-01 05:27:32 +00004045 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004046 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004047 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4048 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004049 if (tmp == NULL) {
4050 rc = -ENOMEM;
4051 goto parse_DFS_referrals_exit;
4052 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004053 cifsConvertToUCS((__le16 *) tmp, searchName,
4054 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004055 node->path_consumed = cifs_ucs2_bytes(tmp,
4056 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004057 nls_codepage);
4058 kfree(tmp);
4059 } else
4060 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4061
Igor Mammedovfec45852008-05-16 13:06:30 +04004062 node->server_type = le16_to_cpu(ref->ServerType);
4063 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4064
4065 /* copy DfsPath */
4066 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4067 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004068 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4069 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004070 if (!node->path_name) {
4071 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004072 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004073 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004074
4075 /* copy link target UNC */
4076 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4077 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004078 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4079 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004080 if (!node->node_name)
4081 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004082 }
4083
Steve Frencha1fe78f2008-05-16 18:48:38 +00004084parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004085 if (rc) {
4086 free_dfs_info_array(*target_nodes, *num_of_nodes);
4087 *target_nodes = NULL;
4088 *num_of_nodes = 0;
4089 }
4090 return rc;
4091}
4092
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093int
4094CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4095 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004096 struct dfs_info3_param **target_nodes,
4097 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004098 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099{
4100/* TRANS2_GET_DFS_REFERRAL */
4101 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4102 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 int rc = 0;
4104 int bytes_returned;
4105 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004107 *num_of_nodes = 0;
4108 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109
4110 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4111 if (ses == NULL)
4112 return -ENODEV;
4113getDFSRetry:
4114 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4115 (void **) &pSMBr);
4116 if (rc)
4117 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004118
4119 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004120 but should never be null here anyway */
4121 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 pSMB->hdr.Tid = ses->ipc_tid;
4123 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004124 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004126 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128
4129 if (ses->capabilities & CAP_UNICODE) {
4130 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4131 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004132 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004133 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 name_len++; /* trailing null */
4135 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004136 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 name_len = strnlen(searchName, PATH_MAX);
4138 name_len++; /* trailing null */
4139 strncpy(pSMB->RequestFileName, searchName, name_len);
4140 }
4141
Steve French790fe572007-07-07 19:25:05 +00004142 if (ses->server) {
4143 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004144 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4145 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4146 }
4147
Steve French50c2f752007-07-13 00:33:32 +00004148 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004149
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 params = 2 /* level */ + name_len /*includes null */ ;
4151 pSMB->TotalDataCount = 0;
4152 pSMB->DataCount = 0;
4153 pSMB->DataOffset = 0;
4154 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004155 /* BB find exact max SMB PDU from sess structure BB */
4156 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 pSMB->MaxSetupCount = 0;
4158 pSMB->Reserved = 0;
4159 pSMB->Flags = 0;
4160 pSMB->Timeout = 0;
4161 pSMB->Reserved2 = 0;
4162 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004163 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 pSMB->SetupCount = 1;
4165 pSMB->Reserved3 = 0;
4166 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4167 byte_count = params + 3 /* pad */ ;
4168 pSMB->ParameterCount = cpu_to_le16(params);
4169 pSMB->TotalParameterCount = pSMB->ParameterCount;
4170 pSMB->MaxReferralLevel = cpu_to_le16(3);
4171 pSMB->hdr.smb_buf_length += byte_count;
4172 pSMB->ByteCount = cpu_to_le16(byte_count);
4173
4174 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4175 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4176 if (rc) {
4177 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004178 goto GetDFSRefExit;
4179 }
4180 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004182 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004183 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004184 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004185 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004187
4188 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4189 pSMBr->ByteCount,
4190 le16_to_cpu(pSMBr->t2.DataOffset)));
4191
4192 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004193 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004194 target_nodes, nls_codepage, remap,
4195 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004196
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004198 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199
4200 if (rc == -EAGAIN)
4201 goto getDFSRetry;
4202
4203 return rc;
4204}
4205
Steve French20962432005-09-21 22:05:57 -07004206/* Query File System Info such as free space to old servers such as Win 9x */
4207int
4208SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4209{
4210/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4211 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4212 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4213 FILE_SYSTEM_ALLOC_INFO *response_data;
4214 int rc = 0;
4215 int bytes_returned = 0;
4216 __u16 params, byte_count;
4217
4218 cFYI(1, ("OldQFSInfo"));
4219oldQFSInfoRetry:
4220 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4221 (void **) &pSMBr);
4222 if (rc)
4223 return rc;
Steve French20962432005-09-21 22:05:57 -07004224
4225 params = 2; /* level */
4226 pSMB->TotalDataCount = 0;
4227 pSMB->MaxParameterCount = cpu_to_le16(2);
4228 pSMB->MaxDataCount = cpu_to_le16(1000);
4229 pSMB->MaxSetupCount = 0;
4230 pSMB->Reserved = 0;
4231 pSMB->Flags = 0;
4232 pSMB->Timeout = 0;
4233 pSMB->Reserved2 = 0;
4234 byte_count = params + 1 /* pad */ ;
4235 pSMB->TotalParameterCount = cpu_to_le16(params);
4236 pSMB->ParameterCount = pSMB->TotalParameterCount;
4237 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4238 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4239 pSMB->DataCount = 0;
4240 pSMB->DataOffset = 0;
4241 pSMB->SetupCount = 1;
4242 pSMB->Reserved3 = 0;
4243 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4244 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4245 pSMB->hdr.smb_buf_length += byte_count;
4246 pSMB->ByteCount = cpu_to_le16(byte_count);
4247
4248 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4249 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4250 if (rc) {
4251 cFYI(1, ("Send error in QFSInfo = %d", rc));
4252 } else { /* decode response */
4253 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4254
4255 if (rc || (pSMBr->ByteCount < 18))
4256 rc = -EIO; /* bad smb */
4257 else {
4258 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004259 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004260 pSMBr->ByteCount, data_offset));
4261
Steve French50c2f752007-07-13 00:33:32 +00004262 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004263 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4264 FSData->f_bsize =
4265 le16_to_cpu(response_data->BytesPerSector) *
4266 le32_to_cpu(response_data->
4267 SectorsPerAllocationUnit);
4268 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004269 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004270 FSData->f_bfree = FSData->f_bavail =
4271 le32_to_cpu(response_data->FreeAllocationUnits);
4272 cFYI(1,
4273 ("Blocks: %lld Free: %lld Block size %ld",
4274 (unsigned long long)FSData->f_blocks,
4275 (unsigned long long)FSData->f_bfree,
4276 FSData->f_bsize));
4277 }
4278 }
4279 cifs_buf_release(pSMB);
4280
4281 if (rc == -EAGAIN)
4282 goto oldQFSInfoRetry;
4283
4284 return rc;
4285}
4286
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287int
Steve French737b7582005-04-28 22:41:06 -07004288CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289{
4290/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4291 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4292 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4293 FILE_SYSTEM_INFO *response_data;
4294 int rc = 0;
4295 int bytes_returned = 0;
4296 __u16 params, byte_count;
4297
4298 cFYI(1, ("In QFSInfo"));
4299QFSInfoRetry:
4300 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4301 (void **) &pSMBr);
4302 if (rc)
4303 return rc;
4304
4305 params = 2; /* level */
4306 pSMB->TotalDataCount = 0;
4307 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004308 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 pSMB->MaxSetupCount = 0;
4310 pSMB->Reserved = 0;
4311 pSMB->Flags = 0;
4312 pSMB->Timeout = 0;
4313 pSMB->Reserved2 = 0;
4314 byte_count = params + 1 /* pad */ ;
4315 pSMB->TotalParameterCount = cpu_to_le16(params);
4316 pSMB->ParameterCount = pSMB->TotalParameterCount;
4317 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004318 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 pSMB->DataCount = 0;
4320 pSMB->DataOffset = 0;
4321 pSMB->SetupCount = 1;
4322 pSMB->Reserved3 = 0;
4323 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4324 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4325 pSMB->hdr.smb_buf_length += byte_count;
4326 pSMB->ByteCount = cpu_to_le16(byte_count);
4327
4328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4329 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4330 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004331 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004333 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334
Steve French20962432005-09-21 22:05:57 -07004335 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 rc = -EIO; /* bad smb */
4337 else {
4338 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339
4340 response_data =
4341 (FILE_SYSTEM_INFO
4342 *) (((char *) &pSMBr->hdr.Protocol) +
4343 data_offset);
4344 FSData->f_bsize =
4345 le32_to_cpu(response_data->BytesPerSector) *
4346 le32_to_cpu(response_data->
4347 SectorsPerAllocationUnit);
4348 FSData->f_blocks =
4349 le64_to_cpu(response_data->TotalAllocationUnits);
4350 FSData->f_bfree = FSData->f_bavail =
4351 le64_to_cpu(response_data->FreeAllocationUnits);
4352 cFYI(1,
4353 ("Blocks: %lld Free: %lld Block size %ld",
4354 (unsigned long long)FSData->f_blocks,
4355 (unsigned long long)FSData->f_bfree,
4356 FSData->f_bsize));
4357 }
4358 }
4359 cifs_buf_release(pSMB);
4360
4361 if (rc == -EAGAIN)
4362 goto QFSInfoRetry;
4363
4364 return rc;
4365}
4366
4367int
Steve French737b7582005-04-28 22:41:06 -07004368CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369{
4370/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4371 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4372 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4373 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4374 int rc = 0;
4375 int bytes_returned = 0;
4376 __u16 params, byte_count;
4377
4378 cFYI(1, ("In QFSAttributeInfo"));
4379QFSAttributeRetry:
4380 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4381 (void **) &pSMBr);
4382 if (rc)
4383 return rc;
4384
4385 params = 2; /* level */
4386 pSMB->TotalDataCount = 0;
4387 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004388 /* BB find exact max SMB PDU from sess structure BB */
4389 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 pSMB->MaxSetupCount = 0;
4391 pSMB->Reserved = 0;
4392 pSMB->Flags = 0;
4393 pSMB->Timeout = 0;
4394 pSMB->Reserved2 = 0;
4395 byte_count = params + 1 /* pad */ ;
4396 pSMB->TotalParameterCount = cpu_to_le16(params);
4397 pSMB->ParameterCount = pSMB->TotalParameterCount;
4398 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004399 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 pSMB->DataCount = 0;
4401 pSMB->DataOffset = 0;
4402 pSMB->SetupCount = 1;
4403 pSMB->Reserved3 = 0;
4404 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4405 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4406 pSMB->hdr.smb_buf_length += byte_count;
4407 pSMB->ByteCount = cpu_to_le16(byte_count);
4408
4409 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4410 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4411 if (rc) {
4412 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4413 } else { /* decode response */
4414 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4415
Steve French50c2f752007-07-13 00:33:32 +00004416 if (rc || (pSMBr->ByteCount < 13)) {
4417 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418 rc = -EIO; /* bad smb */
4419 } else {
4420 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4421 response_data =
4422 (FILE_SYSTEM_ATTRIBUTE_INFO
4423 *) (((char *) &pSMBr->hdr.Protocol) +
4424 data_offset);
4425 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004426 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 }
4428 }
4429 cifs_buf_release(pSMB);
4430
4431 if (rc == -EAGAIN)
4432 goto QFSAttributeRetry;
4433
4434 return rc;
4435}
4436
4437int
Steve French737b7582005-04-28 22:41:06 -07004438CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439{
4440/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4441 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4442 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4443 FILE_SYSTEM_DEVICE_INFO *response_data;
4444 int rc = 0;
4445 int bytes_returned = 0;
4446 __u16 params, byte_count;
4447
4448 cFYI(1, ("In QFSDeviceInfo"));
4449QFSDeviceRetry:
4450 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4451 (void **) &pSMBr);
4452 if (rc)
4453 return rc;
4454
4455 params = 2; /* level */
4456 pSMB->TotalDataCount = 0;
4457 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004458 /* BB find exact max SMB PDU from sess structure BB */
4459 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 pSMB->MaxSetupCount = 0;
4461 pSMB->Reserved = 0;
4462 pSMB->Flags = 0;
4463 pSMB->Timeout = 0;
4464 pSMB->Reserved2 = 0;
4465 byte_count = params + 1 /* pad */ ;
4466 pSMB->TotalParameterCount = cpu_to_le16(params);
4467 pSMB->ParameterCount = pSMB->TotalParameterCount;
4468 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004469 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470
4471 pSMB->DataCount = 0;
4472 pSMB->DataOffset = 0;
4473 pSMB->SetupCount = 1;
4474 pSMB->Reserved3 = 0;
4475 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4476 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4477 pSMB->hdr.smb_buf_length += byte_count;
4478 pSMB->ByteCount = cpu_to_le16(byte_count);
4479
4480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4482 if (rc) {
4483 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4484 } else { /* decode response */
4485 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4486
Steve French630f3f02007-10-25 21:17:17 +00004487 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 rc = -EIO; /* bad smb */
4489 else {
4490 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4491 response_data =
Steve French737b7582005-04-28 22:41:06 -07004492 (FILE_SYSTEM_DEVICE_INFO *)
4493 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 data_offset);
4495 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004496 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 }
4498 }
4499 cifs_buf_release(pSMB);
4500
4501 if (rc == -EAGAIN)
4502 goto QFSDeviceRetry;
4503
4504 return rc;
4505}
4506
4507int
Steve French737b7582005-04-28 22:41:06 -07004508CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509{
4510/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4511 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4512 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4513 FILE_SYSTEM_UNIX_INFO *response_data;
4514 int rc = 0;
4515 int bytes_returned = 0;
4516 __u16 params, byte_count;
4517
4518 cFYI(1, ("In QFSUnixInfo"));
4519QFSUnixRetry:
4520 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4521 (void **) &pSMBr);
4522 if (rc)
4523 return rc;
4524
4525 params = 2; /* level */
4526 pSMB->TotalDataCount = 0;
4527 pSMB->DataCount = 0;
4528 pSMB->DataOffset = 0;
4529 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004530 /* BB find exact max SMB PDU from sess structure BB */
4531 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 pSMB->MaxSetupCount = 0;
4533 pSMB->Reserved = 0;
4534 pSMB->Flags = 0;
4535 pSMB->Timeout = 0;
4536 pSMB->Reserved2 = 0;
4537 byte_count = params + 1 /* pad */ ;
4538 pSMB->ParameterCount = cpu_to_le16(params);
4539 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004540 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4541 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 pSMB->SetupCount = 1;
4543 pSMB->Reserved3 = 0;
4544 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4545 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4546 pSMB->hdr.smb_buf_length += byte_count;
4547 pSMB->ByteCount = cpu_to_le16(byte_count);
4548
4549 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4550 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4551 if (rc) {
4552 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4553 } else { /* decode response */
4554 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4555
4556 if (rc || (pSMBr->ByteCount < 13)) {
4557 rc = -EIO; /* bad smb */
4558 } else {
4559 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4560 response_data =
4561 (FILE_SYSTEM_UNIX_INFO
4562 *) (((char *) &pSMBr->hdr.Protocol) +
4563 data_offset);
4564 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004565 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 }
4567 }
4568 cifs_buf_release(pSMB);
4569
4570 if (rc == -EAGAIN)
4571 goto QFSUnixRetry;
4572
4573
4574 return rc;
4575}
4576
Jeremy Allisonac670552005-06-22 17:26:35 -07004577int
Steve French45abc6e2005-06-23 13:42:03 -05004578CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004579{
4580/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4581 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4582 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4583 int rc = 0;
4584 int bytes_returned = 0;
4585 __u16 params, param_offset, offset, byte_count;
4586
4587 cFYI(1, ("In SETFSUnixInfo"));
4588SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004589 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004590 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4591 (void **) &pSMBr);
4592 if (rc)
4593 return rc;
4594
4595 params = 4; /* 2 bytes zero followed by info level. */
4596 pSMB->MaxSetupCount = 0;
4597 pSMB->Reserved = 0;
4598 pSMB->Flags = 0;
4599 pSMB->Timeout = 0;
4600 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004601 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4602 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004603 offset = param_offset + params;
4604
4605 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004606 /* BB find exact max SMB PDU from sess structure BB */
4607 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004608 pSMB->SetupCount = 1;
4609 pSMB->Reserved3 = 0;
4610 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4611 byte_count = 1 /* pad */ + params + 12;
4612
4613 pSMB->DataCount = cpu_to_le16(12);
4614 pSMB->ParameterCount = cpu_to_le16(params);
4615 pSMB->TotalDataCount = pSMB->DataCount;
4616 pSMB->TotalParameterCount = pSMB->ParameterCount;
4617 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4618 pSMB->DataOffset = cpu_to_le16(offset);
4619
4620 /* Params. */
4621 pSMB->FileNum = 0;
4622 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4623
4624 /* Data. */
4625 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4626 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4627 pSMB->ClientUnixCap = cpu_to_le64(cap);
4628
4629 pSMB->hdr.smb_buf_length += byte_count;
4630 pSMB->ByteCount = cpu_to_le16(byte_count);
4631
4632 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4633 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4634 if (rc) {
4635 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4636 } else { /* decode response */
4637 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004638 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004639 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004640 }
4641 cifs_buf_release(pSMB);
4642
4643 if (rc == -EAGAIN)
4644 goto SETFSUnixRetry;
4645
4646 return rc;
4647}
4648
4649
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650
4651int
4652CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004653 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654{
4655/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4656 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4657 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4658 FILE_SYSTEM_POSIX_INFO *response_data;
4659 int rc = 0;
4660 int bytes_returned = 0;
4661 __u16 params, byte_count;
4662
4663 cFYI(1, ("In QFSPosixInfo"));
4664QFSPosixRetry:
4665 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4666 (void **) &pSMBr);
4667 if (rc)
4668 return rc;
4669
4670 params = 2; /* level */
4671 pSMB->TotalDataCount = 0;
4672 pSMB->DataCount = 0;
4673 pSMB->DataOffset = 0;
4674 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004675 /* BB find exact max SMB PDU from sess structure BB */
4676 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 pSMB->MaxSetupCount = 0;
4678 pSMB->Reserved = 0;
4679 pSMB->Flags = 0;
4680 pSMB->Timeout = 0;
4681 pSMB->Reserved2 = 0;
4682 byte_count = params + 1 /* pad */ ;
4683 pSMB->ParameterCount = cpu_to_le16(params);
4684 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004685 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4686 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 pSMB->SetupCount = 1;
4688 pSMB->Reserved3 = 0;
4689 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4690 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4691 pSMB->hdr.smb_buf_length += byte_count;
4692 pSMB->ByteCount = cpu_to_le16(byte_count);
4693
4694 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4695 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4696 if (rc) {
4697 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4698 } else { /* decode response */
4699 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4700
4701 if (rc || (pSMBr->ByteCount < 13)) {
4702 rc = -EIO; /* bad smb */
4703 } else {
4704 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4705 response_data =
4706 (FILE_SYSTEM_POSIX_INFO
4707 *) (((char *) &pSMBr->hdr.Protocol) +
4708 data_offset);
4709 FSData->f_bsize =
4710 le32_to_cpu(response_data->BlockSize);
4711 FSData->f_blocks =
4712 le64_to_cpu(response_data->TotalBlocks);
4713 FSData->f_bfree =
4714 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004715 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 FSData->f_bavail = FSData->f_bfree;
4717 } else {
4718 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004719 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 }
Steve French790fe572007-07-07 19:25:05 +00004721 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004723 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004724 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004726 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 }
4728 }
4729 cifs_buf_release(pSMB);
4730
4731 if (rc == -EAGAIN)
4732 goto QFSPosixRetry;
4733
4734 return rc;
4735}
4736
4737
Steve French50c2f752007-07-13 00:33:32 +00004738/* We can not use write of zero bytes trick to
4739 set file size due to need for large file support. Also note that
4740 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 routine which is only needed to work around a sharing violation bug
4742 in Samba which this routine can run into */
4743
4744int
4745CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004746 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004747 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748{
4749 struct smb_com_transaction2_spi_req *pSMB = NULL;
4750 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4751 struct file_end_of_file_info *parm_data;
4752 int name_len;
4753 int rc = 0;
4754 int bytes_returned = 0;
4755 __u16 params, byte_count, data_count, param_offset, offset;
4756
4757 cFYI(1, ("In SetEOF"));
4758SetEOFRetry:
4759 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4760 (void **) &pSMBr);
4761 if (rc)
4762 return rc;
4763
4764 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4765 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004766 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004767 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 name_len++; /* trailing null */
4769 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004770 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 name_len = strnlen(fileName, PATH_MAX);
4772 name_len++; /* trailing null */
4773 strncpy(pSMB->FileName, fileName, name_len);
4774 }
4775 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004776 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004778 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 pSMB->MaxSetupCount = 0;
4780 pSMB->Reserved = 0;
4781 pSMB->Flags = 0;
4782 pSMB->Timeout = 0;
4783 pSMB->Reserved2 = 0;
4784 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004785 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004787 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004788 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4789 pSMB->InformationLevel =
4790 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4791 else
4792 pSMB->InformationLevel =
4793 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4794 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4796 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004797 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 else
4799 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004800 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 }
4802
4803 parm_data =
4804 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4805 offset);
4806 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4807 pSMB->DataOffset = cpu_to_le16(offset);
4808 pSMB->SetupCount = 1;
4809 pSMB->Reserved3 = 0;
4810 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4811 byte_count = 3 /* pad */ + params + data_count;
4812 pSMB->DataCount = cpu_to_le16(data_count);
4813 pSMB->TotalDataCount = pSMB->DataCount;
4814 pSMB->ParameterCount = cpu_to_le16(params);
4815 pSMB->TotalParameterCount = pSMB->ParameterCount;
4816 pSMB->Reserved4 = 0;
4817 pSMB->hdr.smb_buf_length += byte_count;
4818 parm_data->FileSize = cpu_to_le64(size);
4819 pSMB->ByteCount = cpu_to_le16(byte_count);
4820 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4821 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004822 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824
4825 cifs_buf_release(pSMB);
4826
4827 if (rc == -EAGAIN)
4828 goto SetEOFRetry;
4829
4830 return rc;
4831}
4832
4833int
Steve French50c2f752007-07-13 00:33:32 +00004834CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004835 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836{
4837 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 char *data_offset;
4839 struct file_end_of_file_info *parm_data;
4840 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 __u16 params, param_offset, offset, byte_count, count;
4842
4843 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4844 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004845 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4846
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847 if (rc)
4848 return rc;
4849
4850 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4851 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004852
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 params = 6;
4854 pSMB->MaxSetupCount = 0;
4855 pSMB->Reserved = 0;
4856 pSMB->Flags = 0;
4857 pSMB->Timeout = 0;
4858 pSMB->Reserved2 = 0;
4859 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4860 offset = param_offset + params;
4861
Steve French50c2f752007-07-13 00:33:32 +00004862 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863
4864 count = sizeof(struct file_end_of_file_info);
4865 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004866 /* BB find exact max SMB PDU from sess structure BB */
4867 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 pSMB->SetupCount = 1;
4869 pSMB->Reserved3 = 0;
4870 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4871 byte_count = 3 /* pad */ + params + count;
4872 pSMB->DataCount = cpu_to_le16(count);
4873 pSMB->ParameterCount = cpu_to_le16(params);
4874 pSMB->TotalDataCount = pSMB->DataCount;
4875 pSMB->TotalParameterCount = pSMB->ParameterCount;
4876 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4877 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004878 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4879 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880 pSMB->DataOffset = cpu_to_le16(offset);
4881 parm_data->FileSize = cpu_to_le64(size);
4882 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004883 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4885 pSMB->InformationLevel =
4886 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4887 else
4888 pSMB->InformationLevel =
4889 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004890 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4892 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004893 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 else
4895 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004896 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 }
4898 pSMB->Reserved4 = 0;
4899 pSMB->hdr.smb_buf_length += byte_count;
4900 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004901 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 if (rc) {
4903 cFYI(1,
4904 ("Send error in SetFileInfo (SetFileSize) = %d",
4905 rc));
4906 }
4907
Steve French50c2f752007-07-13 00:33:32 +00004908 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 since file handle passed in no longer valid */
4910
4911 return rc;
4912}
4913
Steve French50c2f752007-07-13 00:33:32 +00004914/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 an open handle, rather than by pathname - this is awkward due to
4916 potential access conflicts on the open, but it is unavoidable for these
4917 old servers since the only other choice is to go from 100 nanosecond DCE
4918 time and resort to the original setpathinfo level which takes the ancient
4919 DOS time format with 2 second granularity */
4920int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004921CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4922 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923{
4924 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 char *data_offset;
4926 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 __u16 params, param_offset, offset, byte_count, count;
4928
4929 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004930 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4931
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 if (rc)
4933 return rc;
4934
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004935 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4936 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004937
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 params = 6;
4939 pSMB->MaxSetupCount = 0;
4940 pSMB->Reserved = 0;
4941 pSMB->Flags = 0;
4942 pSMB->Timeout = 0;
4943 pSMB->Reserved2 = 0;
4944 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4945 offset = param_offset + params;
4946
Steve French50c2f752007-07-13 00:33:32 +00004947 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948
Steve French26f57362007-08-30 22:09:15 +00004949 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004950 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004951 /* BB find max SMB PDU from sess */
4952 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 pSMB->SetupCount = 1;
4954 pSMB->Reserved3 = 0;
4955 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4956 byte_count = 3 /* pad */ + params + count;
4957 pSMB->DataCount = cpu_to_le16(count);
4958 pSMB->ParameterCount = cpu_to_le16(params);
4959 pSMB->TotalDataCount = pSMB->DataCount;
4960 pSMB->TotalParameterCount = pSMB->ParameterCount;
4961 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4962 pSMB->DataOffset = cpu_to_le16(offset);
4963 pSMB->Fid = fid;
4964 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4965 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4966 else
4967 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4968 pSMB->Reserved4 = 0;
4969 pSMB->hdr.smb_buf_length += byte_count;
4970 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004971 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004972 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004973 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004974 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975
Steve French50c2f752007-07-13 00:33:32 +00004976 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 since file handle passed in no longer valid */
4978
4979 return rc;
4980}
4981
Jeff Layton6d22f092008-09-23 11:48:35 -04004982int
4983CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4984 bool delete_file, __u16 fid, __u32 pid_of_opener)
4985{
4986 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4987 char *data_offset;
4988 int rc = 0;
4989 __u16 params, param_offset, offset, byte_count, count;
4990
4991 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4992 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4993
4994 if (rc)
4995 return rc;
4996
4997 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4998 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4999
5000 params = 6;
5001 pSMB->MaxSetupCount = 0;
5002 pSMB->Reserved = 0;
5003 pSMB->Flags = 0;
5004 pSMB->Timeout = 0;
5005 pSMB->Reserved2 = 0;
5006 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5007 offset = param_offset + params;
5008
5009 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5010
5011 count = 1;
5012 pSMB->MaxParameterCount = cpu_to_le16(2);
5013 /* BB find max SMB PDU from sess */
5014 pSMB->MaxDataCount = cpu_to_le16(1000);
5015 pSMB->SetupCount = 1;
5016 pSMB->Reserved3 = 0;
5017 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5018 byte_count = 3 /* pad */ + params + count;
5019 pSMB->DataCount = cpu_to_le16(count);
5020 pSMB->ParameterCount = cpu_to_le16(params);
5021 pSMB->TotalDataCount = pSMB->DataCount;
5022 pSMB->TotalParameterCount = pSMB->ParameterCount;
5023 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5024 pSMB->DataOffset = cpu_to_le16(offset);
5025 pSMB->Fid = fid;
5026 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5027 pSMB->Reserved4 = 0;
5028 pSMB->hdr.smb_buf_length += byte_count;
5029 pSMB->ByteCount = cpu_to_le16(byte_count);
5030 *data_offset = delete_file ? 1 : 0;
5031 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5032 if (rc)
5033 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
5034
5035 return rc;
5036}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005037
5038int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005039CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5040 const char *fileName, const FILE_BASIC_INFO *data,
5041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042{
5043 TRANSACTION2_SPI_REQ *pSMB = NULL;
5044 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5045 int name_len;
5046 int rc = 0;
5047 int bytes_returned = 0;
5048 char *data_offset;
5049 __u16 params, param_offset, offset, byte_count, count;
5050
5051 cFYI(1, ("In SetTimes"));
5052
5053SetTimesRetry:
5054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5055 (void **) &pSMBr);
5056 if (rc)
5057 return rc;
5058
5059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5060 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005061 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005062 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 name_len++; /* trailing null */
5064 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005065 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 name_len = strnlen(fileName, PATH_MAX);
5067 name_len++; /* trailing null */
5068 strncpy(pSMB->FileName, fileName, name_len);
5069 }
5070
5071 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005072 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005074 /* BB find max SMB PDU from sess structure BB */
5075 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 pSMB->MaxSetupCount = 0;
5077 pSMB->Reserved = 0;
5078 pSMB->Flags = 0;
5079 pSMB->Timeout = 0;
5080 pSMB->Reserved2 = 0;
5081 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005082 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 offset = param_offset + params;
5084 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5085 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5086 pSMB->DataOffset = cpu_to_le16(offset);
5087 pSMB->SetupCount = 1;
5088 pSMB->Reserved3 = 0;
5089 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5090 byte_count = 3 /* pad */ + params + count;
5091
5092 pSMB->DataCount = cpu_to_le16(count);
5093 pSMB->ParameterCount = cpu_to_le16(params);
5094 pSMB->TotalDataCount = pSMB->DataCount;
5095 pSMB->TotalParameterCount = pSMB->ParameterCount;
5096 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5097 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5098 else
5099 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5100 pSMB->Reserved4 = 0;
5101 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005102 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 pSMB->ByteCount = cpu_to_le16(byte_count);
5104 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5105 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005106 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005108
5109 cifs_buf_release(pSMB);
5110
5111 if (rc == -EAGAIN)
5112 goto SetTimesRetry;
5113
5114 return rc;
5115}
5116
5117/* Can not be used to set time stamps yet (due to old DOS time format) */
5118/* Can be used to set attributes */
5119#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5120 handling it anyway and NT4 was what we thought it would be needed for
5121 Do not delete it until we prove whether needed for Win9x though */
5122int
5123CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5124 __u16 dos_attrs, const struct nls_table *nls_codepage)
5125{
5126 SETATTR_REQ *pSMB = NULL;
5127 SETATTR_RSP *pSMBr = NULL;
5128 int rc = 0;
5129 int bytes_returned;
5130 int name_len;
5131
5132 cFYI(1, ("In SetAttrLegacy"));
5133
5134SetAttrLgcyRetry:
5135 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5136 (void **) &pSMBr);
5137 if (rc)
5138 return rc;
5139
5140 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5141 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005142 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143 PATH_MAX, nls_codepage);
5144 name_len++; /* trailing null */
5145 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005146 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 name_len = strnlen(fileName, PATH_MAX);
5148 name_len++; /* trailing null */
5149 strncpy(pSMB->fileName, fileName, name_len);
5150 }
5151 pSMB->attr = cpu_to_le16(dos_attrs);
5152 pSMB->BufferFormat = 0x04;
5153 pSMB->hdr.smb_buf_length += name_len + 1;
5154 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5155 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5156 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005157 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005158 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159
5160 cifs_buf_release(pSMB);
5161
5162 if (rc == -EAGAIN)
5163 goto SetAttrLgcyRetry;
5164
5165 return rc;
5166}
5167#endif /* temporarily unneeded SetAttr legacy function */
5168
Jeff Layton654cf142009-07-09 20:02:49 -04005169static void
5170cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5171 const struct cifs_unix_set_info_args *args)
5172{
5173 u64 mode = args->mode;
5174
5175 /*
5176 * Samba server ignores set of file size to zero due to bugs in some
5177 * older clients, but we should be precise - we use SetFileSize to
5178 * set file size and do not want to truncate file size to zero
5179 * accidently as happened on one Samba server beta by putting
5180 * zero instead of -1 here
5181 */
5182 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5183 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5184 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5185 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5186 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5187 data_offset->Uid = cpu_to_le64(args->uid);
5188 data_offset->Gid = cpu_to_le64(args->gid);
5189 /* better to leave device as zero when it is */
5190 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5191 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5192 data_offset->Permissions = cpu_to_le64(mode);
5193
5194 if (S_ISREG(mode))
5195 data_offset->Type = cpu_to_le32(UNIX_FILE);
5196 else if (S_ISDIR(mode))
5197 data_offset->Type = cpu_to_le32(UNIX_DIR);
5198 else if (S_ISLNK(mode))
5199 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5200 else if (S_ISCHR(mode))
5201 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5202 else if (S_ISBLK(mode))
5203 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5204 else if (S_ISFIFO(mode))
5205 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5206 else if (S_ISSOCK(mode))
5207 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5208}
5209
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005211CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5212 const struct cifs_unix_set_info_args *args,
5213 u16 fid, u32 pid_of_opener)
5214{
5215 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5216 FILE_UNIX_BASIC_INFO *data_offset;
5217 int rc = 0;
5218 u16 params, param_offset, offset, byte_count, count;
5219
5220 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5221 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5222
5223 if (rc)
5224 return rc;
5225
5226 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5227 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5228
5229 params = 6;
5230 pSMB->MaxSetupCount = 0;
5231 pSMB->Reserved = 0;
5232 pSMB->Flags = 0;
5233 pSMB->Timeout = 0;
5234 pSMB->Reserved2 = 0;
5235 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5236 offset = param_offset + params;
5237
5238 data_offset = (FILE_UNIX_BASIC_INFO *)
5239 ((char *)(&pSMB->hdr.Protocol) + offset);
5240 count = sizeof(FILE_UNIX_BASIC_INFO);
5241
5242 pSMB->MaxParameterCount = cpu_to_le16(2);
5243 /* BB find max SMB PDU from sess */
5244 pSMB->MaxDataCount = cpu_to_le16(1000);
5245 pSMB->SetupCount = 1;
5246 pSMB->Reserved3 = 0;
5247 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5248 byte_count = 3 /* pad */ + params + count;
5249 pSMB->DataCount = cpu_to_le16(count);
5250 pSMB->ParameterCount = cpu_to_le16(params);
5251 pSMB->TotalDataCount = pSMB->DataCount;
5252 pSMB->TotalParameterCount = pSMB->ParameterCount;
5253 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5254 pSMB->DataOffset = cpu_to_le16(offset);
5255 pSMB->Fid = fid;
5256 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5257 pSMB->Reserved4 = 0;
5258 pSMB->hdr.smb_buf_length += byte_count;
5259 pSMB->ByteCount = cpu_to_le16(byte_count);
5260
5261 cifs_fill_unix_set_info(data_offset, args);
5262
5263 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5264 if (rc)
5265 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5266
5267 /* Note: On -EAGAIN error only caller can retry on handle based calls
5268 since file handle passed in no longer valid */
5269
5270 return rc;
5271}
5272
5273int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005274CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5275 const struct cifs_unix_set_info_args *args,
5276 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277{
5278 TRANSACTION2_SPI_REQ *pSMB = NULL;
5279 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5280 int name_len;
5281 int rc = 0;
5282 int bytes_returned = 0;
5283 FILE_UNIX_BASIC_INFO *data_offset;
5284 __u16 params, param_offset, offset, count, byte_count;
5285
5286 cFYI(1, ("In SetUID/GID/Mode"));
5287setPermsRetry:
5288 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5289 (void **) &pSMBr);
5290 if (rc)
5291 return rc;
5292
5293 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5294 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005295 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005296 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 name_len++; /* trailing null */
5298 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005299 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 name_len = strnlen(fileName, PATH_MAX);
5301 name_len++; /* trailing null */
5302 strncpy(pSMB->FileName, fileName, name_len);
5303 }
5304
5305 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005306 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005308 /* BB find max SMB PDU from sess structure BB */
5309 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005310 pSMB->MaxSetupCount = 0;
5311 pSMB->Reserved = 0;
5312 pSMB->Flags = 0;
5313 pSMB->Timeout = 0;
5314 pSMB->Reserved2 = 0;
5315 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005316 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 offset = param_offset + params;
5318 data_offset =
5319 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5320 offset);
5321 memset(data_offset, 0, count);
5322 pSMB->DataOffset = cpu_to_le16(offset);
5323 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5324 pSMB->SetupCount = 1;
5325 pSMB->Reserved3 = 0;
5326 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5327 byte_count = 3 /* pad */ + params + count;
5328 pSMB->ParameterCount = cpu_to_le16(params);
5329 pSMB->DataCount = cpu_to_le16(count);
5330 pSMB->TotalParameterCount = pSMB->ParameterCount;
5331 pSMB->TotalDataCount = pSMB->DataCount;
5332 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5333 pSMB->Reserved4 = 0;
5334 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005335
Jeff Layton654cf142009-07-09 20:02:49 -04005336 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337
5338 pSMB->ByteCount = cpu_to_le16(byte_count);
5339 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5340 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005341 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005342 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343
Steve French0d817bc2008-05-22 02:02:03 +00005344 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 if (rc == -EAGAIN)
5346 goto setPermsRetry;
5347 return rc;
5348}
5349
Steve French50c2f752007-07-13 00:33:32 +00005350int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005351 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005352 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005353 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354{
5355 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005356 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5357 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005358 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 int bytes_returned;
5360
Steve French50c2f752007-07-13 00:33:32 +00005361 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005363 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005364 if (rc)
5365 return rc;
5366
5367 pSMB->TotalParameterCount = 0 ;
5368 pSMB->TotalDataCount = 0;
5369 pSMB->MaxParameterCount = cpu_to_le32(2);
5370 /* BB find exact data count max from sess structure BB */
5371 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005372/* BB VERIFY verify which is correct for above BB */
5373 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5374 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5375
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 pSMB->MaxSetupCount = 4;
5377 pSMB->Reserved = 0;
5378 pSMB->ParameterOffset = 0;
5379 pSMB->DataCount = 0;
5380 pSMB->DataOffset = 0;
5381 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5382 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5383 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005384 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5386 pSMB->Reserved2 = 0;
5387 pSMB->CompletionFilter = cpu_to_le32(filter);
5388 pSMB->Fid = netfid; /* file handle always le */
5389 pSMB->ByteCount = 0;
5390
5391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005392 (struct smb_hdr *)pSMBr, &bytes_returned,
5393 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005394 if (rc) {
5395 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005396 } else {
5397 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005398 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005399 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005400 sizeof(struct dir_notify_req),
5401 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005402 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005403 dnotify_req->Pid = pSMB->hdr.Pid;
5404 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5405 dnotify_req->Mid = pSMB->hdr.Mid;
5406 dnotify_req->Tid = pSMB->hdr.Tid;
5407 dnotify_req->Uid = pSMB->hdr.Uid;
5408 dnotify_req->netfid = netfid;
5409 dnotify_req->pfile = pfile;
5410 dnotify_req->filter = filter;
5411 dnotify_req->multishot = multishot;
5412 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005413 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005414 &GlobalDnotifyReqList);
5415 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005416 } else
Steve French47c786e2005-10-11 20:03:18 -07005417 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418 }
5419 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005420 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421}
Jeff Layton31c05192010-02-10 16:18:26 -05005422
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005424/*
5425 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5426 * function used by listxattr and getxattr type calls. When ea_name is set,
5427 * it looks for that attribute name and stuffs that value into the EAData
5428 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5429 * buffer. In both cases, the return value is either the length of the
5430 * resulting data or a negative error code. If EAData is a NULL pointer then
5431 * the data isn't copied to it, but the length is returned.
5432 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433ssize_t
5434CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005435 const unsigned char *searchName, const unsigned char *ea_name,
5436 char *EAData, size_t buf_size,
5437 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438{
5439 /* BB assumes one setup word */
5440 TRANSACTION2_QPI_REQ *pSMB = NULL;
5441 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5442 int rc = 0;
5443 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005444 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005445 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005446 struct fea *temp_fea;
5447 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005448 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005449 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450
5451 cFYI(1, ("In Query All EAs path %s", searchName));
5452QAllEAsRetry:
5453 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5454 (void **) &pSMBr);
5455 if (rc)
5456 return rc;
5457
5458 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005459 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005460 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005461 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005462 list_len++; /* trailing null */
5463 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005465 list_len = strnlen(searchName, PATH_MAX);
5466 list_len++; /* trailing null */
5467 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 }
5469
Jeff Layton6e462b92010-02-10 16:18:26 -05005470 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 pSMB->TotalDataCount = 0;
5472 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005473 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005474 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 pSMB->MaxSetupCount = 0;
5476 pSMB->Reserved = 0;
5477 pSMB->Flags = 0;
5478 pSMB->Timeout = 0;
5479 pSMB->Reserved2 = 0;
5480 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005481 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 pSMB->DataCount = 0;
5483 pSMB->DataOffset = 0;
5484 pSMB->SetupCount = 1;
5485 pSMB->Reserved3 = 0;
5486 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5487 byte_count = params + 1 /* pad */ ;
5488 pSMB->TotalParameterCount = cpu_to_le16(params);
5489 pSMB->ParameterCount = pSMB->TotalParameterCount;
5490 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5491 pSMB->Reserved4 = 0;
5492 pSMB->hdr.smb_buf_length += byte_count;
5493 pSMB->ByteCount = cpu_to_le16(byte_count);
5494
5495 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5496 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5497 if (rc) {
5498 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
Jeff Laytonf0d38682010-02-10 16:18:26 -05005499 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005501
5502
5503 /* BB also check enough total bytes returned */
5504 /* BB we need to improve the validity checking
5505 of these trans2 responses */
5506
5507 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5508 if (rc || (pSMBr->ByteCount < 4)) {
5509 rc = -EIO; /* bad smb */
5510 goto QAllEAsOut;
5511 }
5512
5513 /* check that length of list is not more than bcc */
5514 /* check that each entry does not go beyond length
5515 of list */
5516 /* check that each element of each entry does not
5517 go beyond end of list */
5518 /* validate_trans2_offsets() */
5519 /* BB check if start of smb + data_offset > &bcc+ bcc */
5520
5521 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5522 ea_response_data = (struct fealist *)
5523 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5524
Jeff Layton6e462b92010-02-10 16:18:26 -05005525 list_len = le32_to_cpu(ea_response_data->list_len);
5526 cFYI(1, ("ea length %d", list_len));
5527 if (list_len <= 8) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005528 cFYI(1, ("empty EA list returned from server"));
5529 goto QAllEAsOut;
5530 }
5531
Jeff Layton0cd126b2010-02-10 16:18:26 -05005532 /* make sure list_len doesn't go past end of SMB */
5533 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5534 if ((char *)ea_response_data + list_len > end_of_smb) {
5535 cFYI(1, ("EA list appears to go beyond SMB"));
5536 rc = -EIO;
5537 goto QAllEAsOut;
5538 }
5539
Jeff Laytonf0d38682010-02-10 16:18:26 -05005540 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005541 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005542 temp_fea = ea_response_data->list;
5543 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005544 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005545 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005546 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005547
Jeff Layton6e462b92010-02-10 16:18:26 -05005548 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005549 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005550 /* make sure we can read name_len and value_len */
5551 if (list_len < 0) {
5552 cFYI(1, ("EA entry goes beyond length of list"));
5553 rc = -EIO;
5554 goto QAllEAsOut;
5555 }
5556
5557 name_len = temp_fea->name_len;
5558 value_len = le16_to_cpu(temp_fea->value_len);
5559 list_len -= name_len + 1 + value_len;
5560 if (list_len < 0) {
5561 cFYI(1, ("EA entry goes beyond length of list"));
5562 rc = -EIO;
5563 goto QAllEAsOut;
5564 }
5565
Jeff Layton31c05192010-02-10 16:18:26 -05005566 if (ea_name) {
5567 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5568 temp_ptr += name_len + 1;
5569 rc = value_len;
5570 if (buf_size == 0)
5571 goto QAllEAsOut;
5572 if ((size_t)value_len > buf_size) {
5573 rc = -ERANGE;
5574 goto QAllEAsOut;
5575 }
5576 memcpy(EAData, temp_ptr, value_len);
5577 goto QAllEAsOut;
5578 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005579 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005580 /* account for prefix user. and trailing null */
5581 rc += (5 + 1 + name_len);
5582 if (rc < (int) buf_size) {
5583 memcpy(EAData, "user.", 5);
5584 EAData += 5;
5585 memcpy(EAData, temp_ptr, name_len);
5586 EAData += name_len;
5587 /* null terminate name */
5588 *EAData = 0;
5589 ++EAData;
5590 } else if (buf_size == 0) {
5591 /* skip copy - calc size only */
5592 } else {
5593 /* stop before overrun buffer */
5594 rc = -ERANGE;
5595 break;
5596 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005597 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005598 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005599 temp_fea = (struct fea *)temp_ptr;
5600 }
5601
Jeff Layton31c05192010-02-10 16:18:26 -05005602 /* didn't find the named attribute */
5603 if (ea_name)
5604 rc = -ENODATA;
5605
Jeff Laytonf0d38682010-02-10 16:18:26 -05005606QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005607 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005608 if (rc == -EAGAIN)
5609 goto QAllEAsRetry;
5610
5611 return (ssize_t)rc;
5612}
5613
Linus Torvalds1da177e2005-04-16 15:20:36 -07005614int
5615CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005616 const char *ea_name, const void *ea_value,
5617 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5618 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619{
5620 struct smb_com_transaction2_spi_req *pSMB = NULL;
5621 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5622 struct fealist *parm_data;
5623 int name_len;
5624 int rc = 0;
5625 int bytes_returned = 0;
5626 __u16 params, param_offset, byte_count, offset, count;
5627
5628 cFYI(1, ("In SetEA"));
5629SetEARetry:
5630 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5631 (void **) &pSMBr);
5632 if (rc)
5633 return rc;
5634
5635 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5636 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005637 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005638 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 name_len++; /* trailing null */
5640 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005641 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 name_len = strnlen(fileName, PATH_MAX);
5643 name_len++; /* trailing null */
5644 strncpy(pSMB->FileName, fileName, name_len);
5645 }
5646
5647 params = 6 + name_len;
5648
5649 /* done calculating parms using name_len of file name,
5650 now use name_len to calculate length of ea name
5651 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005652 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 name_len = 0;
5654 else
Steve French50c2f752007-07-13 00:33:32 +00005655 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005657 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005659 /* BB find max SMB PDU from sess */
5660 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 pSMB->MaxSetupCount = 0;
5662 pSMB->Reserved = 0;
5663 pSMB->Flags = 0;
5664 pSMB->Timeout = 0;
5665 pSMB->Reserved2 = 0;
5666 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005667 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 offset = param_offset + params;
5669 pSMB->InformationLevel =
5670 cpu_to_le16(SMB_SET_FILE_EA);
5671
5672 parm_data =
5673 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5674 offset);
5675 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5676 pSMB->DataOffset = cpu_to_le16(offset);
5677 pSMB->SetupCount = 1;
5678 pSMB->Reserved3 = 0;
5679 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5680 byte_count = 3 /* pad */ + params + count;
5681 pSMB->DataCount = cpu_to_le16(count);
5682 parm_data->list_len = cpu_to_le32(count);
5683 parm_data->list[0].EA_flags = 0;
5684 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005685 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005686 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005687 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005688 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 parm_data->list[0].name[name_len] = 0;
5690 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5691 /* caller ensures that ea_value_len is less than 64K but
5692 we need to ensure that it fits within the smb */
5693
Steve French50c2f752007-07-13 00:33:32 +00005694 /*BB add length check to see if it would fit in
5695 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005696 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5697 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005698 memcpy(parm_data->list[0].name+name_len+1,
5699 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700
5701 pSMB->TotalDataCount = pSMB->DataCount;
5702 pSMB->ParameterCount = cpu_to_le16(params);
5703 pSMB->TotalParameterCount = pSMB->ParameterCount;
5704 pSMB->Reserved4 = 0;
5705 pSMB->hdr.smb_buf_length += byte_count;
5706 pSMB->ByteCount = cpu_to_le16(byte_count);
5707 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5708 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005709 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005710 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711
5712 cifs_buf_release(pSMB);
5713
5714 if (rc == -EAGAIN)
5715 goto SetEARetry;
5716
5717 return rc;
5718}
5719
5720#endif