blob: e1f90a3a0162853fa1ad38df68d8e601c918fc68 [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);
1521 }
1522
1523 cifs_buf_release(pSMB);
1524
Steve French50c2f752007-07-13 00:33:32 +00001525 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 since file handle passed in no longer valid */
1527
1528 return rc;
1529}
1530
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001531int
1532CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001534 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1535 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
1537 int rc = -EACCES;
1538 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001539 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001540 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001541 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001543 *nbytes = 0;
1544
Steve French790fe572007-07-07 19:25:05 +00001545 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001546
Steve French4c3130e2008-12-09 00:28:16 +00001547 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001548 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001549 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001550 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001551 if ((offset >> 32) > 0) {
1552 /* can not handle big offset for old srv */
1553 return -EIO;
1554 }
1555 }
Steve French8cc64c62005-10-03 13:49:43 -07001556 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 if (rc)
1558 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 /* tcon and ses pointer are checked in smb_init */
1560 if (tcon->ses->server == NULL)
1561 return -ECONNABORTED;
1562
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001563 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 pSMB->Fid = netfid;
1565 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001566 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001567 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 pSMB->Reserved = 0xFFFFFFFF;
1569 pSMB->WriteMode = 0;
1570 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001571
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001573 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
Steve French3e844692005-10-03 13:37:24 -07001575 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1576 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001577 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001578 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001579 pSMB->hdr.smb_buf_length += count+1;
1580 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001581 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1582 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001583 pSMB->ByteCount = cpu_to_le16(count + 1);
1584 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001585 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001586 (struct smb_com_writex_req *)pSMB;
1587 pSMBW->ByteCount = cpu_to_le16(count + 5);
1588 }
Steve French3e844692005-10-03 13:37:24 -07001589 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001590 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001591 iov[0].iov_len = smb_hdr_len + 4;
1592 else /* wct == 12 pad bigger by four bytes */
1593 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001594
Steve French3e844692005-10-03 13:37:24 -07001595
Steve Frenchec637e32005-12-12 20:53:18 -08001596 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001597 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001598 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001600 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001601 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001602 /* presumably this can not happen, but best to be safe */
1603 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001604 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001605 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001606 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1607 *nbytes = (*nbytes) << 16;
1608 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001609 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610
Steve French4b8f9302006-02-26 16:41:18 +00001611/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001612 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001613 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001614 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001615 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616
Steve French50c2f752007-07-13 00:33:32 +00001617 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 since file handle passed in no longer valid */
1619
1620 return rc;
1621}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001622
1623
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624int
1625CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1626 const __u16 smb_file_id, const __u64 len,
1627 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001628 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629{
1630 int rc = 0;
1631 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001632/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 int bytes_returned;
1634 int timeout = 0;
1635 __u16 count;
1636
Steve French4b18f2a2008-04-29 00:06:05 +00001637 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001638 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1639
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 if (rc)
1641 return rc;
1642
Steve French790fe572007-07-07 19:25:05 +00001643 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001644 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001646 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001647 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1649 } else {
1650 pSMB->Timeout = 0;
1651 }
1652
1653 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1654 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1655 pSMB->LockType = lockType;
1656 pSMB->AndXCommand = 0xFF; /* none */
1657 pSMB->Fid = smb_file_id; /* netfid stays le */
1658
Steve French790fe572007-07-07 19:25:05 +00001659 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1661 /* BB where to store pid high? */
1662 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1663 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1664 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1665 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1666 count = sizeof(LOCKING_ANDX_RANGE);
1667 } else {
1668 /* oplock break */
1669 count = 0;
1670 }
1671 pSMB->hdr.smb_buf_length += count;
1672 pSMB->ByteCount = cpu_to_le16(count);
1673
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001674 if (waitFlag) {
1675 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001676 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001677 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001678 } else {
Steve French133672e2007-11-13 22:41:37 +00001679 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1680 timeout);
1681 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001682 }
Steve Frencha4544342005-08-24 13:59:35 -07001683 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001684 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
Steve French50c2f752007-07-13 00:33:32 +00001687 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 since file handle passed in no longer valid */
1689 return rc;
1690}
1691
1692int
Steve French08547b02006-02-28 22:39:25 +00001693CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1694 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001695 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001696 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001697{
1698 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1699 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001700 struct cifs_posix_lock *parm_data;
1701 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001702 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001703 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001704 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001705 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001706 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001707
1708 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001709
Steve French790fe572007-07-07 19:25:05 +00001710 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001711 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001712
Steve French08547b02006-02-28 22:39:25 +00001713 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1714
1715 if (rc)
1716 return rc;
1717
1718 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1719
Steve French50c2f752007-07-13 00:33:32 +00001720 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001721 pSMB->MaxSetupCount = 0;
1722 pSMB->Reserved = 0;
1723 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001724 pSMB->Reserved2 = 0;
1725 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1726 offset = param_offset + params;
1727
Steve French08547b02006-02-28 22:39:25 +00001728 count = sizeof(struct cifs_posix_lock);
1729 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001730 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001731 pSMB->SetupCount = 1;
1732 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001733 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001734 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1735 else
1736 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1737 byte_count = 3 /* pad */ + params + count;
1738 pSMB->DataCount = cpu_to_le16(count);
1739 pSMB->ParameterCount = cpu_to_le16(params);
1740 pSMB->TotalDataCount = pSMB->DataCount;
1741 pSMB->TotalParameterCount = pSMB->ParameterCount;
1742 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001743 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001744 (((char *) &pSMB->hdr.Protocol) + offset);
1745
1746 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001747 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001748 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001749 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001750 pSMB->Timeout = cpu_to_le32(-1);
1751 } else
1752 pSMB->Timeout = 0;
1753
Steve French08547b02006-02-28 22:39:25 +00001754 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001755 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001756 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001757
1758 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001759 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001760 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1761 pSMB->Reserved4 = 0;
1762 pSMB->hdr.smb_buf_length += byte_count;
1763 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001764 if (waitFlag) {
1765 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1766 (struct smb_hdr *) pSMBr, &bytes_returned);
1767 } else {
Steve French133672e2007-11-13 22:41:37 +00001768 iov[0].iov_base = (char *)pSMB;
1769 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1770 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1771 &resp_buf_type, timeout);
1772 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1773 not try to free it twice below on exit */
1774 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001775 }
1776
Steve French08547b02006-02-28 22:39:25 +00001777 if (rc) {
1778 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001779 } else if (get_flag) {
1780 /* lock structure can be returned on get */
1781 __u16 data_offset;
1782 __u16 data_count;
1783 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001784
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001785 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1786 rc = -EIO; /* bad smb */
1787 goto plk_err_exit;
1788 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001789 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1790 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001791 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001792 rc = -EIO;
1793 goto plk_err_exit;
1794 }
1795 parm_data = (struct cifs_posix_lock *)
1796 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001797 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001798 pLockData->fl_type = F_UNLCK;
1799 }
Steve French50c2f752007-07-13 00:33:32 +00001800
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001801plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001802 if (pSMB)
1803 cifs_small_buf_release(pSMB);
1804
Steve French133672e2007-11-13 22:41:37 +00001805 if (resp_buf_type == CIFS_SMALL_BUFFER)
1806 cifs_small_buf_release(iov[0].iov_base);
1807 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1808 cifs_buf_release(iov[0].iov_base);
1809
Steve French08547b02006-02-28 22:39:25 +00001810 /* Note: On -EAGAIN error only caller can retry on handle based calls
1811 since file handle passed in no longer valid */
1812
1813 return rc;
1814}
1815
1816
1817int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1819{
1820 int rc = 0;
1821 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 cFYI(1, ("In CIFSSMBClose"));
1823
1824/* do not retry on dead session on close */
1825 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001826 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 return 0;
1828 if (rc)
1829 return rc;
1830
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001832 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001834 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001835 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001837 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 /* EINTR is expected when user ctl-c to kill app */
1839 cERROR(1, ("Send error in Close = %d", rc));
1840 }
1841 }
1842
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001844 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 rc = 0;
1846
1847 return rc;
1848}
1849
1850int
Steve Frenchb298f222009-02-21 21:17:43 +00001851CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1852{
1853 int rc = 0;
1854 FLUSH_REQ *pSMB = NULL;
1855 cFYI(1, ("In CIFSSMBFlush"));
1856
1857 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1858 if (rc)
1859 return rc;
1860
1861 pSMB->FileID = (__u16) smb_file_id;
1862 pSMB->ByteCount = 0;
1863 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1864 cifs_stats_inc(&tcon->num_flushes);
1865 if (rc)
1866 cERROR(1, ("Send error in Flush = %d", rc));
1867
1868 return rc;
1869}
1870
1871int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1873 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001874 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875{
1876 int rc = 0;
1877 RENAME_REQ *pSMB = NULL;
1878 RENAME_RSP *pSMBr = NULL;
1879 int bytes_returned;
1880 int name_len, name_len2;
1881 __u16 count;
1882
1883 cFYI(1, ("In CIFSSMBRename"));
1884renameRetry:
1885 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1886 (void **) &pSMBr);
1887 if (rc)
1888 return rc;
1889
1890 pSMB->BufferFormat = 0x04;
1891 pSMB->SearchAttributes =
1892 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1893 ATTR_DIRECTORY);
1894
1895 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1896 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001897 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001898 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 name_len++; /* trailing null */
1900 name_len *= 2;
1901 pSMB->OldFileName[name_len] = 0x04; /* pad */
1902 /* protocol requires ASCII signature byte on Unicode string */
1903 pSMB->OldFileName[name_len + 1] = 0x00;
1904 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001905 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001906 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1908 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001909 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 name_len = strnlen(fromName, PATH_MAX);
1911 name_len++; /* trailing null */
1912 strncpy(pSMB->OldFileName, fromName, name_len);
1913 name_len2 = strnlen(toName, PATH_MAX);
1914 name_len2++; /* trailing null */
1915 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1916 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1917 name_len2++; /* trailing null */
1918 name_len2++; /* signature byte */
1919 }
1920
1921 count = 1 /* 1st signature byte */ + name_len + name_len2;
1922 pSMB->hdr.smb_buf_length += count;
1923 pSMB->ByteCount = cpu_to_le16(count);
1924
1925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1926 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001927 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001928 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 cifs_buf_release(pSMB);
1932
1933 if (rc == -EAGAIN)
1934 goto renameRetry;
1935
1936 return rc;
1937}
1938
Steve French50c2f752007-07-13 00:33:32 +00001939int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001940 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001941 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942{
1943 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1944 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001945 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 char *data_offset;
1947 char dummy_string[30];
1948 int rc = 0;
1949 int bytes_returned = 0;
1950 int len_of_str;
1951 __u16 params, param_offset, offset, count, byte_count;
1952
1953 cFYI(1, ("Rename to File by handle"));
1954 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1955 (void **) &pSMBr);
1956 if (rc)
1957 return rc;
1958
1959 params = 6;
1960 pSMB->MaxSetupCount = 0;
1961 pSMB->Reserved = 0;
1962 pSMB->Flags = 0;
1963 pSMB->Timeout = 0;
1964 pSMB->Reserved2 = 0;
1965 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1966 offset = param_offset + params;
1967
1968 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1969 rename_info = (struct set_file_rename *) data_offset;
1970 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001971 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 pSMB->SetupCount = 1;
1973 pSMB->Reserved3 = 0;
1974 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1975 byte_count = 3 /* pad */ + params;
1976 pSMB->ParameterCount = cpu_to_le16(params);
1977 pSMB->TotalParameterCount = pSMB->ParameterCount;
1978 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1979 pSMB->DataOffset = cpu_to_le16(offset);
1980 /* construct random name ".cifs_tmp<inodenum><mid>" */
1981 rename_info->overwrite = cpu_to_le32(1);
1982 rename_info->root_fid = 0;
1983 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00001984 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001985 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
1986 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001987 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001989 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00001990 target_name, PATH_MAX, nls_codepage,
1991 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 }
1993 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04001994 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 byte_count += count;
1996 pSMB->DataCount = cpu_to_le16(count);
1997 pSMB->TotalDataCount = pSMB->DataCount;
1998 pSMB->Fid = netfid;
1999 pSMB->InformationLevel =
2000 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2001 pSMB->Reserved4 = 0;
2002 pSMB->hdr.smb_buf_length += byte_count;
2003 pSMB->ByteCount = cpu_to_le16(byte_count);
2004 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002006 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002007 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002008 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002009
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 cifs_buf_release(pSMB);
2011
2012 /* Note: On -EAGAIN error only caller can retry on handle based calls
2013 since file handle passed in no longer valid */
2014
2015 return rc;
2016}
2017
2018int
Steve French50c2f752007-07-13 00:33:32 +00002019CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2020 const __u16 target_tid, const char *toName, const int flags,
2021 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022{
2023 int rc = 0;
2024 COPY_REQ *pSMB = NULL;
2025 COPY_RSP *pSMBr = NULL;
2026 int bytes_returned;
2027 int name_len, name_len2;
2028 __u16 count;
2029
2030 cFYI(1, ("In CIFSSMBCopy"));
2031copyRetry:
2032 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2033 (void **) &pSMBr);
2034 if (rc)
2035 return rc;
2036
2037 pSMB->BufferFormat = 0x04;
2038 pSMB->Tid2 = target_tid;
2039
2040 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2041
2042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002043 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002044 fromName, PATH_MAX, nls_codepage,
2045 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 name_len++; /* trailing null */
2047 name_len *= 2;
2048 pSMB->OldFileName[name_len] = 0x04; /* pad */
2049 /* protocol requires ASCII signature byte on Unicode string */
2050 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002051 name_len2 =
2052 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002053 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2055 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002056 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 name_len = strnlen(fromName, PATH_MAX);
2058 name_len++; /* trailing null */
2059 strncpy(pSMB->OldFileName, fromName, name_len);
2060 name_len2 = strnlen(toName, PATH_MAX);
2061 name_len2++; /* trailing null */
2062 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2063 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2064 name_len2++; /* trailing null */
2065 name_len2++; /* signature byte */
2066 }
2067
2068 count = 1 /* 1st signature byte */ + name_len + name_len2;
2069 pSMB->hdr.smb_buf_length += count;
2070 pSMB->ByteCount = cpu_to_le16(count);
2071
2072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2074 if (rc) {
2075 cFYI(1, ("Send error in copy = %d with %d files copied",
2076 rc, le16_to_cpu(pSMBr->CopyCount)));
2077 }
Steve French0d817bc2008-05-22 02:02:03 +00002078 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079
2080 if (rc == -EAGAIN)
2081 goto copyRetry;
2082
2083 return rc;
2084}
2085
2086int
2087CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2088 const char *fromName, const char *toName,
2089 const struct nls_table *nls_codepage)
2090{
2091 TRANSACTION2_SPI_REQ *pSMB = NULL;
2092 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2093 char *data_offset;
2094 int name_len;
2095 int name_len_target;
2096 int rc = 0;
2097 int bytes_returned = 0;
2098 __u16 params, param_offset, offset, byte_count;
2099
2100 cFYI(1, ("In Symlink Unix style"));
2101createSymLinkRetry:
2102 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2103 (void **) &pSMBr);
2104 if (rc)
2105 return rc;
2106
2107 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2108 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002109 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 /* find define for this maxpathcomponent */
2111 , nls_codepage);
2112 name_len++; /* trailing null */
2113 name_len *= 2;
2114
Steve French50c2f752007-07-13 00:33:32 +00002115 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 name_len = strnlen(fromName, PATH_MAX);
2117 name_len++; /* trailing null */
2118 strncpy(pSMB->FileName, fromName, name_len);
2119 }
2120 params = 6 + name_len;
2121 pSMB->MaxSetupCount = 0;
2122 pSMB->Reserved = 0;
2123 pSMB->Flags = 0;
2124 pSMB->Timeout = 0;
2125 pSMB->Reserved2 = 0;
2126 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002127 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 offset = param_offset + params;
2129
2130 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2131 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2132 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002133 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 /* find define for this maxpathcomponent */
2135 , nls_codepage);
2136 name_len_target++; /* trailing null */
2137 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002138 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 name_len_target = strnlen(toName, PATH_MAX);
2140 name_len_target++; /* trailing null */
2141 strncpy(data_offset, toName, name_len_target);
2142 }
2143
2144 pSMB->MaxParameterCount = cpu_to_le16(2);
2145 /* BB find exact max on data count below from sess */
2146 pSMB->MaxDataCount = cpu_to_le16(1000);
2147 pSMB->SetupCount = 1;
2148 pSMB->Reserved3 = 0;
2149 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2150 byte_count = 3 /* pad */ + params + name_len_target;
2151 pSMB->DataCount = cpu_to_le16(name_len_target);
2152 pSMB->ParameterCount = cpu_to_le16(params);
2153 pSMB->TotalDataCount = pSMB->DataCount;
2154 pSMB->TotalParameterCount = pSMB->ParameterCount;
2155 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2156 pSMB->DataOffset = cpu_to_le16(offset);
2157 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2158 pSMB->Reserved4 = 0;
2159 pSMB->hdr.smb_buf_length += byte_count;
2160 pSMB->ByteCount = cpu_to_le16(byte_count);
2161 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002163 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002164 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002165 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
Steve French0d817bc2008-05-22 02:02:03 +00002167 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
2169 if (rc == -EAGAIN)
2170 goto createSymLinkRetry;
2171
2172 return rc;
2173}
2174
2175int
2176CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2177 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002178 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179{
2180 TRANSACTION2_SPI_REQ *pSMB = NULL;
2181 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2182 char *data_offset;
2183 int name_len;
2184 int name_len_target;
2185 int rc = 0;
2186 int bytes_returned = 0;
2187 __u16 params, param_offset, offset, byte_count;
2188
2189 cFYI(1, ("In Create Hard link Unix style"));
2190createHardLinkRetry:
2191 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2192 (void **) &pSMBr);
2193 if (rc)
2194 return rc;
2195
2196 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002197 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002198 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 name_len++; /* trailing null */
2200 name_len *= 2;
2201
Steve French50c2f752007-07-13 00:33:32 +00002202 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 name_len = strnlen(toName, PATH_MAX);
2204 name_len++; /* trailing null */
2205 strncpy(pSMB->FileName, toName, name_len);
2206 }
2207 params = 6 + name_len;
2208 pSMB->MaxSetupCount = 0;
2209 pSMB->Reserved = 0;
2210 pSMB->Flags = 0;
2211 pSMB->Timeout = 0;
2212 pSMB->Reserved2 = 0;
2213 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002214 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 offset = param_offset + params;
2216
2217 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2218 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2219 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002220 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002221 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 name_len_target++; /* trailing null */
2223 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002224 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 name_len_target = strnlen(fromName, PATH_MAX);
2226 name_len_target++; /* trailing null */
2227 strncpy(data_offset, fromName, name_len_target);
2228 }
2229
2230 pSMB->MaxParameterCount = cpu_to_le16(2);
2231 /* BB find exact max on data count below from sess*/
2232 pSMB->MaxDataCount = cpu_to_le16(1000);
2233 pSMB->SetupCount = 1;
2234 pSMB->Reserved3 = 0;
2235 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2236 byte_count = 3 /* pad */ + params + name_len_target;
2237 pSMB->ParameterCount = cpu_to_le16(params);
2238 pSMB->TotalParameterCount = pSMB->ParameterCount;
2239 pSMB->DataCount = cpu_to_le16(name_len_target);
2240 pSMB->TotalDataCount = pSMB->DataCount;
2241 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2242 pSMB->DataOffset = cpu_to_le16(offset);
2243 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2244 pSMB->Reserved4 = 0;
2245 pSMB->hdr.smb_buf_length += byte_count;
2246 pSMB->ByteCount = cpu_to_le16(byte_count);
2247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2248 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002249 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002250 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
2253 cifs_buf_release(pSMB);
2254 if (rc == -EAGAIN)
2255 goto createHardLinkRetry;
2256
2257 return rc;
2258}
2259
2260int
2261CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2262 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002263 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264{
2265 int rc = 0;
2266 NT_RENAME_REQ *pSMB = NULL;
2267 RENAME_RSP *pSMBr = NULL;
2268 int bytes_returned;
2269 int name_len, name_len2;
2270 __u16 count;
2271
2272 cFYI(1, ("In CIFSCreateHardLink"));
2273winCreateHardLinkRetry:
2274
2275 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2276 (void **) &pSMBr);
2277 if (rc)
2278 return rc;
2279
2280 pSMB->SearchAttributes =
2281 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2282 ATTR_DIRECTORY);
2283 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2284 pSMB->ClusterCount = 0;
2285
2286 pSMB->BufferFormat = 0x04;
2287
2288 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2289 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002290 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002291 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 name_len++; /* trailing null */
2293 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002294
2295 /* protocol specifies ASCII buffer format (0x04) for unicode */
2296 pSMB->OldFileName[name_len] = 0x04;
2297 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002299 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002300 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2302 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002303 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 name_len = strnlen(fromName, PATH_MAX);
2305 name_len++; /* trailing null */
2306 strncpy(pSMB->OldFileName, fromName, name_len);
2307 name_len2 = strnlen(toName, PATH_MAX);
2308 name_len2++; /* trailing null */
2309 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2310 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2311 name_len2++; /* trailing null */
2312 name_len2++; /* signature byte */
2313 }
2314
2315 count = 1 /* string type byte */ + name_len + name_len2;
2316 pSMB->hdr.smb_buf_length += count;
2317 pSMB->ByteCount = cpu_to_le16(count);
2318
2319 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2320 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002321 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002322 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002324
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325 cifs_buf_release(pSMB);
2326 if (rc == -EAGAIN)
2327 goto winCreateHardLinkRetry;
2328
2329 return rc;
2330}
2331
2332int
2333CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002334 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335 const struct nls_table *nls_codepage)
2336{
2337/* SMB_QUERY_FILE_UNIX_LINK */
2338 TRANSACTION2_QPI_REQ *pSMB = NULL;
2339 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2340 int rc = 0;
2341 int bytes_returned;
2342 int name_len;
2343 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002344 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
2346 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2347
2348querySymLinkRetry:
2349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2350 (void **) &pSMBr);
2351 if (rc)
2352 return rc;
2353
2354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2355 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002356 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2357 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 name_len++; /* trailing null */
2359 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002360 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 name_len = strnlen(searchName, PATH_MAX);
2362 name_len++; /* trailing null */
2363 strncpy(pSMB->FileName, searchName, name_len);
2364 }
2365
2366 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2367 pSMB->TotalDataCount = 0;
2368 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002369 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 pSMB->MaxSetupCount = 0;
2371 pSMB->Reserved = 0;
2372 pSMB->Flags = 0;
2373 pSMB->Timeout = 0;
2374 pSMB->Reserved2 = 0;
2375 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002376 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 pSMB->DataCount = 0;
2378 pSMB->DataOffset = 0;
2379 pSMB->SetupCount = 1;
2380 pSMB->Reserved3 = 0;
2381 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2382 byte_count = params + 1 /* pad */ ;
2383 pSMB->TotalParameterCount = cpu_to_le16(params);
2384 pSMB->ParameterCount = pSMB->TotalParameterCount;
2385 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2386 pSMB->Reserved4 = 0;
2387 pSMB->hdr.smb_buf_length += byte_count;
2388 pSMB->ByteCount = cpu_to_le16(byte_count);
2389
2390 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2391 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2392 if (rc) {
2393 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2394 } else {
2395 /* decode response */
2396
2397 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002399 if (rc || (pSMBr->ByteCount < 2))
2400 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002402 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002403 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404
Jeff Layton460b9692009-04-30 07:17:56 -04002405 data_start = ((char *) &pSMBr->hdr.Protocol) +
2406 le16_to_cpu(pSMBr->t2.DataOffset);
2407
Steve French0e0d2cf2009-05-01 05:27:32 +00002408 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2409 is_unicode = true;
2410 else
2411 is_unicode = false;
2412
Steve French737b7582005-04-28 22:41:06 -07002413 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002414 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002415 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002416 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002417 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 }
2419 }
2420 cifs_buf_release(pSMB);
2421 if (rc == -EAGAIN)
2422 goto querySymLinkRetry;
2423 return rc;
2424}
2425
Parag Warudkarc9489772007-10-23 18:09:48 +00002426#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002427/* Initialize NT TRANSACT SMB into small smb request buffer.
2428 This assumes that all NT TRANSACTS that we init here have
2429 total parm and data under about 400 bytes (to fit in small cifs
2430 buffer size), which is the case so far, it easily fits. NB:
2431 Setup words themselves and ByteCount
2432 MaxSetupCount (size of returned setup area) and
2433 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002434static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002435smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002436 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002437 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002438{
2439 int rc;
2440 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002441 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002442
2443 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2444 (void **)&pSMB);
2445 if (rc)
2446 return rc;
2447 *ret_buf = (void *)pSMB;
2448 pSMB->Reserved = 0;
2449 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2450 pSMB->TotalDataCount = 0;
2451 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2452 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2453 pSMB->ParameterCount = pSMB->TotalParameterCount;
2454 pSMB->DataCount = pSMB->TotalDataCount;
2455 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2456 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2457 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2458 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2459 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2460 pSMB->SubCommand = cpu_to_le16(sub_command);
2461 return 0;
2462}
2463
2464static int
Steve French50c2f752007-07-13 00:33:32 +00002465validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002466 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002467{
Steve French50c2f752007-07-13 00:33:32 +00002468 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002469 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002470 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002471
Steve French630f3f02007-10-25 21:17:17 +00002472 *pdatalen = 0;
2473 *pparmlen = 0;
2474
Steve French790fe572007-07-07 19:25:05 +00002475 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002476 return -EINVAL;
2477
2478 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2479
2480 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002481 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002482 (char *)&pSMBr->ByteCount;
2483
Steve French0a4b92c2006-01-12 15:44:21 -08002484 data_offset = le32_to_cpu(pSMBr->DataOffset);
2485 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002486 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002487 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2488
2489 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2490 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2491
2492 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002493 if (*ppparm > end_of_smb) {
2494 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002495 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002496 } else if (parm_count + *ppparm > end_of_smb) {
2497 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002498 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002499 } else if (*ppdata > end_of_smb) {
2500 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002501 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002502 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002503 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002504 *ppdata, data_count, (data_count + *ppdata),
2505 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002506 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002507 } else if (parm_count + data_count > pSMBr->ByteCount) {
2508 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002509 return -EINVAL;
2510 }
Steve French630f3f02007-10-25 21:17:17 +00002511 *pdatalen = data_count;
2512 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002513 return 0;
2514}
2515
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516int
2517CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2518 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002519 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 const struct nls_table *nls_codepage)
2521{
2522 int rc = 0;
2523 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002524 struct smb_com_transaction_ioctl_req *pSMB;
2525 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526
2527 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2528 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2529 (void **) &pSMBr);
2530 if (rc)
2531 return rc;
2532
2533 pSMB->TotalParameterCount = 0 ;
2534 pSMB->TotalDataCount = 0;
2535 pSMB->MaxParameterCount = cpu_to_le32(2);
2536 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002537 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2538 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 pSMB->MaxSetupCount = 4;
2540 pSMB->Reserved = 0;
2541 pSMB->ParameterOffset = 0;
2542 pSMB->DataCount = 0;
2543 pSMB->DataOffset = 0;
2544 pSMB->SetupCount = 4;
2545 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2546 pSMB->ParameterCount = pSMB->TotalParameterCount;
2547 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2548 pSMB->IsFsctl = 1; /* FSCTL */
2549 pSMB->IsRootFlag = 0;
2550 pSMB->Fid = fid; /* file handle always le */
2551 pSMB->ByteCount = 0;
2552
2553 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2554 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2555 if (rc) {
2556 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2557 } else { /* decode response */
2558 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2559 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002560 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 /* BB also check enough total bytes returned */
2562 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002563 goto qreparse_out;
2564 }
2565 if (data_count && (data_count < 2048)) {
2566 char *end_of_smb = 2 /* sizeof byte count */ +
2567 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568
Steve Frenchafe48c32009-05-02 05:25:46 +00002569 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002570 (struct reparse_data *)
2571 ((char *)&pSMBr->hdr.Protocol
2572 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002573 if ((char *)reparse_buf >= end_of_smb) {
2574 rc = -EIO;
2575 goto qreparse_out;
2576 }
2577 if ((reparse_buf->LinkNamesBuf +
2578 reparse_buf->TargetNameOffset +
2579 reparse_buf->TargetNameLen) > end_of_smb) {
2580 cFYI(1, ("reparse buf beyond SMB"));
2581 rc = -EIO;
2582 goto qreparse_out;
2583 }
Steve French50c2f752007-07-13 00:33:32 +00002584
Steve Frenchafe48c32009-05-02 05:25:46 +00002585 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2586 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002587 (reparse_buf->LinkNamesBuf +
2588 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002589 buflen,
2590 reparse_buf->TargetNameLen,
2591 nls_codepage, 0);
2592 } else { /* ASCII names */
2593 strncpy(symlinkinfo,
2594 reparse_buf->LinkNamesBuf +
2595 reparse_buf->TargetNameOffset,
2596 min_t(const int, buflen,
2597 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002599 } else {
2600 rc = -EIO;
2601 cFYI(1, ("Invalid return data count on "
2602 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002604 symlinkinfo[buflen] = 0; /* just in case so the caller
2605 does not go off the end of the buffer */
2606 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 }
Steve French989c7e52009-05-02 05:32:20 +00002608
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002610 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612 /* Note: On -EAGAIN error only caller can retry on handle based calls
2613 since file handle passed in no longer valid */
2614
2615 return rc;
2616}
Steve Frenchafe48c32009-05-02 05:25:46 +00002617#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618
2619#ifdef CONFIG_CIFS_POSIX
2620
2621/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002622static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2623 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624{
2625 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002626 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2627 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2628 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2630
2631 return;
2632}
2633
2634/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002635static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2636 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637{
2638 int size = 0;
2639 int i;
2640 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002641 struct cifs_posix_ace *pACE;
2642 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2643 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2646 return -EOPNOTSUPP;
2647
Steve French790fe572007-07-07 19:25:05 +00002648 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 count = le16_to_cpu(cifs_acl->access_entry_count);
2650 pACE = &cifs_acl->ace_array[0];
2651 size = sizeof(struct cifs_posix_acl);
2652 size += sizeof(struct cifs_posix_ace) * count;
2653 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002654 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002655 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2656 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 return -EINVAL;
2658 }
Steve French790fe572007-07-07 19:25:05 +00002659 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 count = le16_to_cpu(cifs_acl->access_entry_count);
2661 size = sizeof(struct cifs_posix_acl);
2662 size += sizeof(struct cifs_posix_ace) * count;
2663/* skip past access ACEs to get to default ACEs */
2664 pACE = &cifs_acl->ace_array[count];
2665 count = le16_to_cpu(cifs_acl->default_entry_count);
2666 size += sizeof(struct cifs_posix_ace) * count;
2667 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002668 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 return -EINVAL;
2670 } else {
2671 /* illegal type */
2672 return -EINVAL;
2673 }
2674
2675 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002676 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002677 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002678 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 return -ERANGE;
2680 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002681 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002682 for (i = 0; i < count ; i++) {
2683 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2684 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 }
2686 }
2687 return size;
2688}
2689
Steve French50c2f752007-07-13 00:33:32 +00002690static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2691 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692{
2693 __u16 rc = 0; /* 0 = ACL converted ok */
2694
Steve Frenchff7feac2005-11-15 16:45:16 -08002695 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2696 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002698 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 /* Probably no need to le convert -1 on any arch but can not hurt */
2700 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002701 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002702 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002703 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 return rc;
2705}
2706
2707/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002708static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2709 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710{
2711 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002712 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2713 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 int count;
2715 int i;
2716
Steve French790fe572007-07-07 19:25:05 +00002717 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return 0;
2719
2720 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002721 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002722 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002723 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002724 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002725 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002726 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 return 0;
2728 }
2729 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002730 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002731 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002732 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002733 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 else {
Steve French50c2f752007-07-13 00:33:32 +00002735 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 return 0;
2737 }
Steve French50c2f752007-07-13 00:33:32 +00002738 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2740 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002741 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 /* ACE not converted */
2743 break;
2744 }
2745 }
Steve French790fe572007-07-07 19:25:05 +00002746 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2748 rc += sizeof(struct cifs_posix_acl);
2749 /* BB add check to make sure ACL does not overflow SMB */
2750 }
2751 return rc;
2752}
2753
2754int
2755CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002756 const unsigned char *searchName,
2757 char *acl_inf, const int buflen, const int acl_type,
2758 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759{
2760/* SMB_QUERY_POSIX_ACL */
2761 TRANSACTION2_QPI_REQ *pSMB = NULL;
2762 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2763 int rc = 0;
2764 int bytes_returned;
2765 int name_len;
2766 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002767
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2769
2770queryAclRetry:
2771 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2772 (void **) &pSMBr);
2773 if (rc)
2774 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002775
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2777 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002778 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002779 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 name_len++; /* trailing null */
2781 name_len *= 2;
2782 pSMB->FileName[name_len] = 0;
2783 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002784 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 name_len = strnlen(searchName, PATH_MAX);
2786 name_len++; /* trailing null */
2787 strncpy(pSMB->FileName, searchName, name_len);
2788 }
2789
2790 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2791 pSMB->TotalDataCount = 0;
2792 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002793 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 pSMB->MaxDataCount = cpu_to_le16(4000);
2795 pSMB->MaxSetupCount = 0;
2796 pSMB->Reserved = 0;
2797 pSMB->Flags = 0;
2798 pSMB->Timeout = 0;
2799 pSMB->Reserved2 = 0;
2800 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002801 offsetof(struct smb_com_transaction2_qpi_req,
2802 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 pSMB->DataCount = 0;
2804 pSMB->DataOffset = 0;
2805 pSMB->SetupCount = 1;
2806 pSMB->Reserved3 = 0;
2807 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2808 byte_count = params + 1 /* pad */ ;
2809 pSMB->TotalParameterCount = cpu_to_le16(params);
2810 pSMB->ParameterCount = pSMB->TotalParameterCount;
2811 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2812 pSMB->Reserved4 = 0;
2813 pSMB->hdr.smb_buf_length += byte_count;
2814 pSMB->ByteCount = cpu_to_le16(byte_count);
2815
2816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002818 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 if (rc) {
2820 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2821 } else {
2822 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002823
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2825 if (rc || (pSMBr->ByteCount < 2))
2826 /* BB also check enough total bytes returned */
2827 rc = -EIO; /* bad smb */
2828 else {
2829 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2830 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2831 rc = cifs_copy_posix_acl(acl_inf,
2832 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002833 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 }
2835 }
2836 cifs_buf_release(pSMB);
2837 if (rc == -EAGAIN)
2838 goto queryAclRetry;
2839 return rc;
2840}
2841
2842int
2843CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002844 const unsigned char *fileName,
2845 const char *local_acl, const int buflen,
2846 const int acl_type,
2847 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848{
2849 struct smb_com_transaction2_spi_req *pSMB = NULL;
2850 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2851 char *parm_data;
2852 int name_len;
2853 int rc = 0;
2854 int bytes_returned = 0;
2855 __u16 params, byte_count, data_count, param_offset, offset;
2856
2857 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2858setAclRetry:
2859 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002860 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 if (rc)
2862 return rc;
2863 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2864 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002865 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002866 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 name_len++; /* trailing null */
2868 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002869 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 name_len = strnlen(fileName, PATH_MAX);
2871 name_len++; /* trailing null */
2872 strncpy(pSMB->FileName, fileName, name_len);
2873 }
2874 params = 6 + name_len;
2875 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002876 /* BB find max SMB size from sess */
2877 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 pSMB->MaxSetupCount = 0;
2879 pSMB->Reserved = 0;
2880 pSMB->Flags = 0;
2881 pSMB->Timeout = 0;
2882 pSMB->Reserved2 = 0;
2883 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002884 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 offset = param_offset + params;
2886 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2887 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2888
2889 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002890 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891
Steve French790fe572007-07-07 19:25:05 +00002892 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 rc = -EOPNOTSUPP;
2894 goto setACLerrorExit;
2895 }
2896 pSMB->DataOffset = cpu_to_le16(offset);
2897 pSMB->SetupCount = 1;
2898 pSMB->Reserved3 = 0;
2899 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2900 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2901 byte_count = 3 /* pad */ + params + data_count;
2902 pSMB->DataCount = cpu_to_le16(data_count);
2903 pSMB->TotalDataCount = pSMB->DataCount;
2904 pSMB->ParameterCount = cpu_to_le16(params);
2905 pSMB->TotalParameterCount = pSMB->ParameterCount;
2906 pSMB->Reserved4 = 0;
2907 pSMB->hdr.smb_buf_length += byte_count;
2908 pSMB->ByteCount = cpu_to_le16(byte_count);
2909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002911 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913
2914setACLerrorExit:
2915 cifs_buf_release(pSMB);
2916 if (rc == -EAGAIN)
2917 goto setAclRetry;
2918 return rc;
2919}
2920
Steve Frenchf654bac2005-04-28 22:41:04 -07002921/* BB fix tabs in this function FIXME BB */
2922int
2923CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002924 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002925{
Steve French50c2f752007-07-13 00:33:32 +00002926 int rc = 0;
2927 struct smb_t2_qfi_req *pSMB = NULL;
2928 struct smb_t2_qfi_rsp *pSMBr = NULL;
2929 int bytes_returned;
2930 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002931
Steve French790fe572007-07-07 19:25:05 +00002932 cFYI(1, ("In GetExtAttr"));
2933 if (tcon == NULL)
2934 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002935
2936GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002937 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2938 (void **) &pSMBr);
2939 if (rc)
2940 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002941
Steve Frenchad7a2922008-02-07 23:25:02 +00002942 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002943 pSMB->t2.TotalDataCount = 0;
2944 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2945 /* BB find exact max data count below from sess structure BB */
2946 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2947 pSMB->t2.MaxSetupCount = 0;
2948 pSMB->t2.Reserved = 0;
2949 pSMB->t2.Flags = 0;
2950 pSMB->t2.Timeout = 0;
2951 pSMB->t2.Reserved2 = 0;
2952 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2953 Fid) - 4);
2954 pSMB->t2.DataCount = 0;
2955 pSMB->t2.DataOffset = 0;
2956 pSMB->t2.SetupCount = 1;
2957 pSMB->t2.Reserved3 = 0;
2958 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2959 byte_count = params + 1 /* pad */ ;
2960 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2961 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2962 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2963 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002964 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002965 pSMB->hdr.smb_buf_length += byte_count;
2966 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002967
Steve French790fe572007-07-07 19:25:05 +00002968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2970 if (rc) {
2971 cFYI(1, ("error %d in GetExtAttr", rc));
2972 } else {
2973 /* decode response */
2974 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2975 if (rc || (pSMBr->ByteCount < 2))
2976 /* BB also check enough total bytes returned */
2977 /* If rc should we check for EOPNOSUPP and
2978 disable the srvino flag? or in caller? */
2979 rc = -EIO; /* bad smb */
2980 else {
2981 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2982 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2983 struct file_chattr_info *pfinfo;
2984 /* BB Do we need a cast or hash here ? */
2985 if (count != 16) {
2986 cFYI(1, ("Illegal size ret in GetExtAttr"));
2987 rc = -EIO;
2988 goto GetExtAttrOut;
2989 }
2990 pfinfo = (struct file_chattr_info *)
2991 (data_offset + (char *) &pSMBr->hdr.Protocol);
2992 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07002993 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00002994 }
2995 }
Steve Frenchf654bac2005-04-28 22:41:04 -07002996GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00002997 cifs_buf_release(pSMB);
2998 if (rc == -EAGAIN)
2999 goto GetExtAttrRetry;
3000 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003001}
3002
Steve Frenchf654bac2005-04-28 22:41:04 -07003003#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004
Steve French297647c2007-10-12 04:11:59 +00003005#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003006/* Get Security Descriptor (by handle) from remote server for a file or dir */
3007int
3008CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003009 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003010{
3011 int rc = 0;
3012 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003013 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003014 struct kvec iov[1];
3015
3016 cFYI(1, ("GetCifsACL"));
3017
Steve French630f3f02007-10-25 21:17:17 +00003018 *pbuflen = 0;
3019 *acl_inf = NULL;
3020
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003021 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003022 8 /* parm len */, tcon, (void **) &pSMB);
3023 if (rc)
3024 return rc;
3025
3026 pSMB->MaxParameterCount = cpu_to_le32(4);
3027 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3028 pSMB->MaxSetupCount = 0;
3029 pSMB->Fid = fid; /* file handle always le */
3030 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3031 CIFS_ACL_DACL);
3032 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3033 pSMB->hdr.smb_buf_length += 11;
3034 iov[0].iov_base = (char *)pSMB;
3035 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3036
Steve Frencha761ac52007-10-18 21:45:27 +00003037 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003038 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003039 cifs_stats_inc(&tcon->num_acl_get);
3040 if (rc) {
3041 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3042 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003043 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003044 __u32 parm_len;
3045 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003046 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003047 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003048
3049/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003050 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003051 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003052 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003053 goto qsec_out;
3054 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3055
Steve French630f3f02007-10-25 21:17:17 +00003056 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003057
3058 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3059 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003060 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003061 goto qsec_out;
3062 }
3063
3064/* BB check that data area is minimum length and as big as acl_len */
3065
Steve Frenchaf6f4612007-10-16 18:40:37 +00003066 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003067 if (acl_len != *pbuflen) {
3068 cERROR(1, ("acl length %d does not match %d",
3069 acl_len, *pbuflen));
3070 if (*pbuflen > acl_len)
3071 *pbuflen = acl_len;
3072 }
Steve French0a4b92c2006-01-12 15:44:21 -08003073
Steve French630f3f02007-10-25 21:17:17 +00003074 /* check if buffer is big enough for the acl
3075 header followed by the smallest SID */
3076 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3077 (*pbuflen >= 64 * 1024)) {
3078 cERROR(1, ("bad acl length %d", *pbuflen));
3079 rc = -EINVAL;
3080 *pbuflen = 0;
3081 } else {
3082 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3083 if (*acl_inf == NULL) {
3084 *pbuflen = 0;
3085 rc = -ENOMEM;
3086 }
3087 memcpy(*acl_inf, pdata, *pbuflen);
3088 }
Steve French0a4b92c2006-01-12 15:44:21 -08003089 }
3090qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003091 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003092 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003093 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003094 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003095/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003096 return rc;
3097}
Steve French97837582007-12-31 07:47:21 +00003098
3099int
3100CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3101 struct cifs_ntsd *pntsd, __u32 acllen)
3102{
3103 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3104 int rc = 0;
3105 int bytes_returned = 0;
3106 SET_SEC_DESC_REQ *pSMB = NULL;
3107 NTRANSACT_RSP *pSMBr = NULL;
3108
3109setCifsAclRetry:
3110 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3111 (void **) &pSMBr);
3112 if (rc)
3113 return (rc);
3114
3115 pSMB->MaxSetupCount = 0;
3116 pSMB->Reserved = 0;
3117
3118 param_count = 8;
3119 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3120 data_count = acllen;
3121 data_offset = param_offset + param_count;
3122 byte_count = 3 /* pad */ + param_count;
3123
3124 pSMB->DataCount = cpu_to_le32(data_count);
3125 pSMB->TotalDataCount = pSMB->DataCount;
3126 pSMB->MaxParameterCount = cpu_to_le32(4);
3127 pSMB->MaxDataCount = cpu_to_le32(16384);
3128 pSMB->ParameterCount = cpu_to_le32(param_count);
3129 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3130 pSMB->TotalParameterCount = pSMB->ParameterCount;
3131 pSMB->DataOffset = cpu_to_le32(data_offset);
3132 pSMB->SetupCount = 0;
3133 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3134 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3135
3136 pSMB->Fid = fid; /* file handle always le */
3137 pSMB->Reserved2 = 0;
3138 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3139
3140 if (pntsd && acllen) {
3141 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3142 (char *) pntsd,
3143 acllen);
3144 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3145
3146 } else
3147 pSMB->hdr.smb_buf_length += byte_count;
3148
3149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3151
3152 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3153 if (rc)
3154 cFYI(1, ("Set CIFS ACL returned %d", rc));
3155 cifs_buf_release(pSMB);
3156
3157 if (rc == -EAGAIN)
3158 goto setCifsAclRetry;
3159
3160 return (rc);
3161}
3162
Steve French297647c2007-10-12 04:11:59 +00003163#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003164
Steve French6b8edfe2005-08-23 20:26:03 -07003165/* Legacy Query Path Information call for lookup to old servers such
3166 as Win9x/WinME */
3167int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003168 const unsigned char *searchName,
3169 FILE_ALL_INFO *pFinfo,
3170 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003171{
Steve Frenchad7a2922008-02-07 23:25:02 +00003172 QUERY_INFORMATION_REQ *pSMB;
3173 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003174 int rc = 0;
3175 int bytes_returned;
3176 int name_len;
3177
Steve French50c2f752007-07-13 00:33:32 +00003178 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003179QInfRetry:
3180 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003181 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003182 if (rc)
3183 return rc;
3184
3185 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3186 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003187 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3188 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003189 name_len++; /* trailing null */
3190 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003191 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003192 name_len = strnlen(searchName, PATH_MAX);
3193 name_len++; /* trailing null */
3194 strncpy(pSMB->FileName, searchName, name_len);
3195 }
3196 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003197 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003198 pSMB->hdr.smb_buf_length += (__u16) name_len;
3199 pSMB->ByteCount = cpu_to_le16(name_len);
3200
3201 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003202 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003203 if (rc) {
3204 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003205 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003206 struct timespec ts;
3207 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003208
3209 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003210 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003211 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003212 ts.tv_nsec = 0;
3213 ts.tv_sec = time;
3214 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003215 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003216 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3217 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003218 pFinfo->AllocationSize =
3219 cpu_to_le64(le32_to_cpu(pSMBr->size));
3220 pFinfo->EndOfFile = pFinfo->AllocationSize;
3221 pFinfo->Attributes =
3222 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003223 } else
3224 rc = -EIO; /* bad buffer passed in */
3225
3226 cifs_buf_release(pSMB);
3227
3228 if (rc == -EAGAIN)
3229 goto QInfRetry;
3230
3231 return rc;
3232}
3233
Jeff Laytonbcd53572010-02-12 07:44:16 -05003234int
3235CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3236 u16 netfid, FILE_ALL_INFO *pFindData)
3237{
3238 struct smb_t2_qfi_req *pSMB = NULL;
3239 struct smb_t2_qfi_rsp *pSMBr = NULL;
3240 int rc = 0;
3241 int bytes_returned;
3242 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003243
Jeff Laytonbcd53572010-02-12 07:44:16 -05003244QFileInfoRetry:
3245 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3246 (void **) &pSMBr);
3247 if (rc)
3248 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003249
Jeff Laytonbcd53572010-02-12 07:44:16 -05003250 params = 2 /* level */ + 2 /* fid */;
3251 pSMB->t2.TotalDataCount = 0;
3252 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3253 /* BB find exact max data count below from sess structure BB */
3254 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3255 pSMB->t2.MaxSetupCount = 0;
3256 pSMB->t2.Reserved = 0;
3257 pSMB->t2.Flags = 0;
3258 pSMB->t2.Timeout = 0;
3259 pSMB->t2.Reserved2 = 0;
3260 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3261 Fid) - 4);
3262 pSMB->t2.DataCount = 0;
3263 pSMB->t2.DataOffset = 0;
3264 pSMB->t2.SetupCount = 1;
3265 pSMB->t2.Reserved3 = 0;
3266 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3267 byte_count = params + 1 /* pad */ ;
3268 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3269 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3270 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3271 pSMB->Pad = 0;
3272 pSMB->Fid = netfid;
3273 pSMB->hdr.smb_buf_length += byte_count;
3274
3275 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3276 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3277 if (rc) {
3278 cFYI(1, ("Send error in QPathInfo = %d", rc));
3279 } else { /* decode response */
3280 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3281
3282 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3283 rc = -EIO;
3284 else if (pSMBr->ByteCount < 40)
3285 rc = -EIO; /* bad smb */
3286 else if (pFindData) {
3287 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3288 memcpy((char *) pFindData,
3289 (char *) &pSMBr->hdr.Protocol +
3290 data_offset, sizeof(FILE_ALL_INFO));
3291 } else
3292 rc = -ENOMEM;
3293 }
3294 cifs_buf_release(pSMB);
3295 if (rc == -EAGAIN)
3296 goto QFileInfoRetry;
3297
3298 return rc;
3299}
Steve French6b8edfe2005-08-23 20:26:03 -07003300
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301int
3302CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3303 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003304 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003305 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003306 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307{
3308/* level 263 SMB_QUERY_FILE_ALL_INFO */
3309 TRANSACTION2_QPI_REQ *pSMB = NULL;
3310 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3311 int rc = 0;
3312 int bytes_returned;
3313 int name_len;
3314 __u16 params, byte_count;
3315
3316/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3317QPathInfoRetry:
3318 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3319 (void **) &pSMBr);
3320 if (rc)
3321 return rc;
3322
3323 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3324 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003325 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003326 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 name_len++; /* trailing null */
3328 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003329 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 name_len = strnlen(searchName, PATH_MAX);
3331 name_len++; /* trailing null */
3332 strncpy(pSMB->FileName, searchName, name_len);
3333 }
3334
Steve French50c2f752007-07-13 00:33:32 +00003335 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 pSMB->TotalDataCount = 0;
3337 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003338 /* BB find exact max SMB PDU from sess structure BB */
3339 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 pSMB->MaxSetupCount = 0;
3341 pSMB->Reserved = 0;
3342 pSMB->Flags = 0;
3343 pSMB->Timeout = 0;
3344 pSMB->Reserved2 = 0;
3345 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003346 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 pSMB->DataCount = 0;
3348 pSMB->DataOffset = 0;
3349 pSMB->SetupCount = 1;
3350 pSMB->Reserved3 = 0;
3351 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3352 byte_count = params + 1 /* pad */ ;
3353 pSMB->TotalParameterCount = cpu_to_le16(params);
3354 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003355 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003356 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3357 else
3358 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 pSMB->Reserved4 = 0;
3360 pSMB->hdr.smb_buf_length += byte_count;
3361 pSMB->ByteCount = cpu_to_le16(byte_count);
3362
3363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3365 if (rc) {
3366 cFYI(1, ("Send error in QPathInfo = %d", rc));
3367 } else { /* decode response */
3368 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3369
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003370 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3371 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003372 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003374 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003375 rc = -EIO; /* 24 or 26 expected but we do not read
3376 last field */
3377 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003378 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003380
3381 /* On legacy responses we do not read the last field,
3382 EAsize, fortunately since it varies by subdialect and
3383 also note it differs on Set vs. Get, ie two bytes or 4
3384 bytes depending but we don't care here */
3385 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003386 size = sizeof(FILE_INFO_STANDARD);
3387 else
3388 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 memcpy((char *) pFindData,
3390 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003391 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 } else
3393 rc = -ENOMEM;
3394 }
3395 cifs_buf_release(pSMB);
3396 if (rc == -EAGAIN)
3397 goto QPathInfoRetry;
3398
3399 return rc;
3400}
3401
3402int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003403CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3404 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3405{
3406 struct smb_t2_qfi_req *pSMB = NULL;
3407 struct smb_t2_qfi_rsp *pSMBr = NULL;
3408 int rc = 0;
3409 int bytes_returned;
3410 __u16 params, byte_count;
3411
3412UnixQFileInfoRetry:
3413 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3414 (void **) &pSMBr);
3415 if (rc)
3416 return rc;
3417
3418 params = 2 /* level */ + 2 /* fid */;
3419 pSMB->t2.TotalDataCount = 0;
3420 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3421 /* BB find exact max data count below from sess structure BB */
3422 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3423 pSMB->t2.MaxSetupCount = 0;
3424 pSMB->t2.Reserved = 0;
3425 pSMB->t2.Flags = 0;
3426 pSMB->t2.Timeout = 0;
3427 pSMB->t2.Reserved2 = 0;
3428 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3429 Fid) - 4);
3430 pSMB->t2.DataCount = 0;
3431 pSMB->t2.DataOffset = 0;
3432 pSMB->t2.SetupCount = 1;
3433 pSMB->t2.Reserved3 = 0;
3434 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3435 byte_count = params + 1 /* pad */ ;
3436 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3437 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3438 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3439 pSMB->Pad = 0;
3440 pSMB->Fid = netfid;
3441 pSMB->hdr.smb_buf_length += byte_count;
3442
3443 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3444 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3445 if (rc) {
3446 cFYI(1, ("Send error in QPathInfo = %d", rc));
3447 } else { /* decode response */
3448 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3449
3450 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3451 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3452 "Unix Extensions can be disabled on mount "
3453 "by specifying the nosfu mount option."));
3454 rc = -EIO; /* bad smb */
3455 } else {
3456 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3457 memcpy((char *) pFindData,
3458 (char *) &pSMBr->hdr.Protocol +
3459 data_offset,
3460 sizeof(FILE_UNIX_BASIC_INFO));
3461 }
3462 }
3463
3464 cifs_buf_release(pSMB);
3465 if (rc == -EAGAIN)
3466 goto UnixQFileInfoRetry;
3467
3468 return rc;
3469}
3470
3471int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3473 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003474 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003475 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003476{
3477/* SMB_QUERY_FILE_UNIX_BASIC */
3478 TRANSACTION2_QPI_REQ *pSMB = NULL;
3479 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3480 int rc = 0;
3481 int bytes_returned = 0;
3482 int name_len;
3483 __u16 params, byte_count;
3484
3485 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3486UnixQPathInfoRetry:
3487 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3488 (void **) &pSMBr);
3489 if (rc)
3490 return rc;
3491
3492 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3493 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003494 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003495 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 name_len++; /* trailing null */
3497 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003498 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 name_len = strnlen(searchName, PATH_MAX);
3500 name_len++; /* trailing null */
3501 strncpy(pSMB->FileName, searchName, name_len);
3502 }
3503
Steve French50c2f752007-07-13 00:33:32 +00003504 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 pSMB->TotalDataCount = 0;
3506 pSMB->MaxParameterCount = cpu_to_le16(2);
3507 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003508 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 pSMB->MaxSetupCount = 0;
3510 pSMB->Reserved = 0;
3511 pSMB->Flags = 0;
3512 pSMB->Timeout = 0;
3513 pSMB->Reserved2 = 0;
3514 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003515 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 pSMB->DataCount = 0;
3517 pSMB->DataOffset = 0;
3518 pSMB->SetupCount = 1;
3519 pSMB->Reserved3 = 0;
3520 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3521 byte_count = params + 1 /* pad */ ;
3522 pSMB->TotalParameterCount = cpu_to_le16(params);
3523 pSMB->ParameterCount = pSMB->TotalParameterCount;
3524 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3525 pSMB->Reserved4 = 0;
3526 pSMB->hdr.smb_buf_length += byte_count;
3527 pSMB->ByteCount = cpu_to_le16(byte_count);
3528
3529 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3530 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3531 if (rc) {
3532 cFYI(1, ("Send error in QPathInfo = %d", rc));
3533 } else { /* decode response */
3534 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3535
3536 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003537 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3538 "Unix Extensions can be disabled on mount "
3539 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 rc = -EIO; /* bad smb */
3541 } else {
3542 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3543 memcpy((char *) pFindData,
3544 (char *) &pSMBr->hdr.Protocol +
3545 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003546 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 }
3548 }
3549 cifs_buf_release(pSMB);
3550 if (rc == -EAGAIN)
3551 goto UnixQPathInfoRetry;
3552
3553 return rc;
3554}
3555
Linus Torvalds1da177e2005-04-16 15:20:36 -07003556/* xid, tcon, searchName and codepage are input parms, rest are returned */
3557int
3558CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003559 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003561 __u16 *pnetfid,
3562 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563{
3564/* level 257 SMB_ */
3565 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3566 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003567 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 int rc = 0;
3569 int bytes_returned = 0;
3570 int name_len;
3571 __u16 params, byte_count;
3572
Steve French50c2f752007-07-13 00:33:32 +00003573 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
3575findFirstRetry:
3576 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3577 (void **) &pSMBr);
3578 if (rc)
3579 return rc;
3580
3581 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3582 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003583 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003584 PATH_MAX, nls_codepage, remap);
3585 /* We can not add the asterik earlier in case
3586 it got remapped to 0xF03A as if it were part of the
3587 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003589 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003590 pSMB->FileName[name_len+1] = 0;
3591 pSMB->FileName[name_len+2] = '*';
3592 pSMB->FileName[name_len+3] = 0;
3593 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3595 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003596 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 } else { /* BB add check for overrun of SMB buf BB */
3598 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003600 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 free buffer exit; BB */
3602 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003603 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003604 pSMB->FileName[name_len+1] = '*';
3605 pSMB->FileName[name_len+2] = 0;
3606 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 }
3608
3609 params = 12 + name_len /* includes null */ ;
3610 pSMB->TotalDataCount = 0; /* no EAs */
3611 pSMB->MaxParameterCount = cpu_to_le16(10);
3612 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3613 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3614 pSMB->MaxSetupCount = 0;
3615 pSMB->Reserved = 0;
3616 pSMB->Flags = 0;
3617 pSMB->Timeout = 0;
3618 pSMB->Reserved2 = 0;
3619 byte_count = params + 1 /* pad */ ;
3620 pSMB->TotalParameterCount = cpu_to_le16(params);
3621 pSMB->ParameterCount = pSMB->TotalParameterCount;
3622 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003623 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3624 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 pSMB->DataCount = 0;
3626 pSMB->DataOffset = 0;
3627 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3628 pSMB->Reserved3 = 0;
3629 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3630 pSMB->SearchAttributes =
3631 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3632 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003633 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3634 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 CIFS_SEARCH_RETURN_RESUME);
3636 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3637
3638 /* BB what should we set StorageType to? Does it matter? BB */
3639 pSMB->SearchStorageType = 0;
3640 pSMB->hdr.smb_buf_length += byte_count;
3641 pSMB->ByteCount = cpu_to_le16(byte_count);
3642
3643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003645 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646
Steve French88274812006-03-09 22:21:45 +00003647 if (rc) {/* BB add logic to retry regular search if Unix search
3648 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003649 /* BB Add code to handle unsupported level rc */
3650 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003651
Steve French88274812006-03-09 22:21:45 +00003652 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653
3654 /* BB eventually could optimize out free and realloc of buf */
3655 /* for this case */
3656 if (rc == -EAGAIN)
3657 goto findFirstRetry;
3658 } else { /* decode response */
3659 /* BB remember to free buffer if error BB */
3660 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003661 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003662 unsigned int lnoff;
3663
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003665 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 else
Steve French4b18f2a2008-04-29 00:06:05 +00003667 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668
3669 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003670 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003671 psrch_inf->srch_entries_start =
3672 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3675 le16_to_cpu(pSMBr->t2.ParameterOffset));
3676
Steve French790fe572007-07-07 19:25:05 +00003677 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003678 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 else
Steve French4b18f2a2008-04-29 00:06:05 +00003680 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
Steve French50c2f752007-07-13 00:33:32 +00003682 psrch_inf->entries_in_buffer =
3683 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003684 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003686 lnoff = le16_to_cpu(parms->LastNameOffset);
3687 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3688 lnoff) {
3689 cERROR(1, ("ignoring corrupt resume name"));
3690 psrch_inf->last_entry = NULL;
3691 return rc;
3692 }
3693
Steve French0752f152008-10-07 20:03:33 +00003694 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003695 lnoff;
3696
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697 *pnetfid = parms->SearchHandle;
3698 } else {
3699 cifs_buf_release(pSMB);
3700 }
3701 }
3702
3703 return rc;
3704}
3705
3706int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003707 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708{
3709 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3710 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003711 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 char *response_data;
3713 int rc = 0;
3714 int bytes_returned, name_len;
3715 __u16 params, byte_count;
3716
3717 cFYI(1, ("In FindNext"));
3718
Steve French4b18f2a2008-04-29 00:06:05 +00003719 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 return -ENOENT;
3721
3722 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3723 (void **) &pSMBr);
3724 if (rc)
3725 return rc;
3726
Steve French50c2f752007-07-13 00:33:32 +00003727 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728 byte_count = 0;
3729 pSMB->TotalDataCount = 0; /* no EAs */
3730 pSMB->MaxParameterCount = cpu_to_le16(8);
3731 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003732 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3733 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 pSMB->MaxSetupCount = 0;
3735 pSMB->Reserved = 0;
3736 pSMB->Flags = 0;
3737 pSMB->Timeout = 0;
3738 pSMB->Reserved2 = 0;
3739 pSMB->ParameterOffset = cpu_to_le16(
3740 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3741 pSMB->DataCount = 0;
3742 pSMB->DataOffset = 0;
3743 pSMB->SetupCount = 1;
3744 pSMB->Reserved3 = 0;
3745 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3746 pSMB->SearchHandle = searchHandle; /* always kept as le */
3747 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00003748 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3750 pSMB->ResumeKey = psrch_inf->resume_key;
3751 pSMB->SearchFlags =
3752 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3753
3754 name_len = psrch_inf->resume_name_len;
3755 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003756 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3758 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003759 /* 14 byte parm len above enough for 2 byte null terminator */
3760 pSMB->ResumeFileName[name_len] = 0;
3761 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 } else {
3763 rc = -EINVAL;
3764 goto FNext2_err_exit;
3765 }
3766 byte_count = params + 1 /* pad */ ;
3767 pSMB->TotalParameterCount = cpu_to_le16(params);
3768 pSMB->ParameterCount = pSMB->TotalParameterCount;
3769 pSMB->hdr.smb_buf_length += byte_count;
3770 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3773 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003774 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 if (rc) {
3776 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003777 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003778 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003779 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003780 } else
3781 cFYI(1, ("FindNext returned = %d", rc));
3782 } else { /* decode response */
3783 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003784
Steve French790fe572007-07-07 19:25:05 +00003785 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003786 unsigned int lnoff;
3787
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 /* BB fixme add lock for file (srch_info) struct here */
3789 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003790 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 else
Steve French4b18f2a2008-04-29 00:06:05 +00003792 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 response_data = (char *) &pSMBr->hdr.Protocol +
3794 le16_to_cpu(pSMBr->t2.ParameterOffset);
3795 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3796 response_data = (char *)&pSMBr->hdr.Protocol +
3797 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003798 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003799 cifs_small_buf_release(
3800 psrch_inf->ntwrk_buf_start);
3801 else
3802 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 psrch_inf->srch_entries_start = response_data;
3804 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003805 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003806 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003807 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 else
Steve French4b18f2a2008-04-29 00:06:05 +00003809 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003810 psrch_inf->entries_in_buffer =
3811 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 psrch_inf->index_of_last_entry +=
3813 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003814 lnoff = le16_to_cpu(parms->LastNameOffset);
3815 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3816 lnoff) {
3817 cERROR(1, ("ignoring corrupt resume name"));
3818 psrch_inf->last_entry = NULL;
3819 return rc;
3820 } else
3821 psrch_inf->last_entry =
3822 psrch_inf->srch_entries_start + lnoff;
3823
Steve French50c2f752007-07-13 00:33:32 +00003824/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3825 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826
3827 /* BB fixme add unlock here */
3828 }
3829
3830 }
3831
3832 /* BB On error, should we leave previous search buf (and count and
3833 last entry fields) intact or free the previous one? */
3834
3835 /* Note: On -EAGAIN error only caller can retry on handle based calls
3836 since file handle passed in no longer valid */
3837FNext2_err_exit:
3838 if (rc != 0)
3839 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 return rc;
3841}
3842
3843int
Steve French50c2f752007-07-13 00:33:32 +00003844CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3845 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846{
3847 int rc = 0;
3848 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849
3850 cFYI(1, ("In CIFSSMBFindClose"));
3851 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3852
3853 /* no sense returning error if session restarted
3854 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003855 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 return 0;
3857 if (rc)
3858 return rc;
3859
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 pSMB->FileID = searchHandle;
3861 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003862 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003863 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003865
Steve Frencha4544342005-08-24 13:59:35 -07003866 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867
3868 /* Since session is dead, search handle closed on server already */
3869 if (rc == -EAGAIN)
3870 rc = 0;
3871
3872 return rc;
3873}
3874
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875int
3876CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003877 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003878 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003879 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880{
3881 int rc = 0;
3882 TRANSACTION2_QPI_REQ *pSMB = NULL;
3883 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3884 int name_len, bytes_returned;
3885 __u16 params, byte_count;
3886
Steve French50c2f752007-07-13 00:33:32 +00003887 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003888 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003889 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890
3891GetInodeNumberRetry:
3892 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003893 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 if (rc)
3895 return rc;
3896
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3898 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003899 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003900 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 name_len++; /* trailing null */
3902 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003903 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 name_len = strnlen(searchName, PATH_MAX);
3905 name_len++; /* trailing null */
3906 strncpy(pSMB->FileName, searchName, name_len);
3907 }
3908
3909 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3910 pSMB->TotalDataCount = 0;
3911 pSMB->MaxParameterCount = cpu_to_le16(2);
3912 /* BB find exact max data count below from sess structure BB */
3913 pSMB->MaxDataCount = cpu_to_le16(4000);
3914 pSMB->MaxSetupCount = 0;
3915 pSMB->Reserved = 0;
3916 pSMB->Flags = 0;
3917 pSMB->Timeout = 0;
3918 pSMB->Reserved2 = 0;
3919 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003920 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921 pSMB->DataCount = 0;
3922 pSMB->DataOffset = 0;
3923 pSMB->SetupCount = 1;
3924 pSMB->Reserved3 = 0;
3925 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3926 byte_count = params + 1 /* pad */ ;
3927 pSMB->TotalParameterCount = cpu_to_le16(params);
3928 pSMB->ParameterCount = pSMB->TotalParameterCount;
3929 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3930 pSMB->Reserved4 = 0;
3931 pSMB->hdr.smb_buf_length += byte_count;
3932 pSMB->ByteCount = cpu_to_le16(byte_count);
3933
3934 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3935 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3936 if (rc) {
3937 cFYI(1, ("error %d in QueryInternalInfo", rc));
3938 } else {
3939 /* decode response */
3940 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3941 if (rc || (pSMBr->ByteCount < 2))
3942 /* BB also check enough total bytes returned */
3943 /* If rc should we check for EOPNOSUPP and
3944 disable the srvino flag? or in caller? */
3945 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003946 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3948 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003949 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003951 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3953 rc = -EIO;
3954 goto GetInodeNumOut;
3955 }
3956 pfinfo = (struct file_internal_info *)
3957 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003958 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 }
3960 }
3961GetInodeNumOut:
3962 cifs_buf_release(pSMB);
3963 if (rc == -EAGAIN)
3964 goto GetInodeNumberRetry;
3965 return rc;
3966}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967
Igor Mammedovfec45852008-05-16 13:06:30 +04003968/* parses DFS refferal V3 structure
3969 * caller is responsible for freeing target_nodes
3970 * returns:
3971 * on success - 0
3972 * on failure - errno
3973 */
3974static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003975parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003976 unsigned int *num_of_nodes,
3977 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003978 const struct nls_table *nls_codepage, int remap,
3979 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003980{
3981 int i, rc = 0;
3982 char *data_end;
3983 bool is_unicode;
3984 struct dfs_referral_level_3 *ref;
3985
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003986 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3987 is_unicode = true;
3988 else
3989 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003990 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3991
3992 if (*num_of_nodes < 1) {
3993 cERROR(1, ("num_referrals: must be at least > 0,"
3994 "but we get num_referrals = %d\n", *num_of_nodes));
3995 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003996 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003997 }
3998
3999 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004000 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004001 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01004002 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04004003 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004004 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004005 }
4006
4007 /* get the upper boundary of the resp buffer */
4008 data_end = (char *)(&(pSMBr->PathConsumed)) +
4009 le16_to_cpu(pSMBr->t2.DataCount);
4010
4011 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
4012 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00004013 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04004014
4015 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4016 *num_of_nodes, GFP_KERNEL);
4017 if (*target_nodes == NULL) {
4018 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
4019 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004020 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004021 }
4022
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004023 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004024 for (i = 0; i < *num_of_nodes; i++) {
4025 char *temp;
4026 int max_len;
4027 struct dfs_info3_param *node = (*target_nodes)+i;
4028
Steve French0e0d2cf2009-05-01 05:27:32 +00004029 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004030 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004031 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4032 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004033 if (tmp == NULL) {
4034 rc = -ENOMEM;
4035 goto parse_DFS_referrals_exit;
4036 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004037 cifsConvertToUCS((__le16 *) tmp, searchName,
4038 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004039 node->path_consumed = cifs_ucs2_bytes(tmp,
4040 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004041 nls_codepage);
4042 kfree(tmp);
4043 } else
4044 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4045
Igor Mammedovfec45852008-05-16 13:06:30 +04004046 node->server_type = le16_to_cpu(ref->ServerType);
4047 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4048
4049 /* copy DfsPath */
4050 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4051 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004052 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4053 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004054 if (!node->path_name) {
4055 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004056 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004057 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004058
4059 /* copy link target UNC */
4060 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4061 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004062 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4063 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004064 if (!node->node_name)
4065 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004066 }
4067
Steve Frencha1fe78f2008-05-16 18:48:38 +00004068parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004069 if (rc) {
4070 free_dfs_info_array(*target_nodes, *num_of_nodes);
4071 *target_nodes = NULL;
4072 *num_of_nodes = 0;
4073 }
4074 return rc;
4075}
4076
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077int
4078CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4079 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004080 struct dfs_info3_param **target_nodes,
4081 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004082 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083{
4084/* TRANS2_GET_DFS_REFERRAL */
4085 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4086 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 int rc = 0;
4088 int bytes_returned;
4089 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004091 *num_of_nodes = 0;
4092 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093
4094 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4095 if (ses == NULL)
4096 return -ENODEV;
4097getDFSRetry:
4098 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4099 (void **) &pSMBr);
4100 if (rc)
4101 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004102
4103 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004104 but should never be null here anyway */
4105 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 pSMB->hdr.Tid = ses->ipc_tid;
4107 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004108 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004110 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
4113 if (ses->capabilities & CAP_UNICODE) {
4114 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4115 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004116 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004117 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 name_len++; /* trailing null */
4119 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004120 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 name_len = strnlen(searchName, PATH_MAX);
4122 name_len++; /* trailing null */
4123 strncpy(pSMB->RequestFileName, searchName, name_len);
4124 }
4125
Steve French790fe572007-07-07 19:25:05 +00004126 if (ses->server) {
4127 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004128 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4129 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4130 }
4131
Steve French50c2f752007-07-13 00:33:32 +00004132 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004133
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 params = 2 /* level */ + name_len /*includes null */ ;
4135 pSMB->TotalDataCount = 0;
4136 pSMB->DataCount = 0;
4137 pSMB->DataOffset = 0;
4138 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004139 /* BB find exact max SMB PDU from sess structure BB */
4140 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 pSMB->MaxSetupCount = 0;
4142 pSMB->Reserved = 0;
4143 pSMB->Flags = 0;
4144 pSMB->Timeout = 0;
4145 pSMB->Reserved2 = 0;
4146 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004147 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 pSMB->SetupCount = 1;
4149 pSMB->Reserved3 = 0;
4150 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4151 byte_count = params + 3 /* pad */ ;
4152 pSMB->ParameterCount = cpu_to_le16(params);
4153 pSMB->TotalParameterCount = pSMB->ParameterCount;
4154 pSMB->MaxReferralLevel = cpu_to_le16(3);
4155 pSMB->hdr.smb_buf_length += byte_count;
4156 pSMB->ByteCount = cpu_to_le16(byte_count);
4157
4158 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4159 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4160 if (rc) {
4161 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004162 goto GetDFSRefExit;
4163 }
4164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004166 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004167 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004168 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004169 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004171
4172 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4173 pSMBr->ByteCount,
4174 le16_to_cpu(pSMBr->t2.DataOffset)));
4175
4176 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004177 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004178 target_nodes, nls_codepage, remap,
4179 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004180
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004182 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183
4184 if (rc == -EAGAIN)
4185 goto getDFSRetry;
4186
4187 return rc;
4188}
4189
Steve French20962432005-09-21 22:05:57 -07004190/* Query File System Info such as free space to old servers such as Win 9x */
4191int
4192SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4193{
4194/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4195 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4196 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4197 FILE_SYSTEM_ALLOC_INFO *response_data;
4198 int rc = 0;
4199 int bytes_returned = 0;
4200 __u16 params, byte_count;
4201
4202 cFYI(1, ("OldQFSInfo"));
4203oldQFSInfoRetry:
4204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4205 (void **) &pSMBr);
4206 if (rc)
4207 return rc;
Steve French20962432005-09-21 22:05:57 -07004208
4209 params = 2; /* level */
4210 pSMB->TotalDataCount = 0;
4211 pSMB->MaxParameterCount = cpu_to_le16(2);
4212 pSMB->MaxDataCount = cpu_to_le16(1000);
4213 pSMB->MaxSetupCount = 0;
4214 pSMB->Reserved = 0;
4215 pSMB->Flags = 0;
4216 pSMB->Timeout = 0;
4217 pSMB->Reserved2 = 0;
4218 byte_count = params + 1 /* pad */ ;
4219 pSMB->TotalParameterCount = cpu_to_le16(params);
4220 pSMB->ParameterCount = pSMB->TotalParameterCount;
4221 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4222 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4223 pSMB->DataCount = 0;
4224 pSMB->DataOffset = 0;
4225 pSMB->SetupCount = 1;
4226 pSMB->Reserved3 = 0;
4227 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4228 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4229 pSMB->hdr.smb_buf_length += byte_count;
4230 pSMB->ByteCount = cpu_to_le16(byte_count);
4231
4232 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4233 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4234 if (rc) {
4235 cFYI(1, ("Send error in QFSInfo = %d", rc));
4236 } else { /* decode response */
4237 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4238
4239 if (rc || (pSMBr->ByteCount < 18))
4240 rc = -EIO; /* bad smb */
4241 else {
4242 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004243 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004244 pSMBr->ByteCount, data_offset));
4245
Steve French50c2f752007-07-13 00:33:32 +00004246 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004247 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4248 FSData->f_bsize =
4249 le16_to_cpu(response_data->BytesPerSector) *
4250 le32_to_cpu(response_data->
4251 SectorsPerAllocationUnit);
4252 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004253 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004254 FSData->f_bfree = FSData->f_bavail =
4255 le32_to_cpu(response_data->FreeAllocationUnits);
4256 cFYI(1,
4257 ("Blocks: %lld Free: %lld Block size %ld",
4258 (unsigned long long)FSData->f_blocks,
4259 (unsigned long long)FSData->f_bfree,
4260 FSData->f_bsize));
4261 }
4262 }
4263 cifs_buf_release(pSMB);
4264
4265 if (rc == -EAGAIN)
4266 goto oldQFSInfoRetry;
4267
4268 return rc;
4269}
4270
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271int
Steve French737b7582005-04-28 22:41:06 -07004272CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273{
4274/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4275 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4276 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4277 FILE_SYSTEM_INFO *response_data;
4278 int rc = 0;
4279 int bytes_returned = 0;
4280 __u16 params, byte_count;
4281
4282 cFYI(1, ("In QFSInfo"));
4283QFSInfoRetry:
4284 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4285 (void **) &pSMBr);
4286 if (rc)
4287 return rc;
4288
4289 params = 2; /* level */
4290 pSMB->TotalDataCount = 0;
4291 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004292 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 pSMB->MaxSetupCount = 0;
4294 pSMB->Reserved = 0;
4295 pSMB->Flags = 0;
4296 pSMB->Timeout = 0;
4297 pSMB->Reserved2 = 0;
4298 byte_count = params + 1 /* pad */ ;
4299 pSMB->TotalParameterCount = cpu_to_le16(params);
4300 pSMB->ParameterCount = pSMB->TotalParameterCount;
4301 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004302 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 pSMB->DataCount = 0;
4304 pSMB->DataOffset = 0;
4305 pSMB->SetupCount = 1;
4306 pSMB->Reserved3 = 0;
4307 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4308 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4309 pSMB->hdr.smb_buf_length += byte_count;
4310 pSMB->ByteCount = cpu_to_le16(byte_count);
4311
4312 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4313 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4314 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004315 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004317 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318
Steve French20962432005-09-21 22:05:57 -07004319 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 rc = -EIO; /* bad smb */
4321 else {
4322 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323
4324 response_data =
4325 (FILE_SYSTEM_INFO
4326 *) (((char *) &pSMBr->hdr.Protocol) +
4327 data_offset);
4328 FSData->f_bsize =
4329 le32_to_cpu(response_data->BytesPerSector) *
4330 le32_to_cpu(response_data->
4331 SectorsPerAllocationUnit);
4332 FSData->f_blocks =
4333 le64_to_cpu(response_data->TotalAllocationUnits);
4334 FSData->f_bfree = FSData->f_bavail =
4335 le64_to_cpu(response_data->FreeAllocationUnits);
4336 cFYI(1,
4337 ("Blocks: %lld Free: %lld Block size %ld",
4338 (unsigned long long)FSData->f_blocks,
4339 (unsigned long long)FSData->f_bfree,
4340 FSData->f_bsize));
4341 }
4342 }
4343 cifs_buf_release(pSMB);
4344
4345 if (rc == -EAGAIN)
4346 goto QFSInfoRetry;
4347
4348 return rc;
4349}
4350
4351int
Steve French737b7582005-04-28 22:41:06 -07004352CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353{
4354/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4355 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4356 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4357 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4358 int rc = 0;
4359 int bytes_returned = 0;
4360 __u16 params, byte_count;
4361
4362 cFYI(1, ("In QFSAttributeInfo"));
4363QFSAttributeRetry:
4364 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4365 (void **) &pSMBr);
4366 if (rc)
4367 return rc;
4368
4369 params = 2; /* level */
4370 pSMB->TotalDataCount = 0;
4371 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004372 /* BB find exact max SMB PDU from sess structure BB */
4373 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 pSMB->MaxSetupCount = 0;
4375 pSMB->Reserved = 0;
4376 pSMB->Flags = 0;
4377 pSMB->Timeout = 0;
4378 pSMB->Reserved2 = 0;
4379 byte_count = params + 1 /* pad */ ;
4380 pSMB->TotalParameterCount = cpu_to_le16(params);
4381 pSMB->ParameterCount = pSMB->TotalParameterCount;
4382 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004383 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 pSMB->DataCount = 0;
4385 pSMB->DataOffset = 0;
4386 pSMB->SetupCount = 1;
4387 pSMB->Reserved3 = 0;
4388 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4389 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4390 pSMB->hdr.smb_buf_length += byte_count;
4391 pSMB->ByteCount = cpu_to_le16(byte_count);
4392
4393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4395 if (rc) {
4396 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4397 } else { /* decode response */
4398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4399
Steve French50c2f752007-07-13 00:33:32 +00004400 if (rc || (pSMBr->ByteCount < 13)) {
4401 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 rc = -EIO; /* bad smb */
4403 } else {
4404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4405 response_data =
4406 (FILE_SYSTEM_ATTRIBUTE_INFO
4407 *) (((char *) &pSMBr->hdr.Protocol) +
4408 data_offset);
4409 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004410 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 }
4412 }
4413 cifs_buf_release(pSMB);
4414
4415 if (rc == -EAGAIN)
4416 goto QFSAttributeRetry;
4417
4418 return rc;
4419}
4420
4421int
Steve French737b7582005-04-28 22:41:06 -07004422CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423{
4424/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4425 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4426 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4427 FILE_SYSTEM_DEVICE_INFO *response_data;
4428 int rc = 0;
4429 int bytes_returned = 0;
4430 __u16 params, byte_count;
4431
4432 cFYI(1, ("In QFSDeviceInfo"));
4433QFSDeviceRetry:
4434 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4435 (void **) &pSMBr);
4436 if (rc)
4437 return rc;
4438
4439 params = 2; /* level */
4440 pSMB->TotalDataCount = 0;
4441 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004442 /* BB find exact max SMB PDU from sess structure BB */
4443 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 pSMB->MaxSetupCount = 0;
4445 pSMB->Reserved = 0;
4446 pSMB->Flags = 0;
4447 pSMB->Timeout = 0;
4448 pSMB->Reserved2 = 0;
4449 byte_count = params + 1 /* pad */ ;
4450 pSMB->TotalParameterCount = cpu_to_le16(params);
4451 pSMB->ParameterCount = pSMB->TotalParameterCount;
4452 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004453 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
4455 pSMB->DataCount = 0;
4456 pSMB->DataOffset = 0;
4457 pSMB->SetupCount = 1;
4458 pSMB->Reserved3 = 0;
4459 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4460 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4461 pSMB->hdr.smb_buf_length += byte_count;
4462 pSMB->ByteCount = cpu_to_le16(byte_count);
4463
4464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4466 if (rc) {
4467 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4468 } else { /* decode response */
4469 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4470
Steve French630f3f02007-10-25 21:17:17 +00004471 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 rc = -EIO; /* bad smb */
4473 else {
4474 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4475 response_data =
Steve French737b7582005-04-28 22:41:06 -07004476 (FILE_SYSTEM_DEVICE_INFO *)
4477 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 data_offset);
4479 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004480 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 }
4482 }
4483 cifs_buf_release(pSMB);
4484
4485 if (rc == -EAGAIN)
4486 goto QFSDeviceRetry;
4487
4488 return rc;
4489}
4490
4491int
Steve French737b7582005-04-28 22:41:06 -07004492CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493{
4494/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4495 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4496 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4497 FILE_SYSTEM_UNIX_INFO *response_data;
4498 int rc = 0;
4499 int bytes_returned = 0;
4500 __u16 params, byte_count;
4501
4502 cFYI(1, ("In QFSUnixInfo"));
4503QFSUnixRetry:
4504 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4505 (void **) &pSMBr);
4506 if (rc)
4507 return rc;
4508
4509 params = 2; /* level */
4510 pSMB->TotalDataCount = 0;
4511 pSMB->DataCount = 0;
4512 pSMB->DataOffset = 0;
4513 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004514 /* BB find exact max SMB PDU from sess structure BB */
4515 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 pSMB->MaxSetupCount = 0;
4517 pSMB->Reserved = 0;
4518 pSMB->Flags = 0;
4519 pSMB->Timeout = 0;
4520 pSMB->Reserved2 = 0;
4521 byte_count = params + 1 /* pad */ ;
4522 pSMB->ParameterCount = cpu_to_le16(params);
4523 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004524 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4525 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 pSMB->SetupCount = 1;
4527 pSMB->Reserved3 = 0;
4528 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4529 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4530 pSMB->hdr.smb_buf_length += byte_count;
4531 pSMB->ByteCount = cpu_to_le16(byte_count);
4532
4533 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4534 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4535 if (rc) {
4536 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4537 } else { /* decode response */
4538 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4539
4540 if (rc || (pSMBr->ByteCount < 13)) {
4541 rc = -EIO; /* bad smb */
4542 } else {
4543 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4544 response_data =
4545 (FILE_SYSTEM_UNIX_INFO
4546 *) (((char *) &pSMBr->hdr.Protocol) +
4547 data_offset);
4548 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004549 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550 }
4551 }
4552 cifs_buf_release(pSMB);
4553
4554 if (rc == -EAGAIN)
4555 goto QFSUnixRetry;
4556
4557
4558 return rc;
4559}
4560
Jeremy Allisonac670552005-06-22 17:26:35 -07004561int
Steve French45abc6e2005-06-23 13:42:03 -05004562CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004563{
4564/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4565 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4566 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4567 int rc = 0;
4568 int bytes_returned = 0;
4569 __u16 params, param_offset, offset, byte_count;
4570
4571 cFYI(1, ("In SETFSUnixInfo"));
4572SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004573 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004574 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4575 (void **) &pSMBr);
4576 if (rc)
4577 return rc;
4578
4579 params = 4; /* 2 bytes zero followed by info level. */
4580 pSMB->MaxSetupCount = 0;
4581 pSMB->Reserved = 0;
4582 pSMB->Flags = 0;
4583 pSMB->Timeout = 0;
4584 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004585 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4586 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004587 offset = param_offset + params;
4588
4589 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004590 /* BB find exact max SMB PDU from sess structure BB */
4591 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004592 pSMB->SetupCount = 1;
4593 pSMB->Reserved3 = 0;
4594 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4595 byte_count = 1 /* pad */ + params + 12;
4596
4597 pSMB->DataCount = cpu_to_le16(12);
4598 pSMB->ParameterCount = cpu_to_le16(params);
4599 pSMB->TotalDataCount = pSMB->DataCount;
4600 pSMB->TotalParameterCount = pSMB->ParameterCount;
4601 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4602 pSMB->DataOffset = cpu_to_le16(offset);
4603
4604 /* Params. */
4605 pSMB->FileNum = 0;
4606 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4607
4608 /* Data. */
4609 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4610 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4611 pSMB->ClientUnixCap = cpu_to_le64(cap);
4612
4613 pSMB->hdr.smb_buf_length += byte_count;
4614 pSMB->ByteCount = cpu_to_le16(byte_count);
4615
4616 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4617 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4618 if (rc) {
4619 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4620 } else { /* decode response */
4621 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004622 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004623 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004624 }
4625 cifs_buf_release(pSMB);
4626
4627 if (rc == -EAGAIN)
4628 goto SETFSUnixRetry;
4629
4630 return rc;
4631}
4632
4633
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634
4635int
4636CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004637 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638{
4639/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4640 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4641 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4642 FILE_SYSTEM_POSIX_INFO *response_data;
4643 int rc = 0;
4644 int bytes_returned = 0;
4645 __u16 params, byte_count;
4646
4647 cFYI(1, ("In QFSPosixInfo"));
4648QFSPosixRetry:
4649 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4650 (void **) &pSMBr);
4651 if (rc)
4652 return rc;
4653
4654 params = 2; /* level */
4655 pSMB->TotalDataCount = 0;
4656 pSMB->DataCount = 0;
4657 pSMB->DataOffset = 0;
4658 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004659 /* BB find exact max SMB PDU from sess structure BB */
4660 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 pSMB->MaxSetupCount = 0;
4662 pSMB->Reserved = 0;
4663 pSMB->Flags = 0;
4664 pSMB->Timeout = 0;
4665 pSMB->Reserved2 = 0;
4666 byte_count = params + 1 /* pad */ ;
4667 pSMB->ParameterCount = cpu_to_le16(params);
4668 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004669 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4670 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 pSMB->SetupCount = 1;
4672 pSMB->Reserved3 = 0;
4673 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4674 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4675 pSMB->hdr.smb_buf_length += byte_count;
4676 pSMB->ByteCount = cpu_to_le16(byte_count);
4677
4678 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4679 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4680 if (rc) {
4681 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4682 } else { /* decode response */
4683 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4684
4685 if (rc || (pSMBr->ByteCount < 13)) {
4686 rc = -EIO; /* bad smb */
4687 } else {
4688 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4689 response_data =
4690 (FILE_SYSTEM_POSIX_INFO
4691 *) (((char *) &pSMBr->hdr.Protocol) +
4692 data_offset);
4693 FSData->f_bsize =
4694 le32_to_cpu(response_data->BlockSize);
4695 FSData->f_blocks =
4696 le64_to_cpu(response_data->TotalBlocks);
4697 FSData->f_bfree =
4698 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004699 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700 FSData->f_bavail = FSData->f_bfree;
4701 } else {
4702 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004703 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 }
Steve French790fe572007-07-07 19:25:05 +00004705 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004707 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004708 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004710 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 }
4712 }
4713 cifs_buf_release(pSMB);
4714
4715 if (rc == -EAGAIN)
4716 goto QFSPosixRetry;
4717
4718 return rc;
4719}
4720
4721
Steve French50c2f752007-07-13 00:33:32 +00004722/* We can not use write of zero bytes trick to
4723 set file size due to need for large file support. Also note that
4724 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 routine which is only needed to work around a sharing violation bug
4726 in Samba which this routine can run into */
4727
4728int
4729CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004730 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004731 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732{
4733 struct smb_com_transaction2_spi_req *pSMB = NULL;
4734 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4735 struct file_end_of_file_info *parm_data;
4736 int name_len;
4737 int rc = 0;
4738 int bytes_returned = 0;
4739 __u16 params, byte_count, data_count, param_offset, offset;
4740
4741 cFYI(1, ("In SetEOF"));
4742SetEOFRetry:
4743 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4744 (void **) &pSMBr);
4745 if (rc)
4746 return rc;
4747
4748 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4749 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004750 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004751 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 name_len++; /* trailing null */
4753 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004754 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 name_len = strnlen(fileName, PATH_MAX);
4756 name_len++; /* trailing null */
4757 strncpy(pSMB->FileName, fileName, name_len);
4758 }
4759 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004760 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004762 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 pSMB->MaxSetupCount = 0;
4764 pSMB->Reserved = 0;
4765 pSMB->Flags = 0;
4766 pSMB->Timeout = 0;
4767 pSMB->Reserved2 = 0;
4768 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004769 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004771 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004772 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4773 pSMB->InformationLevel =
4774 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4775 else
4776 pSMB->InformationLevel =
4777 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4778 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4780 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004781 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 else
4783 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004784 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 }
4786
4787 parm_data =
4788 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4789 offset);
4790 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4791 pSMB->DataOffset = cpu_to_le16(offset);
4792 pSMB->SetupCount = 1;
4793 pSMB->Reserved3 = 0;
4794 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4795 byte_count = 3 /* pad */ + params + data_count;
4796 pSMB->DataCount = cpu_to_le16(data_count);
4797 pSMB->TotalDataCount = pSMB->DataCount;
4798 pSMB->ParameterCount = cpu_to_le16(params);
4799 pSMB->TotalParameterCount = pSMB->ParameterCount;
4800 pSMB->Reserved4 = 0;
4801 pSMB->hdr.smb_buf_length += byte_count;
4802 parm_data->FileSize = cpu_to_le64(size);
4803 pSMB->ByteCount = cpu_to_le16(byte_count);
4804 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4805 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004806 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808
4809 cifs_buf_release(pSMB);
4810
4811 if (rc == -EAGAIN)
4812 goto SetEOFRetry;
4813
4814 return rc;
4815}
4816
4817int
Steve French50c2f752007-07-13 00:33:32 +00004818CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004819 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820{
4821 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 char *data_offset;
4823 struct file_end_of_file_info *parm_data;
4824 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825 __u16 params, param_offset, offset, byte_count, count;
4826
4827 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4828 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004829 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4830
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 if (rc)
4832 return rc;
4833
4834 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4835 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004836
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 params = 6;
4838 pSMB->MaxSetupCount = 0;
4839 pSMB->Reserved = 0;
4840 pSMB->Flags = 0;
4841 pSMB->Timeout = 0;
4842 pSMB->Reserved2 = 0;
4843 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4844 offset = param_offset + params;
4845
Steve French50c2f752007-07-13 00:33:32 +00004846 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
4848 count = sizeof(struct file_end_of_file_info);
4849 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004850 /* BB find exact max SMB PDU from sess structure BB */
4851 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 pSMB->SetupCount = 1;
4853 pSMB->Reserved3 = 0;
4854 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4855 byte_count = 3 /* pad */ + params + count;
4856 pSMB->DataCount = cpu_to_le16(count);
4857 pSMB->ParameterCount = cpu_to_le16(params);
4858 pSMB->TotalDataCount = pSMB->DataCount;
4859 pSMB->TotalParameterCount = pSMB->ParameterCount;
4860 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4861 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004862 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4863 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864 pSMB->DataOffset = cpu_to_le16(offset);
4865 parm_data->FileSize = cpu_to_le64(size);
4866 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004867 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4869 pSMB->InformationLevel =
4870 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4871 else
4872 pSMB->InformationLevel =
4873 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004874 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4876 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004877 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 else
4879 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004880 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 }
4882 pSMB->Reserved4 = 0;
4883 pSMB->hdr.smb_buf_length += byte_count;
4884 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004885 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 if (rc) {
4887 cFYI(1,
4888 ("Send error in SetFileInfo (SetFileSize) = %d",
4889 rc));
4890 }
4891
Steve French50c2f752007-07-13 00:33:32 +00004892 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 since file handle passed in no longer valid */
4894
4895 return rc;
4896}
4897
Steve French50c2f752007-07-13 00:33:32 +00004898/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 an open handle, rather than by pathname - this is awkward due to
4900 potential access conflicts on the open, but it is unavoidable for these
4901 old servers since the only other choice is to go from 100 nanosecond DCE
4902 time and resort to the original setpathinfo level which takes the ancient
4903 DOS time format with 2 second granularity */
4904int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004905CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4906 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907{
4908 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 char *data_offset;
4910 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 __u16 params, param_offset, offset, byte_count, count;
4912
4913 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004914 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4915
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 if (rc)
4917 return rc;
4918
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004919 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4920 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004921
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 params = 6;
4923 pSMB->MaxSetupCount = 0;
4924 pSMB->Reserved = 0;
4925 pSMB->Flags = 0;
4926 pSMB->Timeout = 0;
4927 pSMB->Reserved2 = 0;
4928 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4929 offset = param_offset + params;
4930
Steve French50c2f752007-07-13 00:33:32 +00004931 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932
Steve French26f57362007-08-30 22:09:15 +00004933 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004934 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004935 /* BB find max SMB PDU from sess */
4936 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937 pSMB->SetupCount = 1;
4938 pSMB->Reserved3 = 0;
4939 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4940 byte_count = 3 /* pad */ + params + count;
4941 pSMB->DataCount = cpu_to_le16(count);
4942 pSMB->ParameterCount = cpu_to_le16(params);
4943 pSMB->TotalDataCount = pSMB->DataCount;
4944 pSMB->TotalParameterCount = pSMB->ParameterCount;
4945 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4946 pSMB->DataOffset = cpu_to_le16(offset);
4947 pSMB->Fid = fid;
4948 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4949 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4950 else
4951 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4952 pSMB->Reserved4 = 0;
4953 pSMB->hdr.smb_buf_length += byte_count;
4954 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004955 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004956 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004957 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004958 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004959
Steve French50c2f752007-07-13 00:33:32 +00004960 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 since file handle passed in no longer valid */
4962
4963 return rc;
4964}
4965
Jeff Layton6d22f092008-09-23 11:48:35 -04004966int
4967CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4968 bool delete_file, __u16 fid, __u32 pid_of_opener)
4969{
4970 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4971 char *data_offset;
4972 int rc = 0;
4973 __u16 params, param_offset, offset, byte_count, count;
4974
4975 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4976 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4977
4978 if (rc)
4979 return rc;
4980
4981 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4982 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4983
4984 params = 6;
4985 pSMB->MaxSetupCount = 0;
4986 pSMB->Reserved = 0;
4987 pSMB->Flags = 0;
4988 pSMB->Timeout = 0;
4989 pSMB->Reserved2 = 0;
4990 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4991 offset = param_offset + params;
4992
4993 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4994
4995 count = 1;
4996 pSMB->MaxParameterCount = cpu_to_le16(2);
4997 /* BB find max SMB PDU from sess */
4998 pSMB->MaxDataCount = cpu_to_le16(1000);
4999 pSMB->SetupCount = 1;
5000 pSMB->Reserved3 = 0;
5001 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5002 byte_count = 3 /* pad */ + params + count;
5003 pSMB->DataCount = cpu_to_le16(count);
5004 pSMB->ParameterCount = cpu_to_le16(params);
5005 pSMB->TotalDataCount = pSMB->DataCount;
5006 pSMB->TotalParameterCount = pSMB->ParameterCount;
5007 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5008 pSMB->DataOffset = cpu_to_le16(offset);
5009 pSMB->Fid = fid;
5010 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5011 pSMB->Reserved4 = 0;
5012 pSMB->hdr.smb_buf_length += byte_count;
5013 pSMB->ByteCount = cpu_to_le16(byte_count);
5014 *data_offset = delete_file ? 1 : 0;
5015 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5016 if (rc)
5017 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
5018
5019 return rc;
5020}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021
5022int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005023CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5024 const char *fileName, const FILE_BASIC_INFO *data,
5025 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026{
5027 TRANSACTION2_SPI_REQ *pSMB = NULL;
5028 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5029 int name_len;
5030 int rc = 0;
5031 int bytes_returned = 0;
5032 char *data_offset;
5033 __u16 params, param_offset, offset, byte_count, count;
5034
5035 cFYI(1, ("In SetTimes"));
5036
5037SetTimesRetry:
5038 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5039 (void **) &pSMBr);
5040 if (rc)
5041 return rc;
5042
5043 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5044 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005045 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005046 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 name_len++; /* trailing null */
5048 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005049 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 name_len = strnlen(fileName, PATH_MAX);
5051 name_len++; /* trailing null */
5052 strncpy(pSMB->FileName, fileName, name_len);
5053 }
5054
5055 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005056 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005058 /* BB find max SMB PDU from sess structure BB */
5059 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 pSMB->MaxSetupCount = 0;
5061 pSMB->Reserved = 0;
5062 pSMB->Flags = 0;
5063 pSMB->Timeout = 0;
5064 pSMB->Reserved2 = 0;
5065 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005066 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 offset = param_offset + params;
5068 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5069 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5070 pSMB->DataOffset = cpu_to_le16(offset);
5071 pSMB->SetupCount = 1;
5072 pSMB->Reserved3 = 0;
5073 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5074 byte_count = 3 /* pad */ + params + count;
5075
5076 pSMB->DataCount = cpu_to_le16(count);
5077 pSMB->ParameterCount = cpu_to_le16(params);
5078 pSMB->TotalDataCount = pSMB->DataCount;
5079 pSMB->TotalParameterCount = pSMB->ParameterCount;
5080 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5081 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5082 else
5083 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5084 pSMB->Reserved4 = 0;
5085 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005086 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 pSMB->ByteCount = cpu_to_le16(byte_count);
5088 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5089 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005090 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092
5093 cifs_buf_release(pSMB);
5094
5095 if (rc == -EAGAIN)
5096 goto SetTimesRetry;
5097
5098 return rc;
5099}
5100
5101/* Can not be used to set time stamps yet (due to old DOS time format) */
5102/* Can be used to set attributes */
5103#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5104 handling it anyway and NT4 was what we thought it would be needed for
5105 Do not delete it until we prove whether needed for Win9x though */
5106int
5107CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5108 __u16 dos_attrs, const struct nls_table *nls_codepage)
5109{
5110 SETATTR_REQ *pSMB = NULL;
5111 SETATTR_RSP *pSMBr = NULL;
5112 int rc = 0;
5113 int bytes_returned;
5114 int name_len;
5115
5116 cFYI(1, ("In SetAttrLegacy"));
5117
5118SetAttrLgcyRetry:
5119 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5120 (void **) &pSMBr);
5121 if (rc)
5122 return rc;
5123
5124 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5125 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005126 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 PATH_MAX, nls_codepage);
5128 name_len++; /* trailing null */
5129 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005130 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 name_len = strnlen(fileName, PATH_MAX);
5132 name_len++; /* trailing null */
5133 strncpy(pSMB->fileName, fileName, name_len);
5134 }
5135 pSMB->attr = cpu_to_le16(dos_attrs);
5136 pSMB->BufferFormat = 0x04;
5137 pSMB->hdr.smb_buf_length += name_len + 1;
5138 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5139 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5140 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005141 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005143
5144 cifs_buf_release(pSMB);
5145
5146 if (rc == -EAGAIN)
5147 goto SetAttrLgcyRetry;
5148
5149 return rc;
5150}
5151#endif /* temporarily unneeded SetAttr legacy function */
5152
Jeff Layton654cf142009-07-09 20:02:49 -04005153static void
5154cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5155 const struct cifs_unix_set_info_args *args)
5156{
5157 u64 mode = args->mode;
5158
5159 /*
5160 * Samba server ignores set of file size to zero due to bugs in some
5161 * older clients, but we should be precise - we use SetFileSize to
5162 * set file size and do not want to truncate file size to zero
5163 * accidently as happened on one Samba server beta by putting
5164 * zero instead of -1 here
5165 */
5166 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5167 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5168 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5169 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5170 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5171 data_offset->Uid = cpu_to_le64(args->uid);
5172 data_offset->Gid = cpu_to_le64(args->gid);
5173 /* better to leave device as zero when it is */
5174 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5175 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5176 data_offset->Permissions = cpu_to_le64(mode);
5177
5178 if (S_ISREG(mode))
5179 data_offset->Type = cpu_to_le32(UNIX_FILE);
5180 else if (S_ISDIR(mode))
5181 data_offset->Type = cpu_to_le32(UNIX_DIR);
5182 else if (S_ISLNK(mode))
5183 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5184 else if (S_ISCHR(mode))
5185 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5186 else if (S_ISBLK(mode))
5187 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5188 else if (S_ISFIFO(mode))
5189 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5190 else if (S_ISSOCK(mode))
5191 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5192}
5193
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005195CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5196 const struct cifs_unix_set_info_args *args,
5197 u16 fid, u32 pid_of_opener)
5198{
5199 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5200 FILE_UNIX_BASIC_INFO *data_offset;
5201 int rc = 0;
5202 u16 params, param_offset, offset, byte_count, count;
5203
5204 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5205 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5206
5207 if (rc)
5208 return rc;
5209
5210 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5211 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5212
5213 params = 6;
5214 pSMB->MaxSetupCount = 0;
5215 pSMB->Reserved = 0;
5216 pSMB->Flags = 0;
5217 pSMB->Timeout = 0;
5218 pSMB->Reserved2 = 0;
5219 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5220 offset = param_offset + params;
5221
5222 data_offset = (FILE_UNIX_BASIC_INFO *)
5223 ((char *)(&pSMB->hdr.Protocol) + offset);
5224 count = sizeof(FILE_UNIX_BASIC_INFO);
5225
5226 pSMB->MaxParameterCount = cpu_to_le16(2);
5227 /* BB find max SMB PDU from sess */
5228 pSMB->MaxDataCount = cpu_to_le16(1000);
5229 pSMB->SetupCount = 1;
5230 pSMB->Reserved3 = 0;
5231 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5232 byte_count = 3 /* pad */ + params + count;
5233 pSMB->DataCount = cpu_to_le16(count);
5234 pSMB->ParameterCount = cpu_to_le16(params);
5235 pSMB->TotalDataCount = pSMB->DataCount;
5236 pSMB->TotalParameterCount = pSMB->ParameterCount;
5237 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5238 pSMB->DataOffset = cpu_to_le16(offset);
5239 pSMB->Fid = fid;
5240 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5241 pSMB->Reserved4 = 0;
5242 pSMB->hdr.smb_buf_length += byte_count;
5243 pSMB->ByteCount = cpu_to_le16(byte_count);
5244
5245 cifs_fill_unix_set_info(data_offset, args);
5246
5247 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5248 if (rc)
5249 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5250
5251 /* Note: On -EAGAIN error only caller can retry on handle based calls
5252 since file handle passed in no longer valid */
5253
5254 return rc;
5255}
5256
5257int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005258CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5259 const struct cifs_unix_set_info_args *args,
5260 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261{
5262 TRANSACTION2_SPI_REQ *pSMB = NULL;
5263 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5264 int name_len;
5265 int rc = 0;
5266 int bytes_returned = 0;
5267 FILE_UNIX_BASIC_INFO *data_offset;
5268 __u16 params, param_offset, offset, count, byte_count;
5269
5270 cFYI(1, ("In SetUID/GID/Mode"));
5271setPermsRetry:
5272 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5273 (void **) &pSMBr);
5274 if (rc)
5275 return rc;
5276
5277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5278 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005279 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005280 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005281 name_len++; /* trailing null */
5282 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005283 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 name_len = strnlen(fileName, PATH_MAX);
5285 name_len++; /* trailing null */
5286 strncpy(pSMB->FileName, fileName, name_len);
5287 }
5288
5289 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005290 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005292 /* BB find max SMB PDU from sess structure BB */
5293 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 pSMB->MaxSetupCount = 0;
5295 pSMB->Reserved = 0;
5296 pSMB->Flags = 0;
5297 pSMB->Timeout = 0;
5298 pSMB->Reserved2 = 0;
5299 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005300 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 offset = param_offset + params;
5302 data_offset =
5303 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5304 offset);
5305 memset(data_offset, 0, count);
5306 pSMB->DataOffset = cpu_to_le16(offset);
5307 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5308 pSMB->SetupCount = 1;
5309 pSMB->Reserved3 = 0;
5310 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5311 byte_count = 3 /* pad */ + params + count;
5312 pSMB->ParameterCount = cpu_to_le16(params);
5313 pSMB->DataCount = cpu_to_le16(count);
5314 pSMB->TotalParameterCount = pSMB->ParameterCount;
5315 pSMB->TotalDataCount = pSMB->DataCount;
5316 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5317 pSMB->Reserved4 = 0;
5318 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005319
Jeff Layton654cf142009-07-09 20:02:49 -04005320 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321
5322 pSMB->ByteCount = cpu_to_le16(byte_count);
5323 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5324 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005325 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005327
Steve French0d817bc2008-05-22 02:02:03 +00005328 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 if (rc == -EAGAIN)
5330 goto setPermsRetry;
5331 return rc;
5332}
5333
Steve French50c2f752007-07-13 00:33:32 +00005334int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005335 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005336 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005337 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005338{
5339 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005340 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5341 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005342 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 int bytes_returned;
5344
Steve French50c2f752007-07-13 00:33:32 +00005345 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005347 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348 if (rc)
5349 return rc;
5350
5351 pSMB->TotalParameterCount = 0 ;
5352 pSMB->TotalDataCount = 0;
5353 pSMB->MaxParameterCount = cpu_to_le32(2);
5354 /* BB find exact data count max from sess structure BB */
5355 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005356/* BB VERIFY verify which is correct for above BB */
5357 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5358 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5359
Linus Torvalds1da177e2005-04-16 15:20:36 -07005360 pSMB->MaxSetupCount = 4;
5361 pSMB->Reserved = 0;
5362 pSMB->ParameterOffset = 0;
5363 pSMB->DataCount = 0;
5364 pSMB->DataOffset = 0;
5365 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5366 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5367 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005368 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5370 pSMB->Reserved2 = 0;
5371 pSMB->CompletionFilter = cpu_to_le32(filter);
5372 pSMB->Fid = netfid; /* file handle always le */
5373 pSMB->ByteCount = 0;
5374
5375 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005376 (struct smb_hdr *)pSMBr, &bytes_returned,
5377 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 if (rc) {
5379 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005380 } else {
5381 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005382 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005383 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005384 sizeof(struct dir_notify_req),
5385 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005386 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005387 dnotify_req->Pid = pSMB->hdr.Pid;
5388 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5389 dnotify_req->Mid = pSMB->hdr.Mid;
5390 dnotify_req->Tid = pSMB->hdr.Tid;
5391 dnotify_req->Uid = pSMB->hdr.Uid;
5392 dnotify_req->netfid = netfid;
5393 dnotify_req->pfile = pfile;
5394 dnotify_req->filter = filter;
5395 dnotify_req->multishot = multishot;
5396 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005397 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005398 &GlobalDnotifyReqList);
5399 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005400 } else
Steve French47c786e2005-10-11 20:03:18 -07005401 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 }
5403 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005404 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405}
Jeff Layton31c05192010-02-10 16:18:26 -05005406
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005408/*
5409 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5410 * function used by listxattr and getxattr type calls. When ea_name is set,
5411 * it looks for that attribute name and stuffs that value into the EAData
5412 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5413 * buffer. In both cases, the return value is either the length of the
5414 * resulting data or a negative error code. If EAData is a NULL pointer then
5415 * the data isn't copied to it, but the length is returned.
5416 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417ssize_t
5418CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005419 const unsigned char *searchName, const unsigned char *ea_name,
5420 char *EAData, size_t buf_size,
5421 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422{
5423 /* BB assumes one setup word */
5424 TRANSACTION2_QPI_REQ *pSMB = NULL;
5425 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5426 int rc = 0;
5427 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005428 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005429 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005430 struct fea *temp_fea;
5431 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005432 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005433 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
5435 cFYI(1, ("In Query All EAs path %s", searchName));
5436QAllEAsRetry:
5437 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5438 (void **) &pSMBr);
5439 if (rc)
5440 return rc;
5441
5442 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005443 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005444 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005445 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005446 list_len++; /* trailing null */
5447 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005449 list_len = strnlen(searchName, PATH_MAX);
5450 list_len++; /* trailing null */
5451 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452 }
5453
Jeff Layton6e462b92010-02-10 16:18:26 -05005454 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455 pSMB->TotalDataCount = 0;
5456 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005457 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005458 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 pSMB->MaxSetupCount = 0;
5460 pSMB->Reserved = 0;
5461 pSMB->Flags = 0;
5462 pSMB->Timeout = 0;
5463 pSMB->Reserved2 = 0;
5464 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005465 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005466 pSMB->DataCount = 0;
5467 pSMB->DataOffset = 0;
5468 pSMB->SetupCount = 1;
5469 pSMB->Reserved3 = 0;
5470 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5471 byte_count = params + 1 /* pad */ ;
5472 pSMB->TotalParameterCount = cpu_to_le16(params);
5473 pSMB->ParameterCount = pSMB->TotalParameterCount;
5474 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5475 pSMB->Reserved4 = 0;
5476 pSMB->hdr.smb_buf_length += byte_count;
5477 pSMB->ByteCount = cpu_to_le16(byte_count);
5478
5479 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5480 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5481 if (rc) {
5482 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
Jeff Laytonf0d38682010-02-10 16:18:26 -05005483 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005485
5486
5487 /* BB also check enough total bytes returned */
5488 /* BB we need to improve the validity checking
5489 of these trans2 responses */
5490
5491 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5492 if (rc || (pSMBr->ByteCount < 4)) {
5493 rc = -EIO; /* bad smb */
5494 goto QAllEAsOut;
5495 }
5496
5497 /* check that length of list is not more than bcc */
5498 /* check that each entry does not go beyond length
5499 of list */
5500 /* check that each element of each entry does not
5501 go beyond end of list */
5502 /* validate_trans2_offsets() */
5503 /* BB check if start of smb + data_offset > &bcc+ bcc */
5504
5505 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5506 ea_response_data = (struct fealist *)
5507 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5508
Jeff Layton6e462b92010-02-10 16:18:26 -05005509 list_len = le32_to_cpu(ea_response_data->list_len);
5510 cFYI(1, ("ea length %d", list_len));
5511 if (list_len <= 8) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005512 cFYI(1, ("empty EA list returned from server"));
5513 goto QAllEAsOut;
5514 }
5515
Jeff Layton0cd126b2010-02-10 16:18:26 -05005516 /* make sure list_len doesn't go past end of SMB */
5517 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5518 if ((char *)ea_response_data + list_len > end_of_smb) {
5519 cFYI(1, ("EA list appears to go beyond SMB"));
5520 rc = -EIO;
5521 goto QAllEAsOut;
5522 }
5523
Jeff Laytonf0d38682010-02-10 16:18:26 -05005524 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005525 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005526 temp_fea = ea_response_data->list;
5527 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005528 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005529 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005530 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005531
Jeff Layton6e462b92010-02-10 16:18:26 -05005532 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005533 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005534 /* make sure we can read name_len and value_len */
5535 if (list_len < 0) {
5536 cFYI(1, ("EA entry goes beyond length of list"));
5537 rc = -EIO;
5538 goto QAllEAsOut;
5539 }
5540
5541 name_len = temp_fea->name_len;
5542 value_len = le16_to_cpu(temp_fea->value_len);
5543 list_len -= name_len + 1 + value_len;
5544 if (list_len < 0) {
5545 cFYI(1, ("EA entry goes beyond length of list"));
5546 rc = -EIO;
5547 goto QAllEAsOut;
5548 }
5549
Jeff Layton31c05192010-02-10 16:18:26 -05005550 if (ea_name) {
5551 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5552 temp_ptr += name_len + 1;
5553 rc = value_len;
5554 if (buf_size == 0)
5555 goto QAllEAsOut;
5556 if ((size_t)value_len > buf_size) {
5557 rc = -ERANGE;
5558 goto QAllEAsOut;
5559 }
5560 memcpy(EAData, temp_ptr, value_len);
5561 goto QAllEAsOut;
5562 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005563 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005564 /* account for prefix user. and trailing null */
5565 rc += (5 + 1 + name_len);
5566 if (rc < (int) buf_size) {
5567 memcpy(EAData, "user.", 5);
5568 EAData += 5;
5569 memcpy(EAData, temp_ptr, name_len);
5570 EAData += name_len;
5571 /* null terminate name */
5572 *EAData = 0;
5573 ++EAData;
5574 } else if (buf_size == 0) {
5575 /* skip copy - calc size only */
5576 } else {
5577 /* stop before overrun buffer */
5578 rc = -ERANGE;
5579 break;
5580 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005581 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005582 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005583 temp_fea = (struct fea *)temp_ptr;
5584 }
5585
Jeff Layton31c05192010-02-10 16:18:26 -05005586 /* didn't find the named attribute */
5587 if (ea_name)
5588 rc = -ENODATA;
5589
Jeff Laytonf0d38682010-02-10 16:18:26 -05005590QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005591 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005592 if (rc == -EAGAIN)
5593 goto QAllEAsRetry;
5594
5595 return (ssize_t)rc;
5596}
5597
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598int
5599CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005600 const char *ea_name, const void *ea_value,
5601 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5602 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005603{
5604 struct smb_com_transaction2_spi_req *pSMB = NULL;
5605 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5606 struct fealist *parm_data;
5607 int name_len;
5608 int rc = 0;
5609 int bytes_returned = 0;
5610 __u16 params, param_offset, byte_count, offset, count;
5611
5612 cFYI(1, ("In SetEA"));
5613SetEARetry:
5614 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5615 (void **) &pSMBr);
5616 if (rc)
5617 return rc;
5618
5619 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5620 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005621 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005622 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 name_len++; /* trailing null */
5624 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005625 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626 name_len = strnlen(fileName, PATH_MAX);
5627 name_len++; /* trailing null */
5628 strncpy(pSMB->FileName, fileName, name_len);
5629 }
5630
5631 params = 6 + name_len;
5632
5633 /* done calculating parms using name_len of file name,
5634 now use name_len to calculate length of ea name
5635 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005636 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637 name_len = 0;
5638 else
Steve French50c2f752007-07-13 00:33:32 +00005639 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005640
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005641 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005643 /* BB find max SMB PDU from sess */
5644 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 pSMB->MaxSetupCount = 0;
5646 pSMB->Reserved = 0;
5647 pSMB->Flags = 0;
5648 pSMB->Timeout = 0;
5649 pSMB->Reserved2 = 0;
5650 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005651 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 offset = param_offset + params;
5653 pSMB->InformationLevel =
5654 cpu_to_le16(SMB_SET_FILE_EA);
5655
5656 parm_data =
5657 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5658 offset);
5659 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5660 pSMB->DataOffset = cpu_to_le16(offset);
5661 pSMB->SetupCount = 1;
5662 pSMB->Reserved3 = 0;
5663 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5664 byte_count = 3 /* pad */ + params + count;
5665 pSMB->DataCount = cpu_to_le16(count);
5666 parm_data->list_len = cpu_to_le32(count);
5667 parm_data->list[0].EA_flags = 0;
5668 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005669 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005671 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005672 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005673 parm_data->list[0].name[name_len] = 0;
5674 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5675 /* caller ensures that ea_value_len is less than 64K but
5676 we need to ensure that it fits within the smb */
5677
Steve French50c2f752007-07-13 00:33:32 +00005678 /*BB add length check to see if it would fit in
5679 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005680 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5681 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005682 memcpy(parm_data->list[0].name+name_len+1,
5683 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684
5685 pSMB->TotalDataCount = pSMB->DataCount;
5686 pSMB->ParameterCount = cpu_to_le16(params);
5687 pSMB->TotalParameterCount = pSMB->ParameterCount;
5688 pSMB->Reserved4 = 0;
5689 pSMB->hdr.smb_buf_length += byte_count;
5690 pSMB->ByteCount = cpu_to_le16(byte_count);
5691 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5692 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005693 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005695
5696 cifs_buf_release(pSMB);
5697
5698 if (rc == -EAGAIN)
5699 goto SetEARetry;
5700
5701 return rc;
5702}
5703
5704#endif