blob: e197e1647d5d4c34ccdb16cfe4e6653cf56cfe3c [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 */
173 down(&ses->sesSem);
174 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) {
179 up(&ses->sesSem);
180 goto out;
181 }
182
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
185 up(&ses->sesSem);
186 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 Frencha45443472005-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 Frencha45443472005-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-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 Frenchb815f1e52006-10-02 05:53:29 +0000475 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000476 } else {
Steve Frenchb815f1e52006-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"));
Steve French7c7b25b2006-06-01 19:20:10 +0000503 rc = -EOPNOTSUPP;
504#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 Frenchb815f1e52006-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
Jeff Layton14fbf502008-11-14 13:53:46 -0500703 down(&ses->sesSem);
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) {
709 up(&ses->sesSem);
710 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 Frencha59c6582005-08-17 12:12:19 -0700724 up(&ses->sesSem);
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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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 Frencheda3c0292005-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 Frencheda3c0292005-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 Frencheda3c0292005-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 Frencha45443472005-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 Frencha45443472005-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 French61de8002008-10-30 20:15:22 +00001433 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001434 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001435 return -ECONNABORTED;
1436
Steve French790fe572007-07-07 19:25:05 +00001437 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001438 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001439 else {
Steve French1c955182005-08-30 20:58:07 -07001440 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001441 if ((offset >> 32) > 0) {
1442 /* can not handle big offset for old srv */
1443 return -EIO;
1444 }
1445 }
Steve French1c955182005-08-30 20:58:07 -07001446
1447 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 (void **) &pSMBr);
1449 if (rc)
1450 return rc;
1451 /* tcon and ses pointer are checked in smb_init */
1452 if (tcon->ses->server == NULL)
1453 return -ECONNABORTED;
1454
1455 pSMB->AndXCommand = 0xFF; /* none */
1456 pSMB->Fid = netfid;
1457 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001458 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001459 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001460
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 pSMB->Reserved = 0xFFFFFFFF;
1462 pSMB->WriteMode = 0;
1463 pSMB->Remaining = 0;
1464
Steve French50c2f752007-07-13 00:33:32 +00001465 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 can send more if LARGE_WRITE_X capability returned by the server and if
1467 our buffer is big enough or if we convert to iovecs on socket writes
1468 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001469 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1471 } else {
1472 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1473 & ~0xFF;
1474 }
1475
1476 if (bytes_sent > count)
1477 bytes_sent = count;
1478 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001479 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001480 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001481 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001482 else if (ubuf) {
1483 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 cifs_buf_release(pSMB);
1485 return -EFAULT;
1486 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001487 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 /* No buffer */
1489 cifs_buf_release(pSMB);
1490 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001491 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001492 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001493 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001494 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001495 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001496
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1498 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001499 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001500
Steve French790fe572007-07-07 19:25:05 +00001501 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001502 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001503 else { /* old style write has byte count 4 bytes earlier
1504 so 4 bytes pad */
1505 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001506 (struct smb_com_writex_req *)pSMB;
1507 pSMBW->ByteCount = cpu_to_le16(byte_count);
1508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509
1510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1511 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001512 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 if (rc) {
1514 cFYI(1, ("Send error in write = %d", rc));
1515 *nbytes = 0;
1516 } else {
1517 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1518 *nbytes = (*nbytes) << 16;
1519 *nbytes += le16_to_cpu(pSMBr->Count);
1520 }
1521
1522 cifs_buf_release(pSMB);
1523
Steve French50c2f752007-07-13 00:33:32 +00001524 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 since file handle passed in no longer valid */
1526
1527 return rc;
1528}
1529
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001530int
1531CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001533 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1534 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535{
1536 int rc = -EACCES;
1537 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001538 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001539 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001540 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001542 *nbytes = 0;
1543
Steve French790fe572007-07-07 19:25:05 +00001544 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001545
Steve French4c3130e2008-12-09 00:28:16 +00001546 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001547 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001548 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001549 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001550 if ((offset >> 32) > 0) {
1551 /* can not handle big offset for old srv */
1552 return -EIO;
1553 }
1554 }
Steve French8cc64c62005-10-03 13:49:43 -07001555 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 if (rc)
1557 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 /* tcon and ses pointer are checked in smb_init */
1559 if (tcon->ses->server == NULL)
1560 return -ECONNABORTED;
1561
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001562 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 pSMB->Fid = netfid;
1564 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001565 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001566 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 pSMB->Reserved = 0xFFFFFFFF;
1568 pSMB->WriteMode = 0;
1569 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001570
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001572 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
Steve French3e844692005-10-03 13:37:24 -07001574 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1575 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001576 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001577 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001578 pSMB->hdr.smb_buf_length += count+1;
1579 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001580 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1581 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001582 pSMB->ByteCount = cpu_to_le16(count + 1);
1583 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001584 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001585 (struct smb_com_writex_req *)pSMB;
1586 pSMBW->ByteCount = cpu_to_le16(count + 5);
1587 }
Steve French3e844692005-10-03 13:37:24 -07001588 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001589 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001590 iov[0].iov_len = smb_hdr_len + 4;
1591 else /* wct == 12 pad bigger by four bytes */
1592 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001593
Steve French3e844692005-10-03 13:37:24 -07001594
Steve Frenchec637e32005-12-12 20:53:18 -08001595 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001596 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001597 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001599 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001600 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001601 /* presumably this can not happen, but best to be safe */
1602 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001603 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001604 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001605 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1606 *nbytes = (*nbytes) << 16;
1607 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609
Steve French4b8f9302006-02-26 16:41:18 +00001610/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001611 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001612 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001613 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001614 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615
Steve French50c2f752007-07-13 00:33:32 +00001616 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 since file handle passed in no longer valid */
1618
1619 return rc;
1620}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001621
1622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623int
1624CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1625 const __u16 smb_file_id, const __u64 len,
1626 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001627 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
1629 int rc = 0;
1630 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001631/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 int bytes_returned;
1633 int timeout = 0;
1634 __u16 count;
1635
Steve French4b18f2a2008-04-29 00:06:05 +00001636 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001637 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 if (rc)
1640 return rc;
1641
Steve French790fe572007-07-07 19:25:05 +00001642 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001643 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001645 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001646 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1648 } else {
1649 pSMB->Timeout = 0;
1650 }
1651
1652 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1653 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1654 pSMB->LockType = lockType;
1655 pSMB->AndXCommand = 0xFF; /* none */
1656 pSMB->Fid = smb_file_id; /* netfid stays le */
1657
Steve French790fe572007-07-07 19:25:05 +00001658 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1660 /* BB where to store pid high? */
1661 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1662 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1663 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1664 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1665 count = sizeof(LOCKING_ANDX_RANGE);
1666 } else {
1667 /* oplock break */
1668 count = 0;
1669 }
1670 pSMB->hdr.smb_buf_length += count;
1671 pSMB->ByteCount = cpu_to_le16(count);
1672
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001673 if (waitFlag) {
1674 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001675 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001676 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001677 } else {
Steve French133672e2007-11-13 22:41:37 +00001678 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1679 timeout);
1680 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001681 }
Steve Frencha45443472005-08-24 13:59:35 -07001682 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001683 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
Steve French50c2f752007-07-13 00:33:32 +00001686 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 since file handle passed in no longer valid */
1688 return rc;
1689}
1690
1691int
Steve French08547b02006-02-28 22:39:25 +00001692CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1693 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001694 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001695 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001696{
1697 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1698 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001699 struct cifs_posix_lock *parm_data;
1700 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001701 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001702 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001703 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001704 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001705 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001706
1707 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001708
Steve French790fe572007-07-07 19:25:05 +00001709 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001710 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001711
Steve French08547b02006-02-28 22:39:25 +00001712 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1713
1714 if (rc)
1715 return rc;
1716
1717 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1718
Steve French50c2f752007-07-13 00:33:32 +00001719 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001720 pSMB->MaxSetupCount = 0;
1721 pSMB->Reserved = 0;
1722 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001723 pSMB->Reserved2 = 0;
1724 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1725 offset = param_offset + params;
1726
Steve French08547b02006-02-28 22:39:25 +00001727 count = sizeof(struct cifs_posix_lock);
1728 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001729 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001730 pSMB->SetupCount = 1;
1731 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001732 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001733 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1734 else
1735 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1736 byte_count = 3 /* pad */ + params + count;
1737 pSMB->DataCount = cpu_to_le16(count);
1738 pSMB->ParameterCount = cpu_to_le16(params);
1739 pSMB->TotalDataCount = pSMB->DataCount;
1740 pSMB->TotalParameterCount = pSMB->ParameterCount;
1741 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001742 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001743 (((char *) &pSMB->hdr.Protocol) + offset);
1744
1745 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001746 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001747 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001748 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001749 pSMB->Timeout = cpu_to_le32(-1);
1750 } else
1751 pSMB->Timeout = 0;
1752
Steve French08547b02006-02-28 22:39:25 +00001753 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001754 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001755 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001756
1757 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001758 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001759 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1760 pSMB->Reserved4 = 0;
1761 pSMB->hdr.smb_buf_length += byte_count;
1762 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001763 if (waitFlag) {
1764 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1765 (struct smb_hdr *) pSMBr, &bytes_returned);
1766 } else {
Steve French133672e2007-11-13 22:41:37 +00001767 iov[0].iov_base = (char *)pSMB;
1768 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1769 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1770 &resp_buf_type, timeout);
1771 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1772 not try to free it twice below on exit */
1773 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001774 }
1775
Steve French08547b02006-02-28 22:39:25 +00001776 if (rc) {
1777 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001778 } else if (get_flag) {
1779 /* lock structure can be returned on get */
1780 __u16 data_offset;
1781 __u16 data_count;
1782 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001783
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001784 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1785 rc = -EIO; /* bad smb */
1786 goto plk_err_exit;
1787 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001788 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1789 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001790 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001791 rc = -EIO;
1792 goto plk_err_exit;
1793 }
1794 parm_data = (struct cifs_posix_lock *)
1795 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001796 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001797 pLockData->fl_type = F_UNLCK;
1798 }
Steve French50c2f752007-07-13 00:33:32 +00001799
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001800plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001801 if (pSMB)
1802 cifs_small_buf_release(pSMB);
1803
Steve French133672e2007-11-13 22:41:37 +00001804 if (resp_buf_type == CIFS_SMALL_BUFFER)
1805 cifs_small_buf_release(iov[0].iov_base);
1806 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1807 cifs_buf_release(iov[0].iov_base);
1808
Steve French08547b02006-02-28 22:39:25 +00001809 /* Note: On -EAGAIN error only caller can retry on handle based calls
1810 since file handle passed in no longer valid */
1811
1812 return rc;
1813}
1814
1815
1816int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1818{
1819 int rc = 0;
1820 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 cFYI(1, ("In CIFSSMBClose"));
1822
1823/* do not retry on dead session on close */
1824 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001825 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 return 0;
1827 if (rc)
1828 return rc;
1829
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001831 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001833 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001834 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001836 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 /* EINTR is expected when user ctl-c to kill app */
1838 cERROR(1, ("Send error in Close = %d", rc));
1839 }
1840 }
1841
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001843 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 rc = 0;
1845
1846 return rc;
1847}
1848
1849int
Steve Frenchb298f222009-02-21 21:17:43 +00001850CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1851{
1852 int rc = 0;
1853 FLUSH_REQ *pSMB = NULL;
1854 cFYI(1, ("In CIFSSMBFlush"));
1855
1856 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1857 if (rc)
1858 return rc;
1859
1860 pSMB->FileID = (__u16) smb_file_id;
1861 pSMB->ByteCount = 0;
1862 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1863 cifs_stats_inc(&tcon->num_flushes);
1864 if (rc)
1865 cERROR(1, ("Send error in Flush = %d", rc));
1866
1867 return rc;
1868}
1869
1870int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1872 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001873 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874{
1875 int rc = 0;
1876 RENAME_REQ *pSMB = NULL;
1877 RENAME_RSP *pSMBr = NULL;
1878 int bytes_returned;
1879 int name_len, name_len2;
1880 __u16 count;
1881
1882 cFYI(1, ("In CIFSSMBRename"));
1883renameRetry:
1884 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1885 (void **) &pSMBr);
1886 if (rc)
1887 return rc;
1888
1889 pSMB->BufferFormat = 0x04;
1890 pSMB->SearchAttributes =
1891 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1892 ATTR_DIRECTORY);
1893
1894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1895 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001896 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001897 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 name_len++; /* trailing null */
1899 name_len *= 2;
1900 pSMB->OldFileName[name_len] = 0x04; /* pad */
1901 /* protocol requires ASCII signature byte on Unicode string */
1902 pSMB->OldFileName[name_len + 1] = 0x00;
1903 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001904 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001905 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1907 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001908 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 name_len = strnlen(fromName, PATH_MAX);
1910 name_len++; /* trailing null */
1911 strncpy(pSMB->OldFileName, fromName, name_len);
1912 name_len2 = strnlen(toName, PATH_MAX);
1913 name_len2++; /* trailing null */
1914 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1915 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1916 name_len2++; /* trailing null */
1917 name_len2++; /* signature byte */
1918 }
1919
1920 count = 1 /* 1st signature byte */ + name_len + name_len2;
1921 pSMB->hdr.smb_buf_length += count;
1922 pSMB->ByteCount = cpu_to_le16(count);
1923
1924 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1925 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001926 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001927 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 cifs_buf_release(pSMB);
1931
1932 if (rc == -EAGAIN)
1933 goto renameRetry;
1934
1935 return rc;
1936}
1937
Steve French50c2f752007-07-13 00:33:32 +00001938int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001939 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001940 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941{
1942 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1943 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001944 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 char *data_offset;
1946 char dummy_string[30];
1947 int rc = 0;
1948 int bytes_returned = 0;
1949 int len_of_str;
1950 __u16 params, param_offset, offset, count, byte_count;
1951
1952 cFYI(1, ("Rename to File by handle"));
1953 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1954 (void **) &pSMBr);
1955 if (rc)
1956 return rc;
1957
1958 params = 6;
1959 pSMB->MaxSetupCount = 0;
1960 pSMB->Reserved = 0;
1961 pSMB->Flags = 0;
1962 pSMB->Timeout = 0;
1963 pSMB->Reserved2 = 0;
1964 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1965 offset = param_offset + params;
1966
1967 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1968 rename_info = (struct set_file_rename *) data_offset;
1969 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001970 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 pSMB->SetupCount = 1;
1972 pSMB->Reserved3 = 0;
1973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1974 byte_count = 3 /* pad */ + params;
1975 pSMB->ParameterCount = cpu_to_le16(params);
1976 pSMB->TotalParameterCount = pSMB->ParameterCount;
1977 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1978 pSMB->DataOffset = cpu_to_le16(offset);
1979 /* construct random name ".cifs_tmp<inodenum><mid>" */
1980 rename_info->overwrite = cpu_to_le32(1);
1981 rename_info->root_fid = 0;
1982 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00001983 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001984 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
1985 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001986 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001988 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00001989 target_name, PATH_MAX, nls_codepage,
1990 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 }
1992 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04001993 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 byte_count += count;
1995 pSMB->DataCount = cpu_to_le16(count);
1996 pSMB->TotalDataCount = pSMB->DataCount;
1997 pSMB->Fid = netfid;
1998 pSMB->InformationLevel =
1999 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2000 pSMB->Reserved4 = 0;
2001 pSMB->hdr.smb_buf_length += byte_count;
2002 pSMB->ByteCount = cpu_to_le16(byte_count);
2003 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002004 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002005 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002006 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002007 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002008
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 cifs_buf_release(pSMB);
2010
2011 /* Note: On -EAGAIN error only caller can retry on handle based calls
2012 since file handle passed in no longer valid */
2013
2014 return rc;
2015}
2016
2017int
Steve French50c2f752007-07-13 00:33:32 +00002018CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2019 const __u16 target_tid, const char *toName, const int flags,
2020 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021{
2022 int rc = 0;
2023 COPY_REQ *pSMB = NULL;
2024 COPY_RSP *pSMBr = NULL;
2025 int bytes_returned;
2026 int name_len, name_len2;
2027 __u16 count;
2028
2029 cFYI(1, ("In CIFSSMBCopy"));
2030copyRetry:
2031 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2032 (void **) &pSMBr);
2033 if (rc)
2034 return rc;
2035
2036 pSMB->BufferFormat = 0x04;
2037 pSMB->Tid2 = target_tid;
2038
2039 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2040
2041 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002042 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002043 fromName, PATH_MAX, nls_codepage,
2044 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045 name_len++; /* trailing null */
2046 name_len *= 2;
2047 pSMB->OldFileName[name_len] = 0x04; /* pad */
2048 /* protocol requires ASCII signature byte on Unicode string */
2049 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002050 name_len2 =
2051 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002052 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2054 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002055 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056 name_len = strnlen(fromName, PATH_MAX);
2057 name_len++; /* trailing null */
2058 strncpy(pSMB->OldFileName, fromName, name_len);
2059 name_len2 = strnlen(toName, PATH_MAX);
2060 name_len2++; /* trailing null */
2061 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2062 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2063 name_len2++; /* trailing null */
2064 name_len2++; /* signature byte */
2065 }
2066
2067 count = 1 /* 1st signature byte */ + name_len + name_len2;
2068 pSMB->hdr.smb_buf_length += count;
2069 pSMB->ByteCount = cpu_to_le16(count);
2070
2071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2073 if (rc) {
2074 cFYI(1, ("Send error in copy = %d with %d files copied",
2075 rc, le16_to_cpu(pSMBr->CopyCount)));
2076 }
Steve French0d817bc2008-05-22 02:02:03 +00002077 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078
2079 if (rc == -EAGAIN)
2080 goto copyRetry;
2081
2082 return rc;
2083}
2084
2085int
2086CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2087 const char *fromName, const char *toName,
2088 const struct nls_table *nls_codepage)
2089{
2090 TRANSACTION2_SPI_REQ *pSMB = NULL;
2091 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2092 char *data_offset;
2093 int name_len;
2094 int name_len_target;
2095 int rc = 0;
2096 int bytes_returned = 0;
2097 __u16 params, param_offset, offset, byte_count;
2098
2099 cFYI(1, ("In Symlink Unix style"));
2100createSymLinkRetry:
2101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2102 (void **) &pSMBr);
2103 if (rc)
2104 return rc;
2105
2106 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2107 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002108 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 /* find define for this maxpathcomponent */
2110 , nls_codepage);
2111 name_len++; /* trailing null */
2112 name_len *= 2;
2113
Steve French50c2f752007-07-13 00:33:32 +00002114 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 name_len = strnlen(fromName, PATH_MAX);
2116 name_len++; /* trailing null */
2117 strncpy(pSMB->FileName, fromName, name_len);
2118 }
2119 params = 6 + name_len;
2120 pSMB->MaxSetupCount = 0;
2121 pSMB->Reserved = 0;
2122 pSMB->Flags = 0;
2123 pSMB->Timeout = 0;
2124 pSMB->Reserved2 = 0;
2125 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002126 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 offset = param_offset + params;
2128
2129 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2130 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2131 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002132 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133 /* find define for this maxpathcomponent */
2134 , nls_codepage);
2135 name_len_target++; /* trailing null */
2136 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002137 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 name_len_target = strnlen(toName, PATH_MAX);
2139 name_len_target++; /* trailing null */
2140 strncpy(data_offset, toName, name_len_target);
2141 }
2142
2143 pSMB->MaxParameterCount = cpu_to_le16(2);
2144 /* BB find exact max on data count below from sess */
2145 pSMB->MaxDataCount = cpu_to_le16(1000);
2146 pSMB->SetupCount = 1;
2147 pSMB->Reserved3 = 0;
2148 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2149 byte_count = 3 /* pad */ + params + name_len_target;
2150 pSMB->DataCount = cpu_to_le16(name_len_target);
2151 pSMB->ParameterCount = cpu_to_le16(params);
2152 pSMB->TotalDataCount = pSMB->DataCount;
2153 pSMB->TotalParameterCount = pSMB->ParameterCount;
2154 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2155 pSMB->DataOffset = cpu_to_le16(offset);
2156 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2157 pSMB->Reserved4 = 0;
2158 pSMB->hdr.smb_buf_length += byte_count;
2159 pSMB->ByteCount = cpu_to_le16(byte_count);
2160 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2161 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002162 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002163 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002164 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165
Steve French0d817bc2008-05-22 02:02:03 +00002166 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
2168 if (rc == -EAGAIN)
2169 goto createSymLinkRetry;
2170
2171 return rc;
2172}
2173
2174int
2175CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2176 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002177 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178{
2179 TRANSACTION2_SPI_REQ *pSMB = NULL;
2180 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2181 char *data_offset;
2182 int name_len;
2183 int name_len_target;
2184 int rc = 0;
2185 int bytes_returned = 0;
2186 __u16 params, param_offset, offset, byte_count;
2187
2188 cFYI(1, ("In Create Hard link Unix style"));
2189createHardLinkRetry:
2190 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2191 (void **) &pSMBr);
2192 if (rc)
2193 return rc;
2194
2195 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002196 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002197 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 name_len++; /* trailing null */
2199 name_len *= 2;
2200
Steve French50c2f752007-07-13 00:33:32 +00002201 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 name_len = strnlen(toName, PATH_MAX);
2203 name_len++; /* trailing null */
2204 strncpy(pSMB->FileName, toName, name_len);
2205 }
2206 params = 6 + name_len;
2207 pSMB->MaxSetupCount = 0;
2208 pSMB->Reserved = 0;
2209 pSMB->Flags = 0;
2210 pSMB->Timeout = 0;
2211 pSMB->Reserved2 = 0;
2212 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002213 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 offset = param_offset + params;
2215
2216 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2218 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002219 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002220 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 name_len_target++; /* trailing null */
2222 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002223 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 name_len_target = strnlen(fromName, PATH_MAX);
2225 name_len_target++; /* trailing null */
2226 strncpy(data_offset, fromName, name_len_target);
2227 }
2228
2229 pSMB->MaxParameterCount = cpu_to_le16(2);
2230 /* BB find exact max on data count below from sess*/
2231 pSMB->MaxDataCount = cpu_to_le16(1000);
2232 pSMB->SetupCount = 1;
2233 pSMB->Reserved3 = 0;
2234 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2235 byte_count = 3 /* pad */ + params + name_len_target;
2236 pSMB->ParameterCount = cpu_to_le16(params);
2237 pSMB->TotalParameterCount = pSMB->ParameterCount;
2238 pSMB->DataCount = cpu_to_le16(name_len_target);
2239 pSMB->TotalDataCount = pSMB->DataCount;
2240 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2241 pSMB->DataOffset = cpu_to_le16(offset);
2242 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2243 pSMB->Reserved4 = 0;
2244 pSMB->hdr.smb_buf_length += byte_count;
2245 pSMB->ByteCount = cpu_to_le16(byte_count);
2246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002248 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002249 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
2252 cifs_buf_release(pSMB);
2253 if (rc == -EAGAIN)
2254 goto createHardLinkRetry;
2255
2256 return rc;
2257}
2258
2259int
2260CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2261 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002262 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263{
2264 int rc = 0;
2265 NT_RENAME_REQ *pSMB = NULL;
2266 RENAME_RSP *pSMBr = NULL;
2267 int bytes_returned;
2268 int name_len, name_len2;
2269 __u16 count;
2270
2271 cFYI(1, ("In CIFSCreateHardLink"));
2272winCreateHardLinkRetry:
2273
2274 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2275 (void **) &pSMBr);
2276 if (rc)
2277 return rc;
2278
2279 pSMB->SearchAttributes =
2280 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2281 ATTR_DIRECTORY);
2282 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2283 pSMB->ClusterCount = 0;
2284
2285 pSMB->BufferFormat = 0x04;
2286
2287 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2288 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002289 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002290 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 name_len++; /* trailing null */
2292 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002293
2294 /* protocol specifies ASCII buffer format (0x04) for unicode */
2295 pSMB->OldFileName[name_len] = 0x04;
2296 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002298 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002299 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2301 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002302 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 name_len = strnlen(fromName, PATH_MAX);
2304 name_len++; /* trailing null */
2305 strncpy(pSMB->OldFileName, fromName, name_len);
2306 name_len2 = strnlen(toName, PATH_MAX);
2307 name_len2++; /* trailing null */
2308 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2309 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2310 name_len2++; /* trailing null */
2311 name_len2++; /* signature byte */
2312 }
2313
2314 count = 1 /* string type byte */ + name_len + name_len2;
2315 pSMB->hdr.smb_buf_length += count;
2316 pSMB->ByteCount = cpu_to_le16(count);
2317
2318 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2319 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002320 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002321 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002323
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 cifs_buf_release(pSMB);
2325 if (rc == -EAGAIN)
2326 goto winCreateHardLinkRetry;
2327
2328 return rc;
2329}
2330
2331int
2332CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002333 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 const struct nls_table *nls_codepage)
2335{
2336/* SMB_QUERY_FILE_UNIX_LINK */
2337 TRANSACTION2_QPI_REQ *pSMB = NULL;
2338 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2339 int rc = 0;
2340 int bytes_returned;
2341 int name_len;
2342 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002343 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
2345 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2346
2347querySymLinkRetry:
2348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2349 (void **) &pSMBr);
2350 if (rc)
2351 return rc;
2352
2353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2354 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002355 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2356 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 name_len++; /* trailing null */
2358 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002359 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 name_len = strnlen(searchName, PATH_MAX);
2361 name_len++; /* trailing null */
2362 strncpy(pSMB->FileName, searchName, name_len);
2363 }
2364
2365 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2366 pSMB->TotalDataCount = 0;
2367 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002368 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 pSMB->MaxSetupCount = 0;
2370 pSMB->Reserved = 0;
2371 pSMB->Flags = 0;
2372 pSMB->Timeout = 0;
2373 pSMB->Reserved2 = 0;
2374 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002375 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 pSMB->DataCount = 0;
2377 pSMB->DataOffset = 0;
2378 pSMB->SetupCount = 1;
2379 pSMB->Reserved3 = 0;
2380 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2381 byte_count = params + 1 /* pad */ ;
2382 pSMB->TotalParameterCount = cpu_to_le16(params);
2383 pSMB->ParameterCount = pSMB->TotalParameterCount;
2384 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2385 pSMB->Reserved4 = 0;
2386 pSMB->hdr.smb_buf_length += byte_count;
2387 pSMB->ByteCount = cpu_to_le16(byte_count);
2388
2389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2391 if (rc) {
2392 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2393 } else {
2394 /* decode response */
2395
2396 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002398 if (rc || (pSMBr->ByteCount < 2))
2399 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002401 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002402 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403
Jeff Layton460b9692009-04-30 07:17:56 -04002404 data_start = ((char *) &pSMBr->hdr.Protocol) +
2405 le16_to_cpu(pSMBr->t2.DataOffset);
2406
Steve French0e0d2cf2009-05-01 05:27:32 +00002407 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2408 is_unicode = true;
2409 else
2410 is_unicode = false;
2411
Steve French737b7582005-04-28 22:41:06 -07002412 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002413 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002414 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002415 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002416 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 }
2418 }
2419 cifs_buf_release(pSMB);
2420 if (rc == -EAGAIN)
2421 goto querySymLinkRetry;
2422 return rc;
2423}
2424
Parag Warudkarc9489772007-10-23 18:09:48 +00002425#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002426/* Initialize NT TRANSACT SMB into small smb request buffer.
2427 This assumes that all NT TRANSACTS that we init here have
2428 total parm and data under about 400 bytes (to fit in small cifs
2429 buffer size), which is the case so far, it easily fits. NB:
2430 Setup words themselves and ByteCount
2431 MaxSetupCount (size of returned setup area) and
2432 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002433static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002434smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002435 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002436 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002437{
2438 int rc;
2439 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002440 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002441
2442 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2443 (void **)&pSMB);
2444 if (rc)
2445 return rc;
2446 *ret_buf = (void *)pSMB;
2447 pSMB->Reserved = 0;
2448 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2449 pSMB->TotalDataCount = 0;
2450 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2451 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2452 pSMB->ParameterCount = pSMB->TotalParameterCount;
2453 pSMB->DataCount = pSMB->TotalDataCount;
2454 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2455 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2456 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2457 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2458 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2459 pSMB->SubCommand = cpu_to_le16(sub_command);
2460 return 0;
2461}
2462
2463static int
Steve French50c2f752007-07-13 00:33:32 +00002464validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002465 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002466{
Steve French50c2f752007-07-13 00:33:32 +00002467 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002468 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002469 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002470
Steve French630f3f0c2007-10-25 21:17:17 +00002471 *pdatalen = 0;
2472 *pparmlen = 0;
2473
Steve French790fe572007-07-07 19:25:05 +00002474 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002475 return -EINVAL;
2476
2477 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2478
2479 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002480 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002481 (char *)&pSMBr->ByteCount;
2482
Steve French0a4b92c2006-01-12 15:44:21 -08002483 data_offset = le32_to_cpu(pSMBr->DataOffset);
2484 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002485 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002486 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2487
2488 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2489 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2490
2491 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002492 if (*ppparm > end_of_smb) {
2493 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002494 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002495 } else if (parm_count + *ppparm > end_of_smb) {
2496 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002497 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002498 } else if (*ppdata > end_of_smb) {
2499 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002500 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002501 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002502 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002503 *ppdata, data_count, (data_count + *ppdata),
2504 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002505 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002506 } else if (parm_count + data_count > pSMBr->ByteCount) {
2507 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002508 return -EINVAL;
2509 }
Steve French630f3f0c2007-10-25 21:17:17 +00002510 *pdatalen = data_count;
2511 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002512 return 0;
2513}
2514
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515int
2516CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2517 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002518 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 const struct nls_table *nls_codepage)
2520{
2521 int rc = 0;
2522 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002523 struct smb_com_transaction_ioctl_req *pSMB;
2524 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
2526 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2527 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2528 (void **) &pSMBr);
2529 if (rc)
2530 return rc;
2531
2532 pSMB->TotalParameterCount = 0 ;
2533 pSMB->TotalDataCount = 0;
2534 pSMB->MaxParameterCount = cpu_to_le32(2);
2535 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002536 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2537 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 pSMB->MaxSetupCount = 4;
2539 pSMB->Reserved = 0;
2540 pSMB->ParameterOffset = 0;
2541 pSMB->DataCount = 0;
2542 pSMB->DataOffset = 0;
2543 pSMB->SetupCount = 4;
2544 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2545 pSMB->ParameterCount = pSMB->TotalParameterCount;
2546 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2547 pSMB->IsFsctl = 1; /* FSCTL */
2548 pSMB->IsRootFlag = 0;
2549 pSMB->Fid = fid; /* file handle always le */
2550 pSMB->ByteCount = 0;
2551
2552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2554 if (rc) {
2555 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2556 } else { /* decode response */
2557 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2558 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002559 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 /* BB also check enough total bytes returned */
2561 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002562 goto qreparse_out;
2563 }
2564 if (data_count && (data_count < 2048)) {
2565 char *end_of_smb = 2 /* sizeof byte count */ +
2566 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
Steve Frenchafe48c32009-05-02 05:25:46 +00002568 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002569 (struct reparse_data *)
2570 ((char *)&pSMBr->hdr.Protocol
2571 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002572 if ((char *)reparse_buf >= end_of_smb) {
2573 rc = -EIO;
2574 goto qreparse_out;
2575 }
2576 if ((reparse_buf->LinkNamesBuf +
2577 reparse_buf->TargetNameOffset +
2578 reparse_buf->TargetNameLen) > end_of_smb) {
2579 cFYI(1, ("reparse buf beyond SMB"));
2580 rc = -EIO;
2581 goto qreparse_out;
2582 }
Steve French50c2f752007-07-13 00:33:32 +00002583
Steve Frenchafe48c32009-05-02 05:25:46 +00002584 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2585 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002586 (reparse_buf->LinkNamesBuf +
2587 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002588 buflen,
2589 reparse_buf->TargetNameLen,
2590 nls_codepage, 0);
2591 } else { /* ASCII names */
2592 strncpy(symlinkinfo,
2593 reparse_buf->LinkNamesBuf +
2594 reparse_buf->TargetNameOffset,
2595 min_t(const int, buflen,
2596 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002598 } else {
2599 rc = -EIO;
2600 cFYI(1, ("Invalid return data count on "
2601 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002603 symlinkinfo[buflen] = 0; /* just in case so the caller
2604 does not go off the end of the buffer */
2605 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 }
Steve French989c7e52009-05-02 05:32:20 +00002607
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002609 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610
2611 /* Note: On -EAGAIN error only caller can retry on handle based calls
2612 since file handle passed in no longer valid */
2613
2614 return rc;
2615}
Steve Frenchafe48c32009-05-02 05:25:46 +00002616#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
2618#ifdef CONFIG_CIFS_POSIX
2619
2620/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002621static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2622 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
2624 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002625 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2626 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2627 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2629
2630 return;
2631}
2632
2633/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002634static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2635 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636{
2637 int size = 0;
2638 int i;
2639 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002640 struct cifs_posix_ace *pACE;
2641 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2642 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
2644 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2645 return -EOPNOTSUPP;
2646
Steve French790fe572007-07-07 19:25:05 +00002647 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 count = le16_to_cpu(cifs_acl->access_entry_count);
2649 pACE = &cifs_acl->ace_array[0];
2650 size = sizeof(struct cifs_posix_acl);
2651 size += sizeof(struct cifs_posix_ace) * count;
2652 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002653 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002654 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2655 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 return -EINVAL;
2657 }
Steve French790fe572007-07-07 19:25:05 +00002658 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 count = le16_to_cpu(cifs_acl->access_entry_count);
2660 size = sizeof(struct cifs_posix_acl);
2661 size += sizeof(struct cifs_posix_ace) * count;
2662/* skip past access ACEs to get to default ACEs */
2663 pACE = &cifs_acl->ace_array[count];
2664 count = le16_to_cpu(cifs_acl->default_entry_count);
2665 size += sizeof(struct cifs_posix_ace) * count;
2666 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002667 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 return -EINVAL;
2669 } else {
2670 /* illegal type */
2671 return -EINVAL;
2672 }
2673
2674 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002675 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002676 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002677 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 return -ERANGE;
2679 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002680 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002681 for (i = 0; i < count ; i++) {
2682 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2683 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 }
2685 }
2686 return size;
2687}
2688
Steve French50c2f752007-07-13 00:33:32 +00002689static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2690 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691{
2692 __u16 rc = 0; /* 0 = ACL converted ok */
2693
Steve Frenchff7feac2005-11-15 16:45:16 -08002694 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2695 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002697 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 /* Probably no need to le convert -1 on any arch but can not hurt */
2699 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002700 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002701 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002702 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 return rc;
2704}
2705
2706/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002707static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2708 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709{
2710 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002711 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2712 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 int count;
2714 int i;
2715
Steve French790fe572007-07-07 19:25:05 +00002716 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return 0;
2718
2719 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002720 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002721 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002722 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002723 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002724 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002725 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 return 0;
2727 }
2728 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002729 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002730 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002731 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002732 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 else {
Steve French50c2f752007-07-13 00:33:32 +00002734 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 return 0;
2736 }
Steve French50c2f752007-07-13 00:33:32 +00002737 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2739 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002740 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 /* ACE not converted */
2742 break;
2743 }
2744 }
Steve French790fe572007-07-07 19:25:05 +00002745 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2747 rc += sizeof(struct cifs_posix_acl);
2748 /* BB add check to make sure ACL does not overflow SMB */
2749 }
2750 return rc;
2751}
2752
2753int
2754CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002755 const unsigned char *searchName,
2756 char *acl_inf, const int buflen, const int acl_type,
2757 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758{
2759/* SMB_QUERY_POSIX_ACL */
2760 TRANSACTION2_QPI_REQ *pSMB = NULL;
2761 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2762 int rc = 0;
2763 int bytes_returned;
2764 int name_len;
2765 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002766
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2768
2769queryAclRetry:
2770 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2771 (void **) &pSMBr);
2772 if (rc)
2773 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002774
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2776 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002777 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002778 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 name_len++; /* trailing null */
2780 name_len *= 2;
2781 pSMB->FileName[name_len] = 0;
2782 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002783 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 name_len = strnlen(searchName, PATH_MAX);
2785 name_len++; /* trailing null */
2786 strncpy(pSMB->FileName, searchName, name_len);
2787 }
2788
2789 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2790 pSMB->TotalDataCount = 0;
2791 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002792 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 pSMB->MaxDataCount = cpu_to_le16(4000);
2794 pSMB->MaxSetupCount = 0;
2795 pSMB->Reserved = 0;
2796 pSMB->Flags = 0;
2797 pSMB->Timeout = 0;
2798 pSMB->Reserved2 = 0;
2799 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002800 offsetof(struct smb_com_transaction2_qpi_req,
2801 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 pSMB->DataCount = 0;
2803 pSMB->DataOffset = 0;
2804 pSMB->SetupCount = 1;
2805 pSMB->Reserved3 = 0;
2806 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2807 byte_count = params + 1 /* pad */ ;
2808 pSMB->TotalParameterCount = cpu_to_le16(params);
2809 pSMB->ParameterCount = pSMB->TotalParameterCount;
2810 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2811 pSMB->Reserved4 = 0;
2812 pSMB->hdr.smb_buf_length += byte_count;
2813 pSMB->ByteCount = cpu_to_le16(byte_count);
2814
2815 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2816 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002817 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 if (rc) {
2819 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2820 } else {
2821 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002822
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2824 if (rc || (pSMBr->ByteCount < 2))
2825 /* BB also check enough total bytes returned */
2826 rc = -EIO; /* bad smb */
2827 else {
2828 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2829 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2830 rc = cifs_copy_posix_acl(acl_inf,
2831 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002832 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 }
2834 }
2835 cifs_buf_release(pSMB);
2836 if (rc == -EAGAIN)
2837 goto queryAclRetry;
2838 return rc;
2839}
2840
2841int
2842CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002843 const unsigned char *fileName,
2844 const char *local_acl, const int buflen,
2845 const int acl_type,
2846 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847{
2848 struct smb_com_transaction2_spi_req *pSMB = NULL;
2849 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2850 char *parm_data;
2851 int name_len;
2852 int rc = 0;
2853 int bytes_returned = 0;
2854 __u16 params, byte_count, data_count, param_offset, offset;
2855
2856 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2857setAclRetry:
2858 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002859 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 if (rc)
2861 return rc;
2862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2863 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002864 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002865 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 name_len++; /* trailing null */
2867 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002868 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 name_len = strnlen(fileName, PATH_MAX);
2870 name_len++; /* trailing null */
2871 strncpy(pSMB->FileName, fileName, name_len);
2872 }
2873 params = 6 + name_len;
2874 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002875 /* BB find max SMB size from sess */
2876 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 pSMB->MaxSetupCount = 0;
2878 pSMB->Reserved = 0;
2879 pSMB->Flags = 0;
2880 pSMB->Timeout = 0;
2881 pSMB->Reserved2 = 0;
2882 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002883 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 offset = param_offset + params;
2885 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2886 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2887
2888 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002889 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890
Steve French790fe572007-07-07 19:25:05 +00002891 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 rc = -EOPNOTSUPP;
2893 goto setACLerrorExit;
2894 }
2895 pSMB->DataOffset = cpu_to_le16(offset);
2896 pSMB->SetupCount = 1;
2897 pSMB->Reserved3 = 0;
2898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2899 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2900 byte_count = 3 /* pad */ + params + data_count;
2901 pSMB->DataCount = cpu_to_le16(data_count);
2902 pSMB->TotalDataCount = pSMB->DataCount;
2903 pSMB->ParameterCount = cpu_to_le16(params);
2904 pSMB->TotalParameterCount = pSMB->ParameterCount;
2905 pSMB->Reserved4 = 0;
2906 pSMB->hdr.smb_buf_length += byte_count;
2907 pSMB->ByteCount = cpu_to_le16(byte_count);
2908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002910 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
2913setACLerrorExit:
2914 cifs_buf_release(pSMB);
2915 if (rc == -EAGAIN)
2916 goto setAclRetry;
2917 return rc;
2918}
2919
Steve Frenchf654bac2005-04-28 22:41:04 -07002920/* BB fix tabs in this function FIXME BB */
2921int
2922CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002923 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002924{
Steve French50c2f752007-07-13 00:33:32 +00002925 int rc = 0;
2926 struct smb_t2_qfi_req *pSMB = NULL;
2927 struct smb_t2_qfi_rsp *pSMBr = NULL;
2928 int bytes_returned;
2929 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002930
Steve French790fe572007-07-07 19:25:05 +00002931 cFYI(1, ("In GetExtAttr"));
2932 if (tcon == NULL)
2933 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002934
2935GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002936 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2937 (void **) &pSMBr);
2938 if (rc)
2939 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002940
Steve Frenchad7a2922008-02-07 23:25:02 +00002941 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002942 pSMB->t2.TotalDataCount = 0;
2943 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2944 /* BB find exact max data count below from sess structure BB */
2945 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2946 pSMB->t2.MaxSetupCount = 0;
2947 pSMB->t2.Reserved = 0;
2948 pSMB->t2.Flags = 0;
2949 pSMB->t2.Timeout = 0;
2950 pSMB->t2.Reserved2 = 0;
2951 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2952 Fid) - 4);
2953 pSMB->t2.DataCount = 0;
2954 pSMB->t2.DataOffset = 0;
2955 pSMB->t2.SetupCount = 1;
2956 pSMB->t2.Reserved3 = 0;
2957 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2958 byte_count = params + 1 /* pad */ ;
2959 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2960 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2961 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2962 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002963 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002964 pSMB->hdr.smb_buf_length += byte_count;
2965 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002966
Steve French790fe572007-07-07 19:25:05 +00002967 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2968 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2969 if (rc) {
2970 cFYI(1, ("error %d in GetExtAttr", rc));
2971 } else {
2972 /* decode response */
2973 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2974 if (rc || (pSMBr->ByteCount < 2))
2975 /* BB also check enough total bytes returned */
2976 /* If rc should we check for EOPNOSUPP and
2977 disable the srvino flag? or in caller? */
2978 rc = -EIO; /* bad smb */
2979 else {
2980 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2981 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2982 struct file_chattr_info *pfinfo;
2983 /* BB Do we need a cast or hash here ? */
2984 if (count != 16) {
2985 cFYI(1, ("Illegal size ret in GetExtAttr"));
2986 rc = -EIO;
2987 goto GetExtAttrOut;
2988 }
2989 pfinfo = (struct file_chattr_info *)
2990 (data_offset + (char *) &pSMBr->hdr.Protocol);
2991 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07002992 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00002993 }
2994 }
Steve Frenchf654bac2005-04-28 22:41:04 -07002995GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00002996 cifs_buf_release(pSMB);
2997 if (rc == -EAGAIN)
2998 goto GetExtAttrRetry;
2999 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003000}
3001
Steve Frenchf654bac2005-04-28 22:41:04 -07003002#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003
Steve French297647c2007-10-12 04:11:59 +00003004#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003005/* Get Security Descriptor (by handle) from remote server for a file or dir */
3006int
3007CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003008 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003009{
3010 int rc = 0;
3011 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003012 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003013 struct kvec iov[1];
3014
3015 cFYI(1, ("GetCifsACL"));
3016
Steve French630f3f0c2007-10-25 21:17:17 +00003017 *pbuflen = 0;
3018 *acl_inf = NULL;
3019
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003020 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003021 8 /* parm len */, tcon, (void **) &pSMB);
3022 if (rc)
3023 return rc;
3024
3025 pSMB->MaxParameterCount = cpu_to_le32(4);
3026 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3027 pSMB->MaxSetupCount = 0;
3028 pSMB->Fid = fid; /* file handle always le */
3029 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3030 CIFS_ACL_DACL);
3031 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3032 pSMB->hdr.smb_buf_length += 11;
3033 iov[0].iov_base = (char *)pSMB;
3034 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3035
Steve Frencha761ac52007-10-18 21:45:27 +00003036 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003037 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003038 cifs_stats_inc(&tcon->num_acl_get);
3039 if (rc) {
3040 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3041 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003042 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003043 __u32 parm_len;
3044 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003045 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003046 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003047
3048/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003049 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003050 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003051 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003052 goto qsec_out;
3053 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3054
Steve French630f3f0c2007-10-25 21:17:17 +00003055 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003056
3057 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3058 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003059 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003060 goto qsec_out;
3061 }
3062
3063/* BB check that data area is minimum length and as big as acl_len */
3064
Steve Frenchaf6f4612007-10-16 18:40:37 +00003065 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003066 if (acl_len != *pbuflen) {
3067 cERROR(1, ("acl length %d does not match %d",
3068 acl_len, *pbuflen));
3069 if (*pbuflen > acl_len)
3070 *pbuflen = acl_len;
3071 }
Steve French0a4b92c2006-01-12 15:44:21 -08003072
Steve French630f3f0c2007-10-25 21:17:17 +00003073 /* check if buffer is big enough for the acl
3074 header followed by the smallest SID */
3075 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3076 (*pbuflen >= 64 * 1024)) {
3077 cERROR(1, ("bad acl length %d", *pbuflen));
3078 rc = -EINVAL;
3079 *pbuflen = 0;
3080 } else {
3081 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3082 if (*acl_inf == NULL) {
3083 *pbuflen = 0;
3084 rc = -ENOMEM;
3085 }
3086 memcpy(*acl_inf, pdata, *pbuflen);
3087 }
Steve French0a4b92c2006-01-12 15:44:21 -08003088 }
3089qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003090 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003091 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003092 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003093 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003094/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003095 return rc;
3096}
Steve French97837582007-12-31 07:47:21 +00003097
3098int
3099CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3100 struct cifs_ntsd *pntsd, __u32 acllen)
3101{
3102 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3103 int rc = 0;
3104 int bytes_returned = 0;
3105 SET_SEC_DESC_REQ *pSMB = NULL;
3106 NTRANSACT_RSP *pSMBr = NULL;
3107
3108setCifsAclRetry:
3109 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3110 (void **) &pSMBr);
3111 if (rc)
3112 return (rc);
3113
3114 pSMB->MaxSetupCount = 0;
3115 pSMB->Reserved = 0;
3116
3117 param_count = 8;
3118 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3119 data_count = acllen;
3120 data_offset = param_offset + param_count;
3121 byte_count = 3 /* pad */ + param_count;
3122
3123 pSMB->DataCount = cpu_to_le32(data_count);
3124 pSMB->TotalDataCount = pSMB->DataCount;
3125 pSMB->MaxParameterCount = cpu_to_le32(4);
3126 pSMB->MaxDataCount = cpu_to_le32(16384);
3127 pSMB->ParameterCount = cpu_to_le32(param_count);
3128 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3129 pSMB->TotalParameterCount = pSMB->ParameterCount;
3130 pSMB->DataOffset = cpu_to_le32(data_offset);
3131 pSMB->SetupCount = 0;
3132 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3133 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3134
3135 pSMB->Fid = fid; /* file handle always le */
3136 pSMB->Reserved2 = 0;
3137 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3138
3139 if (pntsd && acllen) {
3140 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3141 (char *) pntsd,
3142 acllen);
3143 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3144
3145 } else
3146 pSMB->hdr.smb_buf_length += byte_count;
3147
3148 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3149 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3150
3151 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3152 if (rc)
3153 cFYI(1, ("Set CIFS ACL returned %d", rc));
3154 cifs_buf_release(pSMB);
3155
3156 if (rc == -EAGAIN)
3157 goto setCifsAclRetry;
3158
3159 return (rc);
3160}
3161
Steve French297647c2007-10-12 04:11:59 +00003162#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003163
Steve French6b8edfe2005-08-23 20:26:03 -07003164/* Legacy Query Path Information call for lookup to old servers such
3165 as Win9x/WinME */
3166int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003167 const unsigned char *searchName,
3168 FILE_ALL_INFO *pFinfo,
3169 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003170{
Steve Frenchad7a2922008-02-07 23:25:02 +00003171 QUERY_INFORMATION_REQ *pSMB;
3172 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003173 int rc = 0;
3174 int bytes_returned;
3175 int name_len;
3176
Steve French50c2f752007-07-13 00:33:32 +00003177 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003178QInfRetry:
3179 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003180 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003181 if (rc)
3182 return rc;
3183
3184 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3185 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003186 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3187 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003188 name_len++; /* trailing null */
3189 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003190 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003191 name_len = strnlen(searchName, PATH_MAX);
3192 name_len++; /* trailing null */
3193 strncpy(pSMB->FileName, searchName, name_len);
3194 }
3195 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003196 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003197 pSMB->hdr.smb_buf_length += (__u16) name_len;
3198 pSMB->ByteCount = cpu_to_le16(name_len);
3199
3200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003202 if (rc) {
3203 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003204 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003205 struct timespec ts;
3206 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003207
3208 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003209 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003210 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003211 ts.tv_nsec = 0;
3212 ts.tv_sec = time;
3213 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003214 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003215 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3216 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003217 pFinfo->AllocationSize =
3218 cpu_to_le64(le32_to_cpu(pSMBr->size));
3219 pFinfo->EndOfFile = pFinfo->AllocationSize;
3220 pFinfo->Attributes =
3221 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003222 } else
3223 rc = -EIO; /* bad buffer passed in */
3224
3225 cifs_buf_release(pSMB);
3226
3227 if (rc == -EAGAIN)
3228 goto QInfRetry;
3229
3230 return rc;
3231}
3232
3233
3234
3235
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236int
3237CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3238 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003239 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003240 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003241 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242{
3243/* level 263 SMB_QUERY_FILE_ALL_INFO */
3244 TRANSACTION2_QPI_REQ *pSMB = NULL;
3245 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3246 int rc = 0;
3247 int bytes_returned;
3248 int name_len;
3249 __u16 params, byte_count;
3250
3251/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3252QPathInfoRetry:
3253 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3254 (void **) &pSMBr);
3255 if (rc)
3256 return rc;
3257
3258 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3259 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003260 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003261 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 name_len++; /* trailing null */
3263 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003264 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 name_len = strnlen(searchName, PATH_MAX);
3266 name_len++; /* trailing null */
3267 strncpy(pSMB->FileName, searchName, name_len);
3268 }
3269
Steve French50c2f752007-07-13 00:33:32 +00003270 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 pSMB->TotalDataCount = 0;
3272 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003273 /* BB find exact max SMB PDU from sess structure BB */
3274 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 pSMB->MaxSetupCount = 0;
3276 pSMB->Reserved = 0;
3277 pSMB->Flags = 0;
3278 pSMB->Timeout = 0;
3279 pSMB->Reserved2 = 0;
3280 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003281 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 pSMB->DataCount = 0;
3283 pSMB->DataOffset = 0;
3284 pSMB->SetupCount = 1;
3285 pSMB->Reserved3 = 0;
3286 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3287 byte_count = params + 1 /* pad */ ;
3288 pSMB->TotalParameterCount = cpu_to_le16(params);
3289 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003290 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003291 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3292 else
3293 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 pSMB->Reserved4 = 0;
3295 pSMB->hdr.smb_buf_length += byte_count;
3296 pSMB->ByteCount = cpu_to_le16(byte_count);
3297
3298 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3299 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3300 if (rc) {
3301 cFYI(1, ("Send error in QPathInfo = %d", rc));
3302 } else { /* decode response */
3303 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3304
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003305 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3306 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003307 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003309 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003310 rc = -EIO; /* 24 or 26 expected but we do not read
3311 last field */
3312 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003313 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003315
3316 /* On legacy responses we do not read the last field,
3317 EAsize, fortunately since it varies by subdialect and
3318 also note it differs on Set vs. Get, ie two bytes or 4
3319 bytes depending but we don't care here */
3320 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003321 size = sizeof(FILE_INFO_STANDARD);
3322 else
3323 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324 memcpy((char *) pFindData,
3325 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003326 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 } else
3328 rc = -ENOMEM;
3329 }
3330 cifs_buf_release(pSMB);
3331 if (rc == -EAGAIN)
3332 goto QPathInfoRetry;
3333
3334 return rc;
3335}
3336
3337int
3338CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3339 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003340 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003341 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342{
3343/* SMB_QUERY_FILE_UNIX_BASIC */
3344 TRANSACTION2_QPI_REQ *pSMB = NULL;
3345 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3346 int rc = 0;
3347 int bytes_returned = 0;
3348 int name_len;
3349 __u16 params, byte_count;
3350
3351 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3352UnixQPathInfoRetry:
3353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3354 (void **) &pSMBr);
3355 if (rc)
3356 return rc;
3357
3358 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3359 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003360 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003361 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 name_len++; /* trailing null */
3363 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003364 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 name_len = strnlen(searchName, PATH_MAX);
3366 name_len++; /* trailing null */
3367 strncpy(pSMB->FileName, searchName, name_len);
3368 }
3369
Steve French50c2f752007-07-13 00:33:32 +00003370 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003371 pSMB->TotalDataCount = 0;
3372 pSMB->MaxParameterCount = cpu_to_le16(2);
3373 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003374 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 pSMB->MaxSetupCount = 0;
3376 pSMB->Reserved = 0;
3377 pSMB->Flags = 0;
3378 pSMB->Timeout = 0;
3379 pSMB->Reserved2 = 0;
3380 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003381 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 pSMB->DataCount = 0;
3383 pSMB->DataOffset = 0;
3384 pSMB->SetupCount = 1;
3385 pSMB->Reserved3 = 0;
3386 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3387 byte_count = params + 1 /* pad */ ;
3388 pSMB->TotalParameterCount = cpu_to_le16(params);
3389 pSMB->ParameterCount = pSMB->TotalParameterCount;
3390 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3391 pSMB->Reserved4 = 0;
3392 pSMB->hdr.smb_buf_length += byte_count;
3393 pSMB->ByteCount = cpu_to_le16(byte_count);
3394
3395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3396 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3397 if (rc) {
3398 cFYI(1, ("Send error in QPathInfo = %d", rc));
3399 } else { /* decode response */
3400 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3401
3402 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003403 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3404 "Unix Extensions can be disabled on mount "
3405 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 rc = -EIO; /* bad smb */
3407 } else {
3408 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3409 memcpy((char *) pFindData,
3410 (char *) &pSMBr->hdr.Protocol +
3411 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003412 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 }
3414 }
3415 cifs_buf_release(pSMB);
3416 if (rc == -EAGAIN)
3417 goto UnixQPathInfoRetry;
3418
3419 return rc;
3420}
3421
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422/* xid, tcon, searchName and codepage are input parms, rest are returned */
3423int
3424CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003425 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003427 __u16 *pnetfid,
3428 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429{
3430/* level 257 SMB_ */
3431 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3432 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003433 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 int rc = 0;
3435 int bytes_returned = 0;
3436 int name_len;
3437 __u16 params, byte_count;
3438
Steve French50c2f752007-07-13 00:33:32 +00003439 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440
3441findFirstRetry:
3442 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3443 (void **) &pSMBr);
3444 if (rc)
3445 return rc;
3446
3447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3448 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003449 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003450 PATH_MAX, nls_codepage, remap);
3451 /* We can not add the asterik earlier in case
3452 it got remapped to 0xF03A as if it were part of the
3453 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003455 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003456 pSMB->FileName[name_len+1] = 0;
3457 pSMB->FileName[name_len+2] = '*';
3458 pSMB->FileName[name_len+3] = 0;
3459 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3461 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003462 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 } else { /* BB add check for overrun of SMB buf BB */
3464 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003466 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 free buffer exit; BB */
3468 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003469 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003470 pSMB->FileName[name_len+1] = '*';
3471 pSMB->FileName[name_len+2] = 0;
3472 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 }
3474
3475 params = 12 + name_len /* includes null */ ;
3476 pSMB->TotalDataCount = 0; /* no EAs */
3477 pSMB->MaxParameterCount = cpu_to_le16(10);
3478 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3479 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482 pSMB->Flags = 0;
3483 pSMB->Timeout = 0;
3484 pSMB->Reserved2 = 0;
3485 byte_count = params + 1 /* pad */ ;
3486 pSMB->TotalParameterCount = cpu_to_le16(params);
3487 pSMB->ParameterCount = pSMB->TotalParameterCount;
3488 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003489 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3490 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 pSMB->DataCount = 0;
3492 pSMB->DataOffset = 0;
3493 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3494 pSMB->Reserved3 = 0;
3495 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3496 pSMB->SearchAttributes =
3497 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3498 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003499 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3500 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 CIFS_SEARCH_RETURN_RESUME);
3502 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3503
3504 /* BB what should we set StorageType to? Does it matter? BB */
3505 pSMB->SearchStorageType = 0;
3506 pSMB->hdr.smb_buf_length += byte_count;
3507 pSMB->ByteCount = cpu_to_le16(byte_count);
3508
3509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003511 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512
Steve French88274812006-03-09 22:21:45 +00003513 if (rc) {/* BB add logic to retry regular search if Unix search
3514 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 /* BB Add code to handle unsupported level rc */
3516 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003517
Steve French88274812006-03-09 22:21:45 +00003518 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
3520 /* BB eventually could optimize out free and realloc of buf */
3521 /* for this case */
3522 if (rc == -EAGAIN)
3523 goto findFirstRetry;
3524 } else { /* decode response */
3525 /* BB remember to free buffer if error BB */
3526 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003527 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003528 unsigned int lnoff;
3529
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003531 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 else
Steve French4b18f2a2008-04-29 00:06:05 +00003533 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
3535 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003536 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003537 psrch_inf->srch_entries_start =
3538 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3541 le16_to_cpu(pSMBr->t2.ParameterOffset));
3542
Steve French790fe572007-07-07 19:25:05 +00003543 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003544 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545 else
Steve French4b18f2a2008-04-29 00:06:05 +00003546 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547
Steve French50c2f752007-07-13 00:33:32 +00003548 psrch_inf->entries_in_buffer =
3549 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003550 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003552 lnoff = le16_to_cpu(parms->LastNameOffset);
3553 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3554 lnoff) {
3555 cERROR(1, ("ignoring corrupt resume name"));
3556 psrch_inf->last_entry = NULL;
3557 return rc;
3558 }
3559
Steve French0752f152008-10-07 20:03:33 +00003560 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003561 lnoff;
3562
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563 *pnetfid = parms->SearchHandle;
3564 } else {
3565 cifs_buf_release(pSMB);
3566 }
3567 }
3568
3569 return rc;
3570}
3571
3572int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003573 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574{
3575 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3576 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003577 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003578 char *response_data;
3579 int rc = 0;
3580 int bytes_returned, name_len;
3581 __u16 params, byte_count;
3582
3583 cFYI(1, ("In FindNext"));
3584
Steve French4b18f2a2008-04-29 00:06:05 +00003585 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 return -ENOENT;
3587
3588 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3589 (void **) &pSMBr);
3590 if (rc)
3591 return rc;
3592
Steve French50c2f752007-07-13 00:33:32 +00003593 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594 byte_count = 0;
3595 pSMB->TotalDataCount = 0; /* no EAs */
3596 pSMB->MaxParameterCount = cpu_to_le16(8);
3597 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003598 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3599 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 pSMB->MaxSetupCount = 0;
3601 pSMB->Reserved = 0;
3602 pSMB->Flags = 0;
3603 pSMB->Timeout = 0;
3604 pSMB->Reserved2 = 0;
3605 pSMB->ParameterOffset = cpu_to_le16(
3606 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3607 pSMB->DataCount = 0;
3608 pSMB->DataOffset = 0;
3609 pSMB->SetupCount = 1;
3610 pSMB->Reserved3 = 0;
3611 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3612 pSMB->SearchHandle = searchHandle; /* always kept as le */
3613 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003614 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3616 pSMB->ResumeKey = psrch_inf->resume_key;
3617 pSMB->SearchFlags =
3618 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3619
3620 name_len = psrch_inf->resume_name_len;
3621 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003622 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3624 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003625 /* 14 byte parm len above enough for 2 byte null terminator */
3626 pSMB->ResumeFileName[name_len] = 0;
3627 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 } else {
3629 rc = -EINVAL;
3630 goto FNext2_err_exit;
3631 }
3632 byte_count = params + 1 /* pad */ ;
3633 pSMB->TotalParameterCount = cpu_to_le16(params);
3634 pSMB->ParameterCount = pSMB->TotalParameterCount;
3635 pSMB->hdr.smb_buf_length += byte_count;
3636 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003637
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3639 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003640 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641 if (rc) {
3642 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003643 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003644 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003645 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003646 } else
3647 cFYI(1, ("FindNext returned = %d", rc));
3648 } else { /* decode response */
3649 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003650
Steve French790fe572007-07-07 19:25:05 +00003651 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003652 unsigned int lnoff;
3653
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654 /* BB fixme add lock for file (srch_info) struct here */
3655 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003656 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 else
Steve French4b18f2a2008-04-29 00:06:05 +00003658 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 response_data = (char *) &pSMBr->hdr.Protocol +
3660 le16_to_cpu(pSMBr->t2.ParameterOffset);
3661 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3662 response_data = (char *)&pSMBr->hdr.Protocol +
3663 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003664 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003665 cifs_small_buf_release(
3666 psrch_inf->ntwrk_buf_start);
3667 else
3668 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 psrch_inf->srch_entries_start = response_data;
3670 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003671 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003672 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003673 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 else
Steve French4b18f2a2008-04-29 00:06:05 +00003675 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003676 psrch_inf->entries_in_buffer =
3677 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 psrch_inf->index_of_last_entry +=
3679 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003680 lnoff = le16_to_cpu(parms->LastNameOffset);
3681 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3682 lnoff) {
3683 cERROR(1, ("ignoring corrupt resume name"));
3684 psrch_inf->last_entry = NULL;
3685 return rc;
3686 } else
3687 psrch_inf->last_entry =
3688 psrch_inf->srch_entries_start + lnoff;
3689
Steve French50c2f752007-07-13 00:33:32 +00003690/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3691 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692
3693 /* BB fixme add unlock here */
3694 }
3695
3696 }
3697
3698 /* BB On error, should we leave previous search buf (and count and
3699 last entry fields) intact or free the previous one? */
3700
3701 /* Note: On -EAGAIN error only caller can retry on handle based calls
3702 since file handle passed in no longer valid */
3703FNext2_err_exit:
3704 if (rc != 0)
3705 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 return rc;
3707}
3708
3709int
Steve French50c2f752007-07-13 00:33:32 +00003710CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3711 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712{
3713 int rc = 0;
3714 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715
3716 cFYI(1, ("In CIFSSMBFindClose"));
3717 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3718
3719 /* no sense returning error if session restarted
3720 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003721 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003722 return 0;
3723 if (rc)
3724 return rc;
3725
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 pSMB->FileID = searchHandle;
3727 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003728 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003729 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003731
Steve Frencha45443472005-08-24 13:59:35 -07003732 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733
3734 /* Since session is dead, search handle closed on server already */
3735 if (rc == -EAGAIN)
3736 rc = 0;
3737
3738 return rc;
3739}
3740
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741int
3742CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003743 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003744 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003745 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746{
3747 int rc = 0;
3748 TRANSACTION2_QPI_REQ *pSMB = NULL;
3749 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3750 int name_len, bytes_returned;
3751 __u16 params, byte_count;
3752
Steve French50c2f752007-07-13 00:33:32 +00003753 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003754 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003755 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756
3757GetInodeNumberRetry:
3758 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003759 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 if (rc)
3761 return rc;
3762
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3764 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003765 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003766 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 name_len++; /* trailing null */
3768 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003769 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 name_len = strnlen(searchName, PATH_MAX);
3771 name_len++; /* trailing null */
3772 strncpy(pSMB->FileName, searchName, name_len);
3773 }
3774
3775 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3776 pSMB->TotalDataCount = 0;
3777 pSMB->MaxParameterCount = cpu_to_le16(2);
3778 /* BB find exact max data count below from sess structure BB */
3779 pSMB->MaxDataCount = cpu_to_le16(4000);
3780 pSMB->MaxSetupCount = 0;
3781 pSMB->Reserved = 0;
3782 pSMB->Flags = 0;
3783 pSMB->Timeout = 0;
3784 pSMB->Reserved2 = 0;
3785 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003786 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 pSMB->DataCount = 0;
3788 pSMB->DataOffset = 0;
3789 pSMB->SetupCount = 1;
3790 pSMB->Reserved3 = 0;
3791 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3792 byte_count = params + 1 /* pad */ ;
3793 pSMB->TotalParameterCount = cpu_to_le16(params);
3794 pSMB->ParameterCount = pSMB->TotalParameterCount;
3795 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3796 pSMB->Reserved4 = 0;
3797 pSMB->hdr.smb_buf_length += byte_count;
3798 pSMB->ByteCount = cpu_to_le16(byte_count);
3799
3800 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3801 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3802 if (rc) {
3803 cFYI(1, ("error %d in QueryInternalInfo", rc));
3804 } else {
3805 /* decode response */
3806 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3807 if (rc || (pSMBr->ByteCount < 2))
3808 /* BB also check enough total bytes returned */
3809 /* If rc should we check for EOPNOSUPP and
3810 disable the srvino flag? or in caller? */
3811 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003812 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3814 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003815 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003817 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3819 rc = -EIO;
3820 goto GetInodeNumOut;
3821 }
3822 pfinfo = (struct file_internal_info *)
3823 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003824 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825 }
3826 }
3827GetInodeNumOut:
3828 cifs_buf_release(pSMB);
3829 if (rc == -EAGAIN)
3830 goto GetInodeNumberRetry;
3831 return rc;
3832}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
Igor Mammedovfec45852008-05-16 13:06:30 +04003834/* parses DFS refferal V3 structure
3835 * caller is responsible for freeing target_nodes
3836 * returns:
3837 * on success - 0
3838 * on failure - errno
3839 */
3840static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003841parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003842 unsigned int *num_of_nodes,
3843 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003844 const struct nls_table *nls_codepage, int remap,
3845 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003846{
3847 int i, rc = 0;
3848 char *data_end;
3849 bool is_unicode;
3850 struct dfs_referral_level_3 *ref;
3851
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003852 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3853 is_unicode = true;
3854 else
3855 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003856 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3857
3858 if (*num_of_nodes < 1) {
3859 cERROR(1, ("num_referrals: must be at least > 0,"
3860 "but we get num_referrals = %d\n", *num_of_nodes));
3861 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003862 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003863 }
3864
3865 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003866 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003867 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003868 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003869 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003870 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003871 }
3872
3873 /* get the upper boundary of the resp buffer */
3874 data_end = (char *)(&(pSMBr->PathConsumed)) +
3875 le16_to_cpu(pSMBr->t2.DataCount);
3876
3877 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3878 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00003879 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003880
3881 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3882 *num_of_nodes, GFP_KERNEL);
3883 if (*target_nodes == NULL) {
3884 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3885 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003886 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003887 }
3888
3889 /* collect neccessary data from referrals */
3890 for (i = 0; i < *num_of_nodes; i++) {
3891 char *temp;
3892 int max_len;
3893 struct dfs_info3_param *node = (*target_nodes)+i;
3894
Steve French0e0d2cf2009-05-01 05:27:32 +00003895 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003896 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003897 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3898 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00003899 if (tmp == NULL) {
3900 rc = -ENOMEM;
3901 goto parse_DFS_referrals_exit;
3902 }
Igor Mammedov2c556082008-10-23 13:58:42 +04003903 cifsConvertToUCS((__le16 *) tmp, searchName,
3904 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003905 node->path_consumed = cifs_ucs2_bytes(tmp,
3906 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04003907 nls_codepage);
3908 kfree(tmp);
3909 } else
3910 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3911
Igor Mammedovfec45852008-05-16 13:06:30 +04003912 node->server_type = le16_to_cpu(ref->ServerType);
3913 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3914
3915 /* copy DfsPath */
3916 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3917 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003918 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3919 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003920 if (!node->path_name) {
3921 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003922 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003923 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003924
3925 /* copy link target UNC */
3926 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3927 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003928 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3929 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003930 if (!node->node_name)
3931 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04003932 }
3933
Steve Frencha1fe78f2008-05-16 18:48:38 +00003934parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04003935 if (rc) {
3936 free_dfs_info_array(*target_nodes, *num_of_nodes);
3937 *target_nodes = NULL;
3938 *num_of_nodes = 0;
3939 }
3940 return rc;
3941}
3942
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943int
3944CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3945 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003946 struct dfs_info3_param **target_nodes,
3947 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07003948 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949{
3950/* TRANS2_GET_DFS_REFERRAL */
3951 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3952 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 int rc = 0;
3954 int bytes_returned;
3955 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003957 *num_of_nodes = 0;
3958 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959
3960 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3961 if (ses == NULL)
3962 return -ENODEV;
3963getDFSRetry:
3964 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3965 (void **) &pSMBr);
3966 if (rc)
3967 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003968
3969 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003970 but should never be null here anyway */
3971 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 pSMB->hdr.Tid = ses->ipc_tid;
3973 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003974 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003976 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978
3979 if (ses->capabilities & CAP_UNICODE) {
3980 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3981 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003982 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003983 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 name_len++; /* trailing null */
3985 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003986 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 name_len = strnlen(searchName, PATH_MAX);
3988 name_len++; /* trailing null */
3989 strncpy(pSMB->RequestFileName, searchName, name_len);
3990 }
3991
Steve French790fe572007-07-07 19:25:05 +00003992 if (ses->server) {
3993 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003994 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3995 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3996 }
3997
Steve French50c2f752007-07-13 00:33:32 +00003998 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003999
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 params = 2 /* level */ + name_len /*includes null */ ;
4001 pSMB->TotalDataCount = 0;
4002 pSMB->DataCount = 0;
4003 pSMB->DataOffset = 0;
4004 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004005 /* BB find exact max SMB PDU from sess structure BB */
4006 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 pSMB->MaxSetupCount = 0;
4008 pSMB->Reserved = 0;
4009 pSMB->Flags = 0;
4010 pSMB->Timeout = 0;
4011 pSMB->Reserved2 = 0;
4012 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004013 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 pSMB->SetupCount = 1;
4015 pSMB->Reserved3 = 0;
4016 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4017 byte_count = params + 3 /* pad */ ;
4018 pSMB->ParameterCount = cpu_to_le16(params);
4019 pSMB->TotalParameterCount = pSMB->ParameterCount;
4020 pSMB->MaxReferralLevel = cpu_to_le16(3);
4021 pSMB->hdr.smb_buf_length += byte_count;
4022 pSMB->ByteCount = cpu_to_le16(byte_count);
4023
4024 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4026 if (rc) {
4027 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004028 goto GetDFSRefExit;
4029 }
4030 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004032 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004033 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004034 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004035 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004037
4038 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4039 pSMBr->ByteCount,
4040 le16_to_cpu(pSMBr->t2.DataOffset)));
4041
4042 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004043 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004044 target_nodes, nls_codepage, remap,
4045 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004046
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004048 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049
4050 if (rc == -EAGAIN)
4051 goto getDFSRetry;
4052
4053 return rc;
4054}
4055
Steve French20962432005-09-21 22:05:57 -07004056/* Query File System Info such as free space to old servers such as Win 9x */
4057int
4058SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4059{
4060/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4061 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4062 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4063 FILE_SYSTEM_ALLOC_INFO *response_data;
4064 int rc = 0;
4065 int bytes_returned = 0;
4066 __u16 params, byte_count;
4067
4068 cFYI(1, ("OldQFSInfo"));
4069oldQFSInfoRetry:
4070 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4071 (void **) &pSMBr);
4072 if (rc)
4073 return rc;
Steve French20962432005-09-21 22:05:57 -07004074
4075 params = 2; /* level */
4076 pSMB->TotalDataCount = 0;
4077 pSMB->MaxParameterCount = cpu_to_le16(2);
4078 pSMB->MaxDataCount = cpu_to_le16(1000);
4079 pSMB->MaxSetupCount = 0;
4080 pSMB->Reserved = 0;
4081 pSMB->Flags = 0;
4082 pSMB->Timeout = 0;
4083 pSMB->Reserved2 = 0;
4084 byte_count = params + 1 /* pad */ ;
4085 pSMB->TotalParameterCount = cpu_to_le16(params);
4086 pSMB->ParameterCount = pSMB->TotalParameterCount;
4087 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4088 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4089 pSMB->DataCount = 0;
4090 pSMB->DataOffset = 0;
4091 pSMB->SetupCount = 1;
4092 pSMB->Reserved3 = 0;
4093 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4094 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4095 pSMB->hdr.smb_buf_length += byte_count;
4096 pSMB->ByteCount = cpu_to_le16(byte_count);
4097
4098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4100 if (rc) {
4101 cFYI(1, ("Send error in QFSInfo = %d", rc));
4102 } else { /* decode response */
4103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4104
4105 if (rc || (pSMBr->ByteCount < 18))
4106 rc = -EIO; /* bad smb */
4107 else {
4108 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004109 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004110 pSMBr->ByteCount, data_offset));
4111
Steve French50c2f752007-07-13 00:33:32 +00004112 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004113 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4114 FSData->f_bsize =
4115 le16_to_cpu(response_data->BytesPerSector) *
4116 le32_to_cpu(response_data->
4117 SectorsPerAllocationUnit);
4118 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004119 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004120 FSData->f_bfree = FSData->f_bavail =
4121 le32_to_cpu(response_data->FreeAllocationUnits);
4122 cFYI(1,
4123 ("Blocks: %lld Free: %lld Block size %ld",
4124 (unsigned long long)FSData->f_blocks,
4125 (unsigned long long)FSData->f_bfree,
4126 FSData->f_bsize));
4127 }
4128 }
4129 cifs_buf_release(pSMB);
4130
4131 if (rc == -EAGAIN)
4132 goto oldQFSInfoRetry;
4133
4134 return rc;
4135}
4136
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137int
Steve French737b7582005-04-28 22:41:06 -07004138CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139{
4140/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4141 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4142 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4143 FILE_SYSTEM_INFO *response_data;
4144 int rc = 0;
4145 int bytes_returned = 0;
4146 __u16 params, byte_count;
4147
4148 cFYI(1, ("In QFSInfo"));
4149QFSInfoRetry:
4150 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4151 (void **) &pSMBr);
4152 if (rc)
4153 return rc;
4154
4155 params = 2; /* level */
4156 pSMB->TotalDataCount = 0;
4157 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004158 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 pSMB->MaxSetupCount = 0;
4160 pSMB->Reserved = 0;
4161 pSMB->Flags = 0;
4162 pSMB->Timeout = 0;
4163 pSMB->Reserved2 = 0;
4164 byte_count = params + 1 /* pad */ ;
4165 pSMB->TotalParameterCount = cpu_to_le16(params);
4166 pSMB->ParameterCount = pSMB->TotalParameterCount;
4167 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004168 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 pSMB->DataCount = 0;
4170 pSMB->DataOffset = 0;
4171 pSMB->SetupCount = 1;
4172 pSMB->Reserved3 = 0;
4173 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4174 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4175 pSMB->hdr.smb_buf_length += byte_count;
4176 pSMB->ByteCount = cpu_to_le16(byte_count);
4177
4178 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4179 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4180 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004181 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004183 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
Steve French20962432005-09-21 22:05:57 -07004185 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 rc = -EIO; /* bad smb */
4187 else {
4188 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189
4190 response_data =
4191 (FILE_SYSTEM_INFO
4192 *) (((char *) &pSMBr->hdr.Protocol) +
4193 data_offset);
4194 FSData->f_bsize =
4195 le32_to_cpu(response_data->BytesPerSector) *
4196 le32_to_cpu(response_data->
4197 SectorsPerAllocationUnit);
4198 FSData->f_blocks =
4199 le64_to_cpu(response_data->TotalAllocationUnits);
4200 FSData->f_bfree = FSData->f_bavail =
4201 le64_to_cpu(response_data->FreeAllocationUnits);
4202 cFYI(1,
4203 ("Blocks: %lld Free: %lld Block size %ld",
4204 (unsigned long long)FSData->f_blocks,
4205 (unsigned long long)FSData->f_bfree,
4206 FSData->f_bsize));
4207 }
4208 }
4209 cifs_buf_release(pSMB);
4210
4211 if (rc == -EAGAIN)
4212 goto QFSInfoRetry;
4213
4214 return rc;
4215}
4216
4217int
Steve French737b7582005-04-28 22:41:06 -07004218CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219{
4220/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4221 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4222 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4223 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4224 int rc = 0;
4225 int bytes_returned = 0;
4226 __u16 params, byte_count;
4227
4228 cFYI(1, ("In QFSAttributeInfo"));
4229QFSAttributeRetry:
4230 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4231 (void **) &pSMBr);
4232 if (rc)
4233 return rc;
4234
4235 params = 2; /* level */
4236 pSMB->TotalDataCount = 0;
4237 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004238 /* BB find exact max SMB PDU from sess structure BB */
4239 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 pSMB->MaxSetupCount = 0;
4241 pSMB->Reserved = 0;
4242 pSMB->Flags = 0;
4243 pSMB->Timeout = 0;
4244 pSMB->Reserved2 = 0;
4245 byte_count = params + 1 /* pad */ ;
4246 pSMB->TotalParameterCount = cpu_to_le16(params);
4247 pSMB->ParameterCount = pSMB->TotalParameterCount;
4248 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004249 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 pSMB->DataCount = 0;
4251 pSMB->DataOffset = 0;
4252 pSMB->SetupCount = 1;
4253 pSMB->Reserved3 = 0;
4254 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4255 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4256 pSMB->hdr.smb_buf_length += byte_count;
4257 pSMB->ByteCount = cpu_to_le16(byte_count);
4258
4259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4261 if (rc) {
4262 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4263 } else { /* decode response */
4264 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4265
Steve French50c2f752007-07-13 00:33:32 +00004266 if (rc || (pSMBr->ByteCount < 13)) {
4267 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 rc = -EIO; /* bad smb */
4269 } else {
4270 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4271 response_data =
4272 (FILE_SYSTEM_ATTRIBUTE_INFO
4273 *) (((char *) &pSMBr->hdr.Protocol) +
4274 data_offset);
4275 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004276 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 }
4278 }
4279 cifs_buf_release(pSMB);
4280
4281 if (rc == -EAGAIN)
4282 goto QFSAttributeRetry;
4283
4284 return rc;
4285}
4286
4287int
Steve French737b7582005-04-28 22:41:06 -07004288CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289{
4290/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4291 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4292 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4293 FILE_SYSTEM_DEVICE_INFO *response_data;
4294 int rc = 0;
4295 int bytes_returned = 0;
4296 __u16 params, byte_count;
4297
4298 cFYI(1, ("In QFSDeviceInfo"));
4299QFSDeviceRetry:
4300 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4301 (void **) &pSMBr);
4302 if (rc)
4303 return rc;
4304
4305 params = 2; /* level */
4306 pSMB->TotalDataCount = 0;
4307 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004308 /* BB find exact max SMB PDU from sess structure BB */
4309 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 pSMB->MaxSetupCount = 0;
4311 pSMB->Reserved = 0;
4312 pSMB->Flags = 0;
4313 pSMB->Timeout = 0;
4314 pSMB->Reserved2 = 0;
4315 byte_count = params + 1 /* pad */ ;
4316 pSMB->TotalParameterCount = cpu_to_le16(params);
4317 pSMB->ParameterCount = pSMB->TotalParameterCount;
4318 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004319 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
4321 pSMB->DataCount = 0;
4322 pSMB->DataOffset = 0;
4323 pSMB->SetupCount = 1;
4324 pSMB->Reserved3 = 0;
4325 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4326 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4327 pSMB->hdr.smb_buf_length += byte_count;
4328 pSMB->ByteCount = cpu_to_le16(byte_count);
4329
4330 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4331 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4332 if (rc) {
4333 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4334 } else { /* decode response */
4335 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4336
Steve French630f3f0c2007-10-25 21:17:17 +00004337 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 rc = -EIO; /* bad smb */
4339 else {
4340 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4341 response_data =
Steve French737b7582005-04-28 22:41:06 -07004342 (FILE_SYSTEM_DEVICE_INFO *)
4343 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 data_offset);
4345 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004346 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 }
4348 }
4349 cifs_buf_release(pSMB);
4350
4351 if (rc == -EAGAIN)
4352 goto QFSDeviceRetry;
4353
4354 return rc;
4355}
4356
4357int
Steve French737b7582005-04-28 22:41:06 -07004358CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359{
4360/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4361 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4362 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4363 FILE_SYSTEM_UNIX_INFO *response_data;
4364 int rc = 0;
4365 int bytes_returned = 0;
4366 __u16 params, byte_count;
4367
4368 cFYI(1, ("In QFSUnixInfo"));
4369QFSUnixRetry:
4370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4371 (void **) &pSMBr);
4372 if (rc)
4373 return rc;
4374
4375 params = 2; /* level */
4376 pSMB->TotalDataCount = 0;
4377 pSMB->DataCount = 0;
4378 pSMB->DataOffset = 0;
4379 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004380 /* BB find exact max SMB PDU from sess structure BB */
4381 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382 pSMB->MaxSetupCount = 0;
4383 pSMB->Reserved = 0;
4384 pSMB->Flags = 0;
4385 pSMB->Timeout = 0;
4386 pSMB->Reserved2 = 0;
4387 byte_count = params + 1 /* pad */ ;
4388 pSMB->ParameterCount = cpu_to_le16(params);
4389 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004390 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4391 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 pSMB->SetupCount = 1;
4393 pSMB->Reserved3 = 0;
4394 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4395 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4396 pSMB->hdr.smb_buf_length += byte_count;
4397 pSMB->ByteCount = cpu_to_le16(byte_count);
4398
4399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4400 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4401 if (rc) {
4402 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4403 } else { /* decode response */
4404 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4405
4406 if (rc || (pSMBr->ByteCount < 13)) {
4407 rc = -EIO; /* bad smb */
4408 } else {
4409 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4410 response_data =
4411 (FILE_SYSTEM_UNIX_INFO
4412 *) (((char *) &pSMBr->hdr.Protocol) +
4413 data_offset);
4414 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004415 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 }
4417 }
4418 cifs_buf_release(pSMB);
4419
4420 if (rc == -EAGAIN)
4421 goto QFSUnixRetry;
4422
4423
4424 return rc;
4425}
4426
Jeremy Allisonac670552005-06-22 17:26:35 -07004427int
Steve French45abc6e2005-06-23 13:42:03 -05004428CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004429{
4430/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4431 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4432 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4433 int rc = 0;
4434 int bytes_returned = 0;
4435 __u16 params, param_offset, offset, byte_count;
4436
4437 cFYI(1, ("In SETFSUnixInfo"));
4438SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004439 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004440 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4441 (void **) &pSMBr);
4442 if (rc)
4443 return rc;
4444
4445 params = 4; /* 2 bytes zero followed by info level. */
4446 pSMB->MaxSetupCount = 0;
4447 pSMB->Reserved = 0;
4448 pSMB->Flags = 0;
4449 pSMB->Timeout = 0;
4450 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004451 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4452 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004453 offset = param_offset + params;
4454
4455 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004456 /* BB find exact max SMB PDU from sess structure BB */
4457 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004458 pSMB->SetupCount = 1;
4459 pSMB->Reserved3 = 0;
4460 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4461 byte_count = 1 /* pad */ + params + 12;
4462
4463 pSMB->DataCount = cpu_to_le16(12);
4464 pSMB->ParameterCount = cpu_to_le16(params);
4465 pSMB->TotalDataCount = pSMB->DataCount;
4466 pSMB->TotalParameterCount = pSMB->ParameterCount;
4467 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4468 pSMB->DataOffset = cpu_to_le16(offset);
4469
4470 /* Params. */
4471 pSMB->FileNum = 0;
4472 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4473
4474 /* Data. */
4475 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4476 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4477 pSMB->ClientUnixCap = cpu_to_le64(cap);
4478
4479 pSMB->hdr.smb_buf_length += byte_count;
4480 pSMB->ByteCount = cpu_to_le16(byte_count);
4481
4482 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4483 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4484 if (rc) {
4485 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4486 } else { /* decode response */
4487 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004488 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004489 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004490 }
4491 cifs_buf_release(pSMB);
4492
4493 if (rc == -EAGAIN)
4494 goto SETFSUnixRetry;
4495
4496 return rc;
4497}
4498
4499
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500
4501int
4502CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004503 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504{
4505/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4506 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4507 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4508 FILE_SYSTEM_POSIX_INFO *response_data;
4509 int rc = 0;
4510 int bytes_returned = 0;
4511 __u16 params, byte_count;
4512
4513 cFYI(1, ("In QFSPosixInfo"));
4514QFSPosixRetry:
4515 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4516 (void **) &pSMBr);
4517 if (rc)
4518 return rc;
4519
4520 params = 2; /* level */
4521 pSMB->TotalDataCount = 0;
4522 pSMB->DataCount = 0;
4523 pSMB->DataOffset = 0;
4524 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004525 /* BB find exact max SMB PDU from sess structure BB */
4526 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 pSMB->MaxSetupCount = 0;
4528 pSMB->Reserved = 0;
4529 pSMB->Flags = 0;
4530 pSMB->Timeout = 0;
4531 pSMB->Reserved2 = 0;
4532 byte_count = params + 1 /* pad */ ;
4533 pSMB->ParameterCount = cpu_to_le16(params);
4534 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004535 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4536 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 pSMB->SetupCount = 1;
4538 pSMB->Reserved3 = 0;
4539 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4540 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4541 pSMB->hdr.smb_buf_length += byte_count;
4542 pSMB->ByteCount = cpu_to_le16(byte_count);
4543
4544 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4545 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4546 if (rc) {
4547 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4548 } else { /* decode response */
4549 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4550
4551 if (rc || (pSMBr->ByteCount < 13)) {
4552 rc = -EIO; /* bad smb */
4553 } else {
4554 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4555 response_data =
4556 (FILE_SYSTEM_POSIX_INFO
4557 *) (((char *) &pSMBr->hdr.Protocol) +
4558 data_offset);
4559 FSData->f_bsize =
4560 le32_to_cpu(response_data->BlockSize);
4561 FSData->f_blocks =
4562 le64_to_cpu(response_data->TotalBlocks);
4563 FSData->f_bfree =
4564 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004565 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566 FSData->f_bavail = FSData->f_bfree;
4567 } else {
4568 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004569 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
Steve French790fe572007-07-07 19:25:05 +00004571 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004573 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004574 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004576 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004577 }
4578 }
4579 cifs_buf_release(pSMB);
4580
4581 if (rc == -EAGAIN)
4582 goto QFSPosixRetry;
4583
4584 return rc;
4585}
4586
4587
Steve French50c2f752007-07-13 00:33:32 +00004588/* We can not use write of zero bytes trick to
4589 set file size due to need for large file support. Also note that
4590 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 routine which is only needed to work around a sharing violation bug
4592 in Samba which this routine can run into */
4593
4594int
4595CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004596 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004597 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598{
4599 struct smb_com_transaction2_spi_req *pSMB = NULL;
4600 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4601 struct file_end_of_file_info *parm_data;
4602 int name_len;
4603 int rc = 0;
4604 int bytes_returned = 0;
4605 __u16 params, byte_count, data_count, param_offset, offset;
4606
4607 cFYI(1, ("In SetEOF"));
4608SetEOFRetry:
4609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4610 (void **) &pSMBr);
4611 if (rc)
4612 return rc;
4613
4614 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4615 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004616 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004617 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 name_len++; /* trailing null */
4619 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004620 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004621 name_len = strnlen(fileName, PATH_MAX);
4622 name_len++; /* trailing null */
4623 strncpy(pSMB->FileName, fileName, name_len);
4624 }
4625 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004626 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004628 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 pSMB->MaxSetupCount = 0;
4630 pSMB->Reserved = 0;
4631 pSMB->Flags = 0;
4632 pSMB->Timeout = 0;
4633 pSMB->Reserved2 = 0;
4634 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004635 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004637 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4639 pSMB->InformationLevel =
4640 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4641 else
4642 pSMB->InformationLevel =
4643 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4644 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4646 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004647 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 else
4649 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004650 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 }
4652
4653 parm_data =
4654 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4655 offset);
4656 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4657 pSMB->DataOffset = cpu_to_le16(offset);
4658 pSMB->SetupCount = 1;
4659 pSMB->Reserved3 = 0;
4660 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4661 byte_count = 3 /* pad */ + params + data_count;
4662 pSMB->DataCount = cpu_to_le16(data_count);
4663 pSMB->TotalDataCount = pSMB->DataCount;
4664 pSMB->ParameterCount = cpu_to_le16(params);
4665 pSMB->TotalParameterCount = pSMB->ParameterCount;
4666 pSMB->Reserved4 = 0;
4667 pSMB->hdr.smb_buf_length += byte_count;
4668 parm_data->FileSize = cpu_to_le64(size);
4669 pSMB->ByteCount = cpu_to_le16(byte_count);
4670 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4671 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004672 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674
4675 cifs_buf_release(pSMB);
4676
4677 if (rc == -EAGAIN)
4678 goto SetEOFRetry;
4679
4680 return rc;
4681}
4682
4683int
Steve French50c2f752007-07-13 00:33:32 +00004684CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004685 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686{
4687 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 char *data_offset;
4689 struct file_end_of_file_info *parm_data;
4690 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 __u16 params, param_offset, offset, byte_count, count;
4692
4693 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4694 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004695 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4696
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 if (rc)
4698 return rc;
4699
4700 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4701 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004702
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 params = 6;
4704 pSMB->MaxSetupCount = 0;
4705 pSMB->Reserved = 0;
4706 pSMB->Flags = 0;
4707 pSMB->Timeout = 0;
4708 pSMB->Reserved2 = 0;
4709 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4710 offset = param_offset + params;
4711
Steve French50c2f752007-07-13 00:33:32 +00004712 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
4714 count = sizeof(struct file_end_of_file_info);
4715 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004716 /* BB find exact max SMB PDU from sess structure BB */
4717 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 pSMB->SetupCount = 1;
4719 pSMB->Reserved3 = 0;
4720 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4721 byte_count = 3 /* pad */ + params + count;
4722 pSMB->DataCount = cpu_to_le16(count);
4723 pSMB->ParameterCount = cpu_to_le16(params);
4724 pSMB->TotalDataCount = pSMB->DataCount;
4725 pSMB->TotalParameterCount = pSMB->ParameterCount;
4726 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4727 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004728 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4729 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 pSMB->DataOffset = cpu_to_le16(offset);
4731 parm_data->FileSize = cpu_to_le64(size);
4732 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004733 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4735 pSMB->InformationLevel =
4736 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4737 else
4738 pSMB->InformationLevel =
4739 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004740 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4742 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004743 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 else
4745 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004746 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 }
4748 pSMB->Reserved4 = 0;
4749 pSMB->hdr.smb_buf_length += byte_count;
4750 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004751 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752 if (rc) {
4753 cFYI(1,
4754 ("Send error in SetFileInfo (SetFileSize) = %d",
4755 rc));
4756 }
4757
Steve French50c2f752007-07-13 00:33:32 +00004758 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 since file handle passed in no longer valid */
4760
4761 return rc;
4762}
4763
Steve French50c2f752007-07-13 00:33:32 +00004764/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 an open handle, rather than by pathname - this is awkward due to
4766 potential access conflicts on the open, but it is unavoidable for these
4767 old servers since the only other choice is to go from 100 nanosecond DCE
4768 time and resort to the original setpathinfo level which takes the ancient
4769 DOS time format with 2 second granularity */
4770int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004771CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4772 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773{
4774 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 char *data_offset;
4776 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 __u16 params, param_offset, offset, byte_count, count;
4778
4779 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004780 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4781
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 if (rc)
4783 return rc;
4784
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004785 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4786 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004787
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788 params = 6;
4789 pSMB->MaxSetupCount = 0;
4790 pSMB->Reserved = 0;
4791 pSMB->Flags = 0;
4792 pSMB->Timeout = 0;
4793 pSMB->Reserved2 = 0;
4794 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4795 offset = param_offset + params;
4796
Steve French50c2f752007-07-13 00:33:32 +00004797 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798
Steve French26f57362007-08-30 22:09:15 +00004799 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004801 /* BB find max SMB PDU from sess */
4802 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 pSMB->SetupCount = 1;
4804 pSMB->Reserved3 = 0;
4805 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4806 byte_count = 3 /* pad */ + params + count;
4807 pSMB->DataCount = cpu_to_le16(count);
4808 pSMB->ParameterCount = cpu_to_le16(params);
4809 pSMB->TotalDataCount = pSMB->DataCount;
4810 pSMB->TotalParameterCount = pSMB->ParameterCount;
4811 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4812 pSMB->DataOffset = cpu_to_le16(offset);
4813 pSMB->Fid = fid;
4814 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4815 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4816 else
4817 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4818 pSMB->Reserved4 = 0;
4819 pSMB->hdr.smb_buf_length += byte_count;
4820 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004821 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004822 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004823 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004824 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825
Steve French50c2f752007-07-13 00:33:32 +00004826 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 since file handle passed in no longer valid */
4828
4829 return rc;
4830}
4831
Jeff Layton6d22f092008-09-23 11:48:35 -04004832int
4833CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4834 bool delete_file, __u16 fid, __u32 pid_of_opener)
4835{
4836 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4837 char *data_offset;
4838 int rc = 0;
4839 __u16 params, param_offset, offset, byte_count, count;
4840
4841 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4842 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4843
4844 if (rc)
4845 return rc;
4846
4847 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4848 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4849
4850 params = 6;
4851 pSMB->MaxSetupCount = 0;
4852 pSMB->Reserved = 0;
4853 pSMB->Flags = 0;
4854 pSMB->Timeout = 0;
4855 pSMB->Reserved2 = 0;
4856 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4857 offset = param_offset + params;
4858
4859 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4860
4861 count = 1;
4862 pSMB->MaxParameterCount = cpu_to_le16(2);
4863 /* BB find max SMB PDU from sess */
4864 pSMB->MaxDataCount = cpu_to_le16(1000);
4865 pSMB->SetupCount = 1;
4866 pSMB->Reserved3 = 0;
4867 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4868 byte_count = 3 /* pad */ + params + count;
4869 pSMB->DataCount = cpu_to_le16(count);
4870 pSMB->ParameterCount = cpu_to_le16(params);
4871 pSMB->TotalDataCount = pSMB->DataCount;
4872 pSMB->TotalParameterCount = pSMB->ParameterCount;
4873 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4874 pSMB->DataOffset = cpu_to_le16(offset);
4875 pSMB->Fid = fid;
4876 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4877 pSMB->Reserved4 = 0;
4878 pSMB->hdr.smb_buf_length += byte_count;
4879 pSMB->ByteCount = cpu_to_le16(byte_count);
4880 *data_offset = delete_file ? 1 : 0;
4881 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4882 if (rc)
4883 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4884
4885 return rc;
4886}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887
4888int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004889CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4890 const char *fileName, const FILE_BASIC_INFO *data,
4891 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892{
4893 TRANSACTION2_SPI_REQ *pSMB = NULL;
4894 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4895 int name_len;
4896 int rc = 0;
4897 int bytes_returned = 0;
4898 char *data_offset;
4899 __u16 params, param_offset, offset, byte_count, count;
4900
4901 cFYI(1, ("In SetTimes"));
4902
4903SetTimesRetry:
4904 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4905 (void **) &pSMBr);
4906 if (rc)
4907 return rc;
4908
4909 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4910 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004911 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004912 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 name_len++; /* trailing null */
4914 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004915 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 name_len = strnlen(fileName, PATH_MAX);
4917 name_len++; /* trailing null */
4918 strncpy(pSMB->FileName, fileName, name_len);
4919 }
4920
4921 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004922 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004924 /* BB find max SMB PDU from sess structure BB */
4925 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 pSMB->MaxSetupCount = 0;
4927 pSMB->Reserved = 0;
4928 pSMB->Flags = 0;
4929 pSMB->Timeout = 0;
4930 pSMB->Reserved2 = 0;
4931 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004932 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 offset = param_offset + params;
4934 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4935 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4936 pSMB->DataOffset = cpu_to_le16(offset);
4937 pSMB->SetupCount = 1;
4938 pSMB->Reserved3 = 0;
4939 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4940 byte_count = 3 /* pad */ + params + count;
4941
4942 pSMB->DataCount = cpu_to_le16(count);
4943 pSMB->ParameterCount = cpu_to_le16(params);
4944 pSMB->TotalDataCount = pSMB->DataCount;
4945 pSMB->TotalParameterCount = pSMB->ParameterCount;
4946 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4947 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4948 else
4949 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4950 pSMB->Reserved4 = 0;
4951 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004952 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 pSMB->ByteCount = cpu_to_le16(byte_count);
4954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004956 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958
4959 cifs_buf_release(pSMB);
4960
4961 if (rc == -EAGAIN)
4962 goto SetTimesRetry;
4963
4964 return rc;
4965}
4966
4967/* Can not be used to set time stamps yet (due to old DOS time format) */
4968/* Can be used to set attributes */
4969#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4970 handling it anyway and NT4 was what we thought it would be needed for
4971 Do not delete it until we prove whether needed for Win9x though */
4972int
4973CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4974 __u16 dos_attrs, const struct nls_table *nls_codepage)
4975{
4976 SETATTR_REQ *pSMB = NULL;
4977 SETATTR_RSP *pSMBr = NULL;
4978 int rc = 0;
4979 int bytes_returned;
4980 int name_len;
4981
4982 cFYI(1, ("In SetAttrLegacy"));
4983
4984SetAttrLgcyRetry:
4985 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4986 (void **) &pSMBr);
4987 if (rc)
4988 return rc;
4989
4990 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4991 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004992 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993 PATH_MAX, nls_codepage);
4994 name_len++; /* trailing null */
4995 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004996 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 name_len = strnlen(fileName, PATH_MAX);
4998 name_len++; /* trailing null */
4999 strncpy(pSMB->fileName, fileName, name_len);
5000 }
5001 pSMB->attr = cpu_to_le16(dos_attrs);
5002 pSMB->BufferFormat = 0x04;
5003 pSMB->hdr.smb_buf_length += name_len + 1;
5004 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005007 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005009
5010 cifs_buf_release(pSMB);
5011
5012 if (rc == -EAGAIN)
5013 goto SetAttrLgcyRetry;
5014
5015 return rc;
5016}
5017#endif /* temporarily unneeded SetAttr legacy function */
5018
Jeff Layton654cf142009-07-09 20:02:49 -04005019static void
5020cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5021 const struct cifs_unix_set_info_args *args)
5022{
5023 u64 mode = args->mode;
5024
5025 /*
5026 * Samba server ignores set of file size to zero due to bugs in some
5027 * older clients, but we should be precise - we use SetFileSize to
5028 * set file size and do not want to truncate file size to zero
5029 * accidently as happened on one Samba server beta by putting
5030 * zero instead of -1 here
5031 */
5032 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5033 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5034 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5035 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5036 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5037 data_offset->Uid = cpu_to_le64(args->uid);
5038 data_offset->Gid = cpu_to_le64(args->gid);
5039 /* better to leave device as zero when it is */
5040 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5041 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5042 data_offset->Permissions = cpu_to_le64(mode);
5043
5044 if (S_ISREG(mode))
5045 data_offset->Type = cpu_to_le32(UNIX_FILE);
5046 else if (S_ISDIR(mode))
5047 data_offset->Type = cpu_to_le32(UNIX_DIR);
5048 else if (S_ISLNK(mode))
5049 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5050 else if (S_ISCHR(mode))
5051 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5052 else if (S_ISBLK(mode))
5053 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5054 else if (S_ISFIFO(mode))
5055 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5056 else if (S_ISSOCK(mode))
5057 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5058}
5059
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005061CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5062 const struct cifs_unix_set_info_args *args,
5063 u16 fid, u32 pid_of_opener)
5064{
5065 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5066 FILE_UNIX_BASIC_INFO *data_offset;
5067 int rc = 0;
5068 u16 params, param_offset, offset, byte_count, count;
5069
5070 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5071 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5072
5073 if (rc)
5074 return rc;
5075
5076 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5077 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5078
5079 params = 6;
5080 pSMB->MaxSetupCount = 0;
5081 pSMB->Reserved = 0;
5082 pSMB->Flags = 0;
5083 pSMB->Timeout = 0;
5084 pSMB->Reserved2 = 0;
5085 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5086 offset = param_offset + params;
5087
5088 data_offset = (FILE_UNIX_BASIC_INFO *)
5089 ((char *)(&pSMB->hdr.Protocol) + offset);
5090 count = sizeof(FILE_UNIX_BASIC_INFO);
5091
5092 pSMB->MaxParameterCount = cpu_to_le16(2);
5093 /* BB find max SMB PDU from sess */
5094 pSMB->MaxDataCount = cpu_to_le16(1000);
5095 pSMB->SetupCount = 1;
5096 pSMB->Reserved3 = 0;
5097 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5098 byte_count = 3 /* pad */ + params + count;
5099 pSMB->DataCount = cpu_to_le16(count);
5100 pSMB->ParameterCount = cpu_to_le16(params);
5101 pSMB->TotalDataCount = pSMB->DataCount;
5102 pSMB->TotalParameterCount = pSMB->ParameterCount;
5103 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5104 pSMB->DataOffset = cpu_to_le16(offset);
5105 pSMB->Fid = fid;
5106 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5107 pSMB->Reserved4 = 0;
5108 pSMB->hdr.smb_buf_length += byte_count;
5109 pSMB->ByteCount = cpu_to_le16(byte_count);
5110
5111 cifs_fill_unix_set_info(data_offset, args);
5112
5113 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5114 if (rc)
5115 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5116
5117 /* Note: On -EAGAIN error only caller can retry on handle based calls
5118 since file handle passed in no longer valid */
5119
5120 return rc;
5121}
5122
5123int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005124CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5125 const struct cifs_unix_set_info_args *args,
5126 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127{
5128 TRANSACTION2_SPI_REQ *pSMB = NULL;
5129 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5130 int name_len;
5131 int rc = 0;
5132 int bytes_returned = 0;
5133 FILE_UNIX_BASIC_INFO *data_offset;
5134 __u16 params, param_offset, offset, count, byte_count;
5135
5136 cFYI(1, ("In SetUID/GID/Mode"));
5137setPermsRetry:
5138 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5139 (void **) &pSMBr);
5140 if (rc)
5141 return rc;
5142
5143 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5144 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005145 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005146 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 name_len++; /* trailing null */
5148 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005149 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 name_len = strnlen(fileName, PATH_MAX);
5151 name_len++; /* trailing null */
5152 strncpy(pSMB->FileName, fileName, name_len);
5153 }
5154
5155 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005156 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005158 /* BB find max SMB PDU from sess structure BB */
5159 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005160 pSMB->MaxSetupCount = 0;
5161 pSMB->Reserved = 0;
5162 pSMB->Flags = 0;
5163 pSMB->Timeout = 0;
5164 pSMB->Reserved2 = 0;
5165 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005166 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 offset = param_offset + params;
5168 data_offset =
5169 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5170 offset);
5171 memset(data_offset, 0, count);
5172 pSMB->DataOffset = cpu_to_le16(offset);
5173 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5174 pSMB->SetupCount = 1;
5175 pSMB->Reserved3 = 0;
5176 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5177 byte_count = 3 /* pad */ + params + count;
5178 pSMB->ParameterCount = cpu_to_le16(params);
5179 pSMB->DataCount = cpu_to_le16(count);
5180 pSMB->TotalParameterCount = pSMB->ParameterCount;
5181 pSMB->TotalDataCount = pSMB->DataCount;
5182 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5183 pSMB->Reserved4 = 0;
5184 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005185
Jeff Layton654cf142009-07-09 20:02:49 -04005186 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187
5188 pSMB->ByteCount = cpu_to_le16(byte_count);
5189 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5190 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005191 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193
Steve French0d817bc2008-05-22 02:02:03 +00005194 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 if (rc == -EAGAIN)
5196 goto setPermsRetry;
5197 return rc;
5198}
5199
Steve French50c2f752007-07-13 00:33:32 +00005200int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005201 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005202 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005203 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204{
5205 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005206 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5207 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005208 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 int bytes_returned;
5210
Steve French50c2f752007-07-13 00:33:32 +00005211 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005213 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 if (rc)
5215 return rc;
5216
5217 pSMB->TotalParameterCount = 0 ;
5218 pSMB->TotalDataCount = 0;
5219 pSMB->MaxParameterCount = cpu_to_le32(2);
5220 /* BB find exact data count max from sess structure BB */
5221 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005222/* BB VERIFY verify which is correct for above BB */
5223 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5224 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5225
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 pSMB->MaxSetupCount = 4;
5227 pSMB->Reserved = 0;
5228 pSMB->ParameterOffset = 0;
5229 pSMB->DataCount = 0;
5230 pSMB->DataOffset = 0;
5231 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5232 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5233 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005234 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5236 pSMB->Reserved2 = 0;
5237 pSMB->CompletionFilter = cpu_to_le32(filter);
5238 pSMB->Fid = netfid; /* file handle always le */
5239 pSMB->ByteCount = 0;
5240
5241 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005242 (struct smb_hdr *)pSMBr, &bytes_returned,
5243 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 if (rc) {
5245 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005246 } else {
5247 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005248 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005249 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005250 sizeof(struct dir_notify_req),
5251 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005252 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005253 dnotify_req->Pid = pSMB->hdr.Pid;
5254 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5255 dnotify_req->Mid = pSMB->hdr.Mid;
5256 dnotify_req->Tid = pSMB->hdr.Tid;
5257 dnotify_req->Uid = pSMB->hdr.Uid;
5258 dnotify_req->netfid = netfid;
5259 dnotify_req->pfile = pfile;
5260 dnotify_req->filter = filter;
5261 dnotify_req->multishot = multishot;
5262 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005263 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005264 &GlobalDnotifyReqList);
5265 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005266 } else
Steve French47c786e2005-10-11 20:03:18 -07005267 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268 }
5269 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005270 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271}
5272#ifdef CONFIG_CIFS_XATTR
5273ssize_t
5274CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5275 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005276 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005277 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278{
5279 /* BB assumes one setup word */
5280 TRANSACTION2_QPI_REQ *pSMB = NULL;
5281 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5282 int rc = 0;
5283 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005284 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005285 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005286 struct fea *temp_fea;
5287 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005288 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005289 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290
5291 cFYI(1, ("In Query All EAs path %s", searchName));
5292QAllEAsRetry:
5293 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5294 (void **) &pSMBr);
5295 if (rc)
5296 return rc;
5297
5298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005299 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005300 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005301 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005302 list_len++; /* trailing null */
5303 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005305 list_len = strnlen(searchName, PATH_MAX);
5306 list_len++; /* trailing null */
5307 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 }
5309
Jeff Layton6e462b92010-02-10 16:18:26 -05005310 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 pSMB->TotalDataCount = 0;
5312 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005313 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005314 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 pSMB->MaxSetupCount = 0;
5316 pSMB->Reserved = 0;
5317 pSMB->Flags = 0;
5318 pSMB->Timeout = 0;
5319 pSMB->Reserved2 = 0;
5320 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005321 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322 pSMB->DataCount = 0;
5323 pSMB->DataOffset = 0;
5324 pSMB->SetupCount = 1;
5325 pSMB->Reserved3 = 0;
5326 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5327 byte_count = params + 1 /* pad */ ;
5328 pSMB->TotalParameterCount = cpu_to_le16(params);
5329 pSMB->ParameterCount = pSMB->TotalParameterCount;
5330 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5331 pSMB->Reserved4 = 0;
5332 pSMB->hdr.smb_buf_length += byte_count;
5333 pSMB->ByteCount = cpu_to_le16(byte_count);
5334
5335 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5336 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5337 if (rc) {
5338 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
Jeff Laytonf0d38682010-02-10 16:18:26 -05005339 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005340 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005341
5342
5343 /* BB also check enough total bytes returned */
5344 /* BB we need to improve the validity checking
5345 of these trans2 responses */
5346
5347 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5348 if (rc || (pSMBr->ByteCount < 4)) {
5349 rc = -EIO; /* bad smb */
5350 goto QAllEAsOut;
5351 }
5352
5353 /* check that length of list is not more than bcc */
5354 /* check that each entry does not go beyond length
5355 of list */
5356 /* check that each element of each entry does not
5357 go beyond end of list */
5358 /* validate_trans2_offsets() */
5359 /* BB check if start of smb + data_offset > &bcc+ bcc */
5360
5361 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5362 ea_response_data = (struct fealist *)
5363 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5364
Jeff Layton6e462b92010-02-10 16:18:26 -05005365 list_len = le32_to_cpu(ea_response_data->list_len);
5366 cFYI(1, ("ea length %d", list_len));
5367 if (list_len <= 8) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005368 cFYI(1, ("empty EA list returned from server"));
5369 goto QAllEAsOut;
5370 }
5371
Jeff Layton0cd126b2010-02-10 16:18:26 -05005372 /* make sure list_len doesn't go past end of SMB */
5373 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5374 if ((char *)ea_response_data + list_len > end_of_smb) {
5375 cFYI(1, ("EA list appears to go beyond SMB"));
5376 rc = -EIO;
5377 goto QAllEAsOut;
5378 }
5379
Jeff Laytonf0d38682010-02-10 16:18:26 -05005380 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005381 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005382 temp_fea = ea_response_data->list;
5383 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005384 while (list_len > 0) {
Jeff Layton0cd126b2010-02-10 16:18:26 -05005385 __u8 name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005386 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005387
Jeff Layton6e462b92010-02-10 16:18:26 -05005388 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005389 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005390 /* make sure we can read name_len and value_len */
5391 if (list_len < 0) {
5392 cFYI(1, ("EA entry goes beyond length of list"));
5393 rc = -EIO;
5394 goto QAllEAsOut;
5395 }
5396
5397 name_len = temp_fea->name_len;
5398 value_len = le16_to_cpu(temp_fea->value_len);
5399 list_len -= name_len + 1 + value_len;
5400 if (list_len < 0) {
5401 cFYI(1, ("EA entry goes beyond length of list"));
5402 rc = -EIO;
5403 goto QAllEAsOut;
5404 }
5405
Jeff Layton6e462b92010-02-10 16:18:26 -05005406 /* account for prefix user. and trailing null */
Jeff Layton0cd126b2010-02-10 16:18:26 -05005407 rc += (5 + 1 + name_len);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005408 if (rc < (int) buf_size) {
5409 memcpy(EAData, "user.", 5);
5410 EAData += 5;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005411 memcpy(EAData, temp_ptr, name_len);
5412 EAData += name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005413 /* null terminate name */
5414 *EAData = 0;
Jeff Layton6e462b92010-02-10 16:18:26 -05005415 ++EAData;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005416 } else if (buf_size == 0) {
5417 /* skip copy - calc size only */
5418 } else {
5419 /* stop before overrun buffer */
5420 rc = -ERANGE;
5421 break;
5422 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005423 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005424 temp_fea = (struct fea *)temp_ptr;
5425 }
5426
5427QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005428 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 if (rc == -EAGAIN)
5430 goto QAllEAsRetry;
5431
5432 return (ssize_t)rc;
5433}
5434
Steve French50c2f752007-07-13 00:33:32 +00005435ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5436 const unsigned char *searchName, const unsigned char *ea_name,
5437 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005438 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005439{
5440 TRANSACTION2_QPI_REQ *pSMB = NULL;
5441 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5442 int rc = 0;
5443 int bytes_returned;
5444 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005445 struct fea *temp_fea;
5446 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 __u16 params, byte_count;
5448
5449 cFYI(1, ("In Query EA path %s", searchName));
5450QEARetry:
5451 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5452 (void **) &pSMBr);
5453 if (rc)
5454 return rc;
5455
5456 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5457 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005458 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005459 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 name_len++; /* trailing null */
5461 name_len *= 2;
5462 } else { /* BB improve the check for buffer overruns BB */
5463 name_len = strnlen(searchName, PATH_MAX);
5464 name_len++; /* trailing null */
5465 strncpy(pSMB->FileName, searchName, name_len);
5466 }
5467
Steve French50c2f752007-07-13 00:33:32 +00005468 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469 pSMB->TotalDataCount = 0;
5470 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005471 /* BB find exact max SMB PDU from sess structure BB */
5472 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005473 pSMB->MaxSetupCount = 0;
5474 pSMB->Reserved = 0;
5475 pSMB->Flags = 0;
5476 pSMB->Timeout = 0;
5477 pSMB->Reserved2 = 0;
5478 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005479 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480 pSMB->DataCount = 0;
5481 pSMB->DataOffset = 0;
5482 pSMB->SetupCount = 1;
5483 pSMB->Reserved3 = 0;
5484 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5485 byte_count = params + 1 /* pad */ ;
5486 pSMB->TotalParameterCount = cpu_to_le16(params);
5487 pSMB->ParameterCount = pSMB->TotalParameterCount;
5488 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5489 pSMB->Reserved4 = 0;
5490 pSMB->hdr.smb_buf_length += byte_count;
5491 pSMB->ByteCount = cpu_to_le16(byte_count);
5492
5493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5495 if (rc) {
5496 cFYI(1, ("Send error in Query EA = %d", rc));
5497 } else { /* decode response */
5498 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5499
5500 /* BB also check enough total bytes returned */
5501 /* BB we need to improve the validity checking
5502 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005503 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 rc = -EIO; /* bad smb */
5505 /* else if (pFindData){
5506 memcpy((char *) pFindData,
5507 (char *) &pSMBr->hdr.Protocol +
5508 data_offset, kl);
5509 }*/ else {
5510 /* check that length of list is not more than bcc */
5511 /* check that each entry does not go beyond length
5512 of list */
5513 /* check that each element of each entry does not
5514 go beyond end of list */
5515 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005516 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517 rc = -ENODATA;
5518 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005519 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520 ea_response_data = (struct fealist *)
5521 (((char *) &pSMBr->hdr.Protocol) +
5522 data_offset);
5523 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005524 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005525 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005526 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005527 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 } else {
5529 /* account for ea list len */
5530 name_len -= 4;
5531 temp_fea = ea_response_data->list;
5532 temp_ptr = (char *)temp_fea;
5533 /* loop through checking if we have a matching
5534 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005535 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 __u16 value_len;
5537 name_len -= 4;
5538 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005539 value_len =
5540 le16_to_cpu(temp_fea->value_len);
5541 /* BB validate that value_len falls within SMB,
5542 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005543 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005544 temp_fea->name_len) == 0) {
5545 /* found a match */
5546 rc = value_len;
5547 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005548 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 memcpy(ea_value,
5550 temp_fea->name+temp_fea->name_len+1,
5551 rc);
Steve French50c2f752007-07-13 00:33:32 +00005552 /* ea values, unlike ea
5553 names, are not null
5554 terminated */
Steve French790fe572007-07-07 19:25:05 +00005555 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556 /* skip copy - calc size only */
5557 } else {
Steve French50c2f752007-07-13 00:33:32 +00005558 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 rc = -ERANGE;
5560 }
5561 break;
5562 }
5563 name_len -= temp_fea->name_len;
5564 temp_ptr += temp_fea->name_len;
5565 /* account for trailing null */
5566 name_len--;
5567 temp_ptr++;
5568 name_len -= value_len;
5569 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005570 /* No trailing null to account for in
5571 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005572 temp_fea = (struct fea *)temp_ptr;
5573 }
Steve French50c2f752007-07-13 00:33:32 +00005574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005575 }
5576 }
Steve French0d817bc2008-05-22 02:02:03 +00005577 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005578 if (rc == -EAGAIN)
5579 goto QEARetry;
5580
5581 return (ssize_t)rc;
5582}
5583
5584int
5585CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005586 const char *ea_name, const void *ea_value,
5587 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5588 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005589{
5590 struct smb_com_transaction2_spi_req *pSMB = NULL;
5591 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5592 struct fealist *parm_data;
5593 int name_len;
5594 int rc = 0;
5595 int bytes_returned = 0;
5596 __u16 params, param_offset, byte_count, offset, count;
5597
5598 cFYI(1, ("In SetEA"));
5599SetEARetry:
5600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5601 (void **) &pSMBr);
5602 if (rc)
5603 return rc;
5604
5605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5606 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005607 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005608 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609 name_len++; /* trailing null */
5610 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005611 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612 name_len = strnlen(fileName, PATH_MAX);
5613 name_len++; /* trailing null */
5614 strncpy(pSMB->FileName, fileName, name_len);
5615 }
5616
5617 params = 6 + name_len;
5618
5619 /* done calculating parms using name_len of file name,
5620 now use name_len to calculate length of ea name
5621 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005622 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623 name_len = 0;
5624 else
Steve French50c2f752007-07-13 00:33:32 +00005625 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005627 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005629 /* BB find max SMB PDU from sess */
5630 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631 pSMB->MaxSetupCount = 0;
5632 pSMB->Reserved = 0;
5633 pSMB->Flags = 0;
5634 pSMB->Timeout = 0;
5635 pSMB->Reserved2 = 0;
5636 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005637 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 offset = param_offset + params;
5639 pSMB->InformationLevel =
5640 cpu_to_le16(SMB_SET_FILE_EA);
5641
5642 parm_data =
5643 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5644 offset);
5645 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5646 pSMB->DataOffset = cpu_to_le16(offset);
5647 pSMB->SetupCount = 1;
5648 pSMB->Reserved3 = 0;
5649 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5650 byte_count = 3 /* pad */ + params + count;
5651 pSMB->DataCount = cpu_to_le16(count);
5652 parm_data->list_len = cpu_to_le32(count);
5653 parm_data->list[0].EA_flags = 0;
5654 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005655 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005657 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005658 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005659 parm_data->list[0].name[name_len] = 0;
5660 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5661 /* caller ensures that ea_value_len is less than 64K but
5662 we need to ensure that it fits within the smb */
5663
Steve French50c2f752007-07-13 00:33:32 +00005664 /*BB add length check to see if it would fit in
5665 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005666 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5667 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005668 memcpy(parm_data->list[0].name+name_len+1,
5669 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670
5671 pSMB->TotalDataCount = pSMB->DataCount;
5672 pSMB->ParameterCount = cpu_to_le16(params);
5673 pSMB->TotalParameterCount = pSMB->ParameterCount;
5674 pSMB->Reserved4 = 0;
5675 pSMB->hdr.smb_buf_length += byte_count;
5676 pSMB->ByteCount = cpu_to_le16(byte_count);
5677 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005679 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005680 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
5682 cifs_buf_release(pSMB);
5683
5684 if (rc == -EAGAIN)
5685 goto SetEARetry;
5686
5687 return rc;
5688}
5689
5690#endif