blob: 5d3f29fef53228eec75dccac45b2d58697d57775 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
35#include <asm/uaccess.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000038#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42
43#ifdef CONFIG_CIFS_POSIX
44static struct {
45 int index;
46 char *name;
47} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000048#ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000050 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000051#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000052 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000053 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 {BAD_PROT, "\2"}
55};
56#else
57static struct {
58 int index;
59 char *name;
60} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000061#ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000063 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000064#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000065 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 {BAD_PROT, "\2"}
67};
68#endif
69
Steve French39798772006-05-31 22:40:51 +000070/* define the number of elements in the cifs dialect array */
71#ifdef CONFIG_CIFS_POSIX
72#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000073#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000074#else
75#define CIFS_NUM_PROT 2
76#endif /* CIFS_WEAK_PW_HASH */
77#else /* not posix */
78#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000079#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000080#else
81#define CIFS_NUM_PROT 1
82#endif /* CONFIG_CIFS_WEAK_PW_HASH */
83#endif /* CIFS_POSIX */
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000097 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040098 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Jeff Layton9162ab22009-09-03 12:07:17 -0400105/* reconnect the socket, tcon, and smb session if needed */
106static int
107cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
108{
109 int rc = 0;
110 struct cifsSesInfo *ses;
111 struct TCP_Server_Info *server;
112 struct nls_table *nls_codepage;
113
114 /*
115 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
116 * tcp and smb session status done differently for those three - in the
117 * calling routine
118 */
119 if (!tcon)
120 return 0;
121
122 ses = tcon->ses;
123 server = ses->server;
124
125 /*
126 * only tree disconnect, open, and write, (and ulogoff which does not
127 * have tcon) are allowed as we start force umount
128 */
129 if (tcon->tidStatus == CifsExiting) {
130 if (smb_command != SMB_COM_WRITE_ANDX &&
131 smb_command != SMB_COM_OPEN_ANDX &&
132 smb_command != SMB_COM_TREE_DISCONNECT) {
133 cFYI(1, ("can not send cmd %d while umounting",
134 smb_command));
135 return -ENODEV;
136 }
137 }
138
139 if (ses->status == CifsExiting)
140 return -EIO;
141
142 /*
143 * Give demultiplex thread up to 10 seconds to reconnect, should be
144 * greater than cifs socket timeout which is 7 seconds
145 */
146 while (server->tcpStatus == CifsNeedReconnect) {
147 wait_event_interruptible_timeout(server->response_q,
148 (server->tcpStatus == CifsGood), 10 * HZ);
149
150 /* is TCP session is reestablished now ?*/
151 if (server->tcpStatus != CifsNeedReconnect)
152 break;
153
154 /*
155 * on "soft" mounts we wait once. Hard mounts keep
156 * retrying until process is killed or server comes
157 * back on-line
158 */
159 if (!tcon->retry || ses->status == CifsExiting) {
160 cFYI(1, ("gave up waiting on reconnect in smb_init"));
161 return -EHOSTDOWN;
162 }
163 }
164
165 if (!ses->need_reconnect && !tcon->need_reconnect)
166 return 0;
167
168 nls_codepage = load_nls_default();
169
170 /*
171 * need to prevent multiple threads trying to simultaneously
172 * reconnect the same SMB session
173 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000174 mutex_lock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400175 if (ses->need_reconnect)
176 rc = cifs_setup_session(0, ses, nls_codepage);
177
178 /* do we need to reconnect tcon? */
179 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400181 goto out;
182 }
183
184 mark_open_files_invalid(tcon);
185 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000186 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400187 cFYI(1, ("reconnect tcon rc = %d", rc));
188
189 if (rc)
190 goto out;
191
192 /*
193 * FIXME: check if wsize needs updated due to negotiated smb buffer
194 * size shrinking
195 */
196 atomic_inc(&tconInfoReconnectCount);
197
198 /* tell server Unix caps we support */
199 if (ses->capabilities & CAP_UNIX)
200 reset_cifs_unix_caps(0, tcon, NULL, NULL);
201
202 /*
203 * Removed call to reopen open files here. It is safer (and faster) to
204 * reopen files one at a time as needed in read and write.
205 *
206 * FIXME: what about file locks? don't we need to reclaim them ASAP?
207 */
208
209out:
210 /*
211 * Check if handle based operation so we know whether we can continue
212 * or not without returning to caller to reset file handle
213 */
214 switch (smb_command) {
215 case SMB_COM_READ_ANDX:
216 case SMB_COM_WRITE_ANDX:
217 case SMB_COM_CLOSE:
218 case SMB_COM_FIND_CLOSE2:
219 case SMB_COM_LOCKING_ANDX:
220 rc = -EAGAIN;
221 }
222
223 unload_nls(nls_codepage);
224 return rc;
225}
226
Steve Frenchad7a2922008-02-07 23:25:02 +0000227/* Allocate and return pointer to an SMB request buffer, and set basic
228 SMB information in the SMB header. If the return code is zero, this
229 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230static int
231small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000232 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
234 int rc = 0;
235
Jeff Layton9162ab22009-09-03 12:07:17 -0400236 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000237 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 return rc;
239
240 *request_buf = cifs_small_buf_get();
241 if (*request_buf == NULL) {
242 /* BB should we add a retry in here if not a writepage? */
243 return -ENOMEM;
244 }
245
Steve French63135e02007-07-17 17:34:02 +0000246 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000247 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Steve French790fe572007-07-07 19:25:05 +0000249 if (tcon != NULL)
250 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000253}
254
Steve French12b3b8f2006-02-09 21:12:47 +0000255int
Steve French50c2f752007-07-13 00:33:32 +0000256small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000257 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000258{
259 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000260 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000261
Steve French5815449d2006-02-14 01:36:20 +0000262 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000263 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000264 return rc;
265
Steve French04fdabe2006-02-10 05:52:50 +0000266 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000267 buffer->Mid = GetNextMid(ses->server);
268 if (ses->capabilities & CAP_UNICODE)
269 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000270 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
272
273 /* uid, tid can stay at zero as set in header assemble */
274
Steve French50c2f752007-07-13 00:33:32 +0000275 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000276 this function is used after 1st of session setup requests */
277
278 return rc;
279}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281/* If the return code is zero, this function must fill in request_buf pointer */
282static int
283smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
284 void **request_buf /* returned */ ,
285 void **response_buf /* returned */ )
286{
287 int rc = 0;
288
Jeff Layton9162ab22009-09-03 12:07:17 -0400289 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000290 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return rc;
292
293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha45443472005-08-24 13:59:35 -0700310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 return rc;
312}
313
Steve French50c2f752007-07-13 00:33:32 +0000314static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 int rc = -EINVAL;
317 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000318 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 /* check for plausible wct, bcc and t2 data and parm sizes */
321 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000322 if (pSMB->hdr.WordCount >= 10) {
323 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
325 /* check that bcc is at least as big as parms + data */
326 /* check that bcc is less than negotiated smb buffer */
327 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000328 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000329 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000330 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000332 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700333 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000335 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000336 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
338 return 0;
339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 }
341 }
342 }
Steve French50c2f752007-07-13 00:33:32 +0000343 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 sizeof(struct smb_t2_rsp) + 16);
345 return rc;
346}
347int
348CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
349{
350 NEGOTIATE_REQ *pSMB;
351 NEGOTIATE_RSP *pSMBr;
352 int rc = 0;
353 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000354 int i;
Steve French50c2f752007-07-13 00:33:32 +0000355 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000357 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100358 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359
Steve French790fe572007-07-07 19:25:05 +0000360 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 server = ses->server;
362 else {
363 rc = -EIO;
364 return rc;
365 }
366 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
367 (void **) &pSMB, (void **) &pSMBr);
368 if (rc)
369 return rc;
Steve French750d1152006-06-27 06:28:30 +0000370
371 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000372 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000373 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000374 else /* if override flags set only sign/seal OR them with global auth */
375 secFlags = extended_security | ses->overrideSecFlg;
376
Steve French762e5ab2007-06-28 18:41:42 +0000377 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000378
Steve French1982c342005-08-17 12:38:22 -0700379 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000380 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000381
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000382 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000383 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000384 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
385 cFYI(1, ("Kerberos only mechanism, enable extended security"));
386 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
387 }
Steve Frenchac683922009-05-06 04:16:04 +0000388#ifdef CONFIG_CIFS_EXPERIMENTAL
389 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
390 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
391 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
392 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
393 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
394 }
395#endif
Steve French50c2f752007-07-13 00:33:32 +0000396
Steve French39798772006-05-31 22:40:51 +0000397 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000398 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000399 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
400 count += strlen(protocols[i].name) + 1;
401 /* null at end of source and target buffers anyway */
402 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 pSMB->hdr.smb_buf_length += count;
404 pSMB->ByteCount = cpu_to_le16(count);
405
406 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000408 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000409 goto neg_err_exit;
410
Al Viro733f99a2006-10-14 16:48:26 +0100411 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000412 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000413 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000414 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000415 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000416 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000417 could not negotiate a common dialect */
418 rc = -EOPNOTSUPP;
419 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000420#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000421 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100422 && ((dialect == LANMAN_PROT)
423 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000424 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000425 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000426
Steve French790fe572007-07-07 19:25:05 +0000427 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000428 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000429 server->secType = LANMAN;
430 else {
431 cERROR(1, ("mount failed weak security disabled"
432 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000433 rc = -EOPNOTSUPP;
434 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000435 }
Steve French254e55e2006-06-04 05:53:15 +0000436 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
437 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
438 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000439 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000440 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000441 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
442 /* even though we do not use raw we might as well set this
443 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000444 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000445 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000446 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
447 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000448 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000449 server->capabilities = CAP_MPX_MODE;
450 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000451 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000452 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000453 /* OS/2 often does not set timezone therefore
454 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000455 * Could deviate slightly from the right zone.
456 * Smallest defined timezone difference is 15 minutes
457 * (i.e. Nepal). Rounding up/down is done to match
458 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000459 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000460 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000461 struct timespec ts, utc;
462 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400463 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
464 rsp->SrvTime.Time, 0);
Steve French50c2f752007-07-13 00:33:32 +0000465 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
466 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000467 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000468 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000469 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000470 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000472 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000473 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000474 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000475 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000477 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000478 server->timeAdj = (int)tmp;
479 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000480 }
Steve French790fe572007-07-07 19:25:05 +0000481 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000482
Steve French39798772006-05-31 22:40:51 +0000483
Steve French254e55e2006-06-04 05:53:15 +0000484 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000485 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000486
Steve French50c2f752007-07-13 00:33:32 +0000487 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000488 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000489 memcpy(server->cryptKey, rsp->EncryptionKey,
490 CIFS_CRYPTO_KEY_SIZE);
491 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
492 rc = -EIO; /* need cryptkey unless plain text */
493 goto neg_err_exit;
494 }
Steve French39798772006-05-31 22:40:51 +0000495
Steve French790fe572007-07-07 19:25:05 +0000496 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000497 /* we will not end up setting signing flags - as no signing
498 was in LANMAN and server did not return the flags on */
499 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000500#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000501 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000502 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000503 "with CIFS_WEAK_PW_HASH support"));
Dan Carpenter8212cf72010-03-15 11:22:26 +0300504 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000505#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000506 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000507 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000508 /* unknown wct */
509 rc = -EOPNOTSUPP;
510 goto neg_err_exit;
511 }
512 /* else wct == 17 NTLM */
513 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000514 if ((server->secMode & SECMODE_USER) == 0)
515 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000516
Steve French790fe572007-07-07 19:25:05 +0000517 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000518#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000519 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000520#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000521 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000522 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000523
Steve French790fe572007-07-07 19:25:05 +0000524 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000525 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000526 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000527 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000528 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000529 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000530 else if (secFlags & CIFSSEC_MAY_KRB5)
531 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000532 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000533 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000534 else if (secFlags & CIFSSEC_MAY_LANMAN)
535 server->secType = LANMAN;
536/* #ifdef CONFIG_CIFS_EXPERIMENTAL
537 else if (secFlags & CIFSSEC_MAY_PLNTXT)
538 server->secType = ??
539#endif */
540 else {
541 rc = -EOPNOTSUPP;
542 cERROR(1, ("Invalid security type"));
543 goto neg_err_exit;
544 }
545 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000546
Steve French254e55e2006-06-04 05:53:15 +0000547 /* one byte, so no need to convert this or EncryptionKeyLen from
548 little endian */
549 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
550 /* probably no need to store and check maxvcs */
551 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000553 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000554 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000555 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
556 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000557 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
558 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000559 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
560 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
561 CIFS_CRYPTO_KEY_SIZE);
562 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
563 && (pSMBr->EncryptionKeyLength == 0)) {
564 /* decode security blob */
565 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
566 rc = -EIO; /* no crypt key only if plain text pwd */
567 goto neg_err_exit;
568 }
569
570 /* BB might be helpful to save off the domain of server here */
571
Steve French50c2f752007-07-13 00:33:32 +0000572 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000573 (server->capabilities & CAP_EXTENDED_SECURITY)) {
574 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000575 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000577 goto neg_err_exit;
578 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500579 read_lock(&cifs_tcp_ses_lock);
580 if (server->srv_count > 1) {
581 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000582 if (memcmp(server->server_GUID,
583 pSMBr->u.extended_response.
584 GUID, 16) != 0) {
585 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000586 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000587 pSMBr->u.extended_response.GUID,
588 16);
589 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500590 } else {
591 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000592 memcpy(server->server_GUID,
593 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500594 }
Jeff Laytone187e442007-10-16 17:10:44 +0000595
596 if (count == 16) {
597 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000598 } else {
599 rc = decode_negTokenInit(pSMBr->u.extended_response.
600 SecurityBlob,
601 count - 16,
602 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000603 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000604 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000605 else
Steve French254e55e2006-06-04 05:53:15 +0000606 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 }
Steve French254e55e2006-06-04 05:53:15 +0000608 } else
609 server->capabilities &= ~CAP_EXTENDED_SECURITY;
610
Steve French6344a422006-06-12 04:18:35 +0000611#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000612signing_check:
Steve French6344a422006-06-12 04:18:35 +0000613#endif
Steve French762e5ab2007-06-28 18:41:42 +0000614 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
615 /* MUST_SIGN already includes the MAY_SIGN FLAG
616 so if this is zero it means that signing is disabled */
617 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000618 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000619 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000620 "packet signing to be enabled in "
621 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000622 rc = -EOPNOTSUPP;
623 }
Steve French50c2f752007-07-13 00:33:32 +0000624 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000625 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000626 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
627 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000628 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000629 if ((server->secMode &
630 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
631 cERROR(1,
632 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000633 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000634 } else
635 server->secMode |= SECMODE_SIGN_REQUIRED;
636 } else {
637 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000638 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000639 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000640 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 }
Steve French50c2f752007-07-13 00:33:32 +0000642
643neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700644 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000645
Steve French790fe572007-07-07 19:25:05 +0000646 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return rc;
648}
649
650int
651CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
652{
653 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500657
658 /* BB: do we need to check this? These should never be NULL. */
659 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
660 return -EIO;
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500663 * No need to return error on this operation if tid invalidated and
664 * closed on server already e.g. due to tcp session crashing. Also,
665 * the tcon is no longer on the list, so no need to take lock before
666 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 */
Steve French268875b2009-06-25 00:29:21 +0000668 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000669 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Steve French50c2f752007-07-13 00:33:32 +0000671 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700672 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500673 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 return rc;
Steve French133672e2007-11-13 22:41:37 +0000675
676 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700678 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Steve French50c2f752007-07-13 00:33:32 +0000680 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500681 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (rc == -EAGAIN)
683 rc = 0;
684
685 return rc;
686}
687
688int
689CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
690{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 LOGOFF_ANDX_REQ *pSMB;
692 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500695
696 /*
697 * BB: do we need to check validity of ses and server? They should
698 * always be valid since we have an active reference. If not, that
699 * should probably be a BUG()
700 */
701 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 return -EIO;
703
Steve Frenchd7b619c2010-02-25 05:36:46 +0000704 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000705 if (ses->need_reconnect)
706 goto session_already_dead; /* no need to send SMBlogoff if uid
707 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
709 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000710 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return rc;
712 }
713
Steve French3b795212008-11-13 19:45:32 +0000714 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700715
Steve French3b795212008-11-13 19:45:32 +0000716 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
718 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 pSMB->hdr.Uid = ses->Suid;
721
722 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000723 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000724session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000725 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000728 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 error */
730 if (rc == -EAGAIN)
731 rc = 0;
732 return rc;
733}
734
735int
Steve French2d785a52007-07-15 01:48:57 +0000736CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
737 __u16 type, const struct nls_table *nls_codepage, int remap)
738{
739 TRANSACTION2_SPI_REQ *pSMB = NULL;
740 TRANSACTION2_SPI_RSP *pSMBr = NULL;
741 struct unlink_psx_rq *pRqD;
742 int name_len;
743 int rc = 0;
744 int bytes_returned = 0;
745 __u16 params, param_offset, offset, byte_count;
746
747 cFYI(1, ("In POSIX delete"));
748PsxDelete:
749 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
750 (void **) &pSMBr);
751 if (rc)
752 return rc;
753
754 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
755 name_len =
756 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
757 PATH_MAX, nls_codepage, remap);
758 name_len++; /* trailing null */
759 name_len *= 2;
760 } else { /* BB add path length overrun check */
761 name_len = strnlen(fileName, PATH_MAX);
762 name_len++; /* trailing null */
763 strncpy(pSMB->FileName, fileName, name_len);
764 }
765
766 params = 6 + name_len;
767 pSMB->MaxParameterCount = cpu_to_le16(2);
768 pSMB->MaxDataCount = 0; /* BB double check this with jra */
769 pSMB->MaxSetupCount = 0;
770 pSMB->Reserved = 0;
771 pSMB->Flags = 0;
772 pSMB->Timeout = 0;
773 pSMB->Reserved2 = 0;
774 param_offset = offsetof(struct smb_com_transaction2_spi_req,
775 InformationLevel) - 4;
776 offset = param_offset + params;
777
778 /* Setup pointer to Request Data (inode type) */
779 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
780 pRqD->type = cpu_to_le16(type);
781 pSMB->ParameterOffset = cpu_to_le16(param_offset);
782 pSMB->DataOffset = cpu_to_le16(offset);
783 pSMB->SetupCount = 1;
784 pSMB->Reserved3 = 0;
785 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
786 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
787
788 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
789 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
790 pSMB->ParameterCount = cpu_to_le16(params);
791 pSMB->TotalParameterCount = pSMB->ParameterCount;
792 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
793 pSMB->Reserved4 = 0;
794 pSMB->hdr.smb_buf_length += byte_count;
795 pSMB->ByteCount = cpu_to_le16(byte_count);
796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000798 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000799 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000800 cifs_buf_release(pSMB);
801
802 cifs_stats_inc(&tcon->num_deletes);
803
804 if (rc == -EAGAIN)
805 goto PsxDelete;
806
807 return rc;
808}
809
810int
Steve French737b7582005-04-28 22:41:06 -0700811CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
812 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
814 DELETE_FILE_REQ *pSMB = NULL;
815 DELETE_FILE_RSP *pSMBr = NULL;
816 int rc = 0;
817 int bytes_returned;
818 int name_len;
819
820DelFileRetry:
821 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
822 (void **) &pSMBr);
823 if (rc)
824 return rc;
825
826 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
827 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000828 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700829 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 name_len++; /* trailing null */
831 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700832 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 name_len = strnlen(fileName, PATH_MAX);
834 name_len++; /* trailing null */
835 strncpy(pSMB->fileName, fileName, name_len);
836 }
837 pSMB->SearchAttributes =
838 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
839 pSMB->BufferFormat = 0x04;
840 pSMB->hdr.smb_buf_length += name_len + 1;
841 pSMB->ByteCount = cpu_to_le16(name_len + 1);
842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700844 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000845 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847
848 cifs_buf_release(pSMB);
849 if (rc == -EAGAIN)
850 goto DelFileRetry;
851
852 return rc;
853}
854
855int
Steve French50c2f752007-07-13 00:33:32 +0000856CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700857 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858{
859 DELETE_DIRECTORY_REQ *pSMB = NULL;
860 DELETE_DIRECTORY_RSP *pSMBr = NULL;
861 int rc = 0;
862 int bytes_returned;
863 int name_len;
864
865 cFYI(1, ("In CIFSSMBRmDir"));
866RmDirRetry:
867 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
868 (void **) &pSMBr);
869 if (rc)
870 return rc;
871
872 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700873 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
874 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 name_len++; /* trailing null */
876 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700877 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 name_len = strnlen(dirName, PATH_MAX);
879 name_len++; /* trailing null */
880 strncpy(pSMB->DirName, dirName, name_len);
881 }
882
883 pSMB->BufferFormat = 0x04;
884 pSMB->hdr.smb_buf_length += name_len + 1;
885 pSMB->ByteCount = cpu_to_le16(name_len + 1);
886 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
887 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700888 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000889 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892 cifs_buf_release(pSMB);
893 if (rc == -EAGAIN)
894 goto RmDirRetry;
895 return rc;
896}
897
898int
899CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700900 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901{
902 int rc = 0;
903 CREATE_DIRECTORY_REQ *pSMB = NULL;
904 CREATE_DIRECTORY_RSP *pSMBr = NULL;
905 int bytes_returned;
906 int name_len;
907
908 cFYI(1, ("In CIFSSMBMkDir"));
909MkDirRetry:
910 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
911 (void **) &pSMBr);
912 if (rc)
913 return rc;
914
915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000916 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700917 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 name_len++; /* trailing null */
919 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700920 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 name_len = strnlen(name, PATH_MAX);
922 name_len++; /* trailing null */
923 strncpy(pSMB->DirName, name, name_len);
924 }
925
926 pSMB->BufferFormat = 0x04;
927 pSMB->hdr.smb_buf_length += name_len + 1;
928 pSMB->ByteCount = cpu_to_le16(name_len + 1);
929 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700931 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000932 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -0700934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 cifs_buf_release(pSMB);
936 if (rc == -EAGAIN)
937 goto MkDirRetry;
938 return rc;
939}
940
Steve French2dd29d32007-04-23 22:07:35 +0000941int
942CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000943 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000944 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000945 const struct nls_table *nls_codepage, int remap)
946{
947 TRANSACTION2_SPI_REQ *pSMB = NULL;
948 TRANSACTION2_SPI_RSP *pSMBr = NULL;
949 int name_len;
950 int rc = 0;
951 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +0000952 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +0000953 OPEN_PSX_REQ *pdata;
954 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +0000955
956 cFYI(1, ("In POSIX Create"));
957PsxCreat:
958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
959 (void **) &pSMBr);
960 if (rc)
961 return rc;
962
963 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
964 name_len =
965 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
966 PATH_MAX, nls_codepage, remap);
967 name_len++; /* trailing null */
968 name_len *= 2;
969 } else { /* BB improve the check for buffer overruns BB */
970 name_len = strnlen(name, PATH_MAX);
971 name_len++; /* trailing null */
972 strncpy(pSMB->FileName, name, name_len);
973 }
974
975 params = 6 + name_len;
976 count = sizeof(OPEN_PSX_REQ);
977 pSMB->MaxParameterCount = cpu_to_le16(2);
978 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
979 pSMB->MaxSetupCount = 0;
980 pSMB->Reserved = 0;
981 pSMB->Flags = 0;
982 pSMB->Timeout = 0;
983 pSMB->Reserved2 = 0;
984 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000985 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000986 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +0000987 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000988 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +0000989 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000990 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000991 pdata->OpenFlags = cpu_to_le32(*pOplock);
992 pSMB->ParameterOffset = cpu_to_le16(param_offset);
993 pSMB->DataOffset = cpu_to_le16(offset);
994 pSMB->SetupCount = 1;
995 pSMB->Reserved3 = 0;
996 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
997 byte_count = 3 /* pad */ + params + count;
998
999 pSMB->DataCount = cpu_to_le16(count);
1000 pSMB->ParameterCount = cpu_to_le16(params);
1001 pSMB->TotalDataCount = pSMB->DataCount;
1002 pSMB->TotalParameterCount = pSMB->ParameterCount;
1003 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1004 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001005 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001006 pSMB->ByteCount = cpu_to_le16(byte_count);
1007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1009 if (rc) {
1010 cFYI(1, ("Posix create returned %d", rc));
1011 goto psx_create_err;
1012 }
1013
Steve French790fe572007-07-07 19:25:05 +00001014 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001015 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1016
1017 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1018 rc = -EIO; /* bad smb */
1019 goto psx_create_err;
1020 }
1021
1022 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001023 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001024 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001025
Steve French2dd29d32007-04-23 22:07:35 +00001026 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001027 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001028 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1029 /* Let caller know file was created so we can set the mode. */
1030 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001031 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001032 *pOplock |= CIFS_CREATE_ACTION;
1033 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001034 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1035 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001036 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001037 } else {
Steve French790fe572007-07-07 19:25:05 +00001038 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001039 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001040 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001041 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001042 goto psx_create_err;
1043 }
Steve French50c2f752007-07-13 00:33:32 +00001044 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001045 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001046 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001047 }
Steve French2dd29d32007-04-23 22:07:35 +00001048
1049psx_create_err:
1050 cifs_buf_release(pSMB);
1051
Steve French65bc98b2009-07-10 15:27:25 +00001052 if (posix_flags & SMB_O_DIRECTORY)
1053 cifs_stats_inc(&tcon->num_posixmkdirs);
1054 else
1055 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001056
1057 if (rc == -EAGAIN)
1058 goto PsxCreat;
1059
Steve French50c2f752007-07-13 00:33:32 +00001060 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001061}
1062
Steve Frencha9d02ad2005-08-24 23:06:05 -07001063static __u16 convert_disposition(int disposition)
1064{
1065 __u16 ofun = 0;
1066
1067 switch (disposition) {
1068 case FILE_SUPERSEDE:
1069 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1070 break;
1071 case FILE_OPEN:
1072 ofun = SMBOPEN_OAPPEND;
1073 break;
1074 case FILE_CREATE:
1075 ofun = SMBOPEN_OCREATE;
1076 break;
1077 case FILE_OPEN_IF:
1078 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1079 break;
1080 case FILE_OVERWRITE:
1081 ofun = SMBOPEN_OTRUNC;
1082 break;
1083 case FILE_OVERWRITE_IF:
1084 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1085 break;
1086 default:
Steve French790fe572007-07-07 19:25:05 +00001087 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001088 ofun = SMBOPEN_OAPPEND; /* regular open */
1089 }
1090 return ofun;
1091}
1092
Jeff Layton35fc37d2008-05-14 10:22:03 -07001093static int
1094access_flags_to_smbopen_mode(const int access_flags)
1095{
1096 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1097
1098 if (masked_flags == GENERIC_READ)
1099 return SMBOPEN_READ;
1100 else if (masked_flags == GENERIC_WRITE)
1101 return SMBOPEN_WRITE;
1102
1103 /* just go for read/write */
1104 return SMBOPEN_READWRITE;
1105}
1106
Steve Frencha9d02ad2005-08-24 23:06:05 -07001107int
1108SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1109 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001110 const int access_flags, const int create_options, __u16 *netfid,
1111 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001112 const struct nls_table *nls_codepage, int remap)
1113{
1114 int rc = -EACCES;
1115 OPENX_REQ *pSMB = NULL;
1116 OPENX_RSP *pSMBr = NULL;
1117 int bytes_returned;
1118 int name_len;
1119 __u16 count;
1120
1121OldOpenRetry:
1122 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1123 (void **) &pSMBr);
1124 if (rc)
1125 return rc;
1126
1127 pSMB->AndXCommand = 0xFF; /* none */
1128
1129 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1130 count = 1; /* account for one byte pad to word boundary */
1131 name_len =
1132 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1133 fileName, PATH_MAX, nls_codepage, remap);
1134 name_len++; /* trailing null */
1135 name_len *= 2;
1136 } else { /* BB improve check for buffer overruns BB */
1137 count = 0; /* no pad */
1138 name_len = strnlen(fileName, PATH_MAX);
1139 name_len++; /* trailing null */
1140 strncpy(pSMB->fileName, fileName, name_len);
1141 }
1142 if (*pOplock & REQ_OPLOCK)
1143 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001144 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001145 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001146
Steve Frencha9d02ad2005-08-24 23:06:05 -07001147 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001148 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001149 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1150 /* set file as system file if special file such
1151 as fifo and server expecting SFU style and
1152 no Unix extensions */
1153
Steve French790fe572007-07-07 19:25:05 +00001154 if (create_options & CREATE_OPTION_SPECIAL)
1155 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001156 else /* BB FIXME BB */
1157 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001158
Jeff Layton67750fb2008-05-09 22:28:02 +00001159 if (create_options & CREATE_OPTION_READONLY)
1160 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001161
1162 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001163/* pSMB->CreateOptions = cpu_to_le32(create_options &
1164 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001165 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001166
1167 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001168 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169 count += name_len;
1170 pSMB->hdr.smb_buf_length += count;
1171
1172 pSMB->ByteCount = cpu_to_le16(count);
1173 /* long_op set to 1 to allow for oplock break timeouts */
1174 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001175 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001176 cifs_stats_inc(&tcon->num_opens);
1177 if (rc) {
1178 cFYI(1, ("Error in Open = %d", rc));
1179 } else {
1180 /* BB verify if wct == 15 */
1181
Steve French582d21e2008-05-13 04:54:12 +00001182/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001183
1184 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1185 /* Let caller know file was created so we can set the mode. */
1186 /* Do we care about the CreateAction in any other cases? */
1187 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001188/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001189 *pOplock |= CIFS_CREATE_ACTION; */
1190 /* BB FIXME END */
1191
Steve French790fe572007-07-07 19:25:05 +00001192 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001193 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1194 pfile_info->LastAccessTime = 0; /* BB fixme */
1195 pfile_info->LastWriteTime = 0; /* BB fixme */
1196 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001197 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001198 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001199 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001200 pfile_info->AllocationSize =
1201 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1202 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001203 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001204 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001205 }
1206 }
1207
1208 cifs_buf_release(pSMB);
1209 if (rc == -EAGAIN)
1210 goto OldOpenRetry;
1211 return rc;
1212}
1213
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214int
1215CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1216 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001217 const int access_flags, const int create_options, __u16 *netfid,
1218 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001219 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220{
1221 int rc = -EACCES;
1222 OPEN_REQ *pSMB = NULL;
1223 OPEN_RSP *pSMBr = NULL;
1224 int bytes_returned;
1225 int name_len;
1226 __u16 count;
1227
1228openRetry:
1229 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1230 (void **) &pSMBr);
1231 if (rc)
1232 return rc;
1233
1234 pSMB->AndXCommand = 0xFF; /* none */
1235
1236 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1237 count = 1; /* account for one byte pad to word boundary */
1238 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001239 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001240 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 name_len++; /* trailing null */
1242 name_len *= 2;
1243 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001244 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 count = 0; /* no pad */
1246 name_len = strnlen(fileName, PATH_MAX);
1247 name_len++; /* trailing null */
1248 pSMB->NameLength = cpu_to_le16(name_len);
1249 strncpy(pSMB->fileName, fileName, name_len);
1250 }
1251 if (*pOplock & REQ_OPLOCK)
1252 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001253 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1256 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001257 /* set file as system file if special file such
1258 as fifo and server expecting SFU style and
1259 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001260 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001261 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1262 else
1263 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001264
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 /* XP does not handle ATTR_POSIX_SEMANTICS */
1266 /* but it helps speed up case sensitive checks for other
1267 servers such as Samba */
1268 if (tcon->ses->capabilities & CAP_UNIX)
1269 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1270
Jeff Layton67750fb2008-05-09 22:28:02 +00001271 if (create_options & CREATE_OPTION_READONLY)
1272 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1275 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001276 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001277 /* BB Expirement with various impersonation levels and verify */
1278 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 pSMB->SecurityFlags =
1280 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1281
1282 count += name_len;
1283 pSMB->hdr.smb_buf_length += count;
1284
1285 pSMB->ByteCount = cpu_to_le16(count);
1286 /* long_op set to 1 to allow for oplock break timeouts */
1287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001288 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha45443472005-08-24 13:59:35 -07001289 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 if (rc) {
1291 cFYI(1, ("Error in Open = %d", rc));
1292 } else {
Steve French09d1db52005-04-28 22:41:08 -07001293 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1295 /* Let caller know file was created so we can set the mode. */
1296 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001297 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001298 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001299 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001300 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1301 36 /* CreationTime to Attributes */);
1302 /* the file_info buf is endian converted by caller */
1303 pfile_info->AllocationSize = pSMBr->AllocationSize;
1304 pfile_info->EndOfFile = pSMBr->EndOfFile;
1305 pfile_info->NumberOfLinks = cpu_to_le32(1);
1306 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001309
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 cifs_buf_release(pSMB);
1311 if (rc == -EAGAIN)
1312 goto openRetry;
1313 return rc;
1314}
1315
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316int
Steve French50c2f752007-07-13 00:33:32 +00001317CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1318 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1319 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
1321 int rc = -EACCES;
1322 READ_REQ *pSMB = NULL;
1323 READ_RSP *pSMBr = NULL;
1324 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001325 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001326 int resp_buf_type = 0;
1327 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328
Steve French790fe572007-07-07 19:25:05 +00001329 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1330 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001331 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001332 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001333 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001334 if ((lseek >> 32) > 0) {
1335 /* can not handle this big offset for old */
1336 return -EIO;
1337 }
1338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339
1340 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001341 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 if (rc)
1343 return rc;
1344
1345 /* tcon and ses pointer are checked in smb_init */
1346 if (tcon->ses->server == NULL)
1347 return -ECONNABORTED;
1348
Steve Frenchec637e32005-12-12 20:53:18 -08001349 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->Fid = netfid;
1351 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001352 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001353 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001354
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 pSMB->Remaining = 0;
1356 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1357 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001358 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001359 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1360 else {
1361 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001362 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001363 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001364 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001365 }
Steve Frenchec637e32005-12-12 20:53:18 -08001366
1367 iov[0].iov_base = (char *)pSMB;
1368 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001369 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001370 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha45443472005-08-24 13:59:35 -07001371 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001372 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 if (rc) {
1374 cERROR(1, ("Send error in read = %d", rc));
1375 } else {
1376 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1377 data_length = data_length << 16;
1378 data_length += le16_to_cpu(pSMBr->DataLength);
1379 *nbytes = data_length;
1380
1381 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001382 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001384 cFYI(1, ("bad length %d for count %d",
1385 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 rc = -EIO;
1387 *nbytes = 0;
1388 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001389 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001390 le16_to_cpu(pSMBr->DataOffset);
1391/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001392 cERROR(1,("Faulting on read rc = %d",rc));
1393 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001394 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001395 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001396 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 }
1398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Steve French4b8f9302006-02-26 16:41:18 +00001400/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001401 if (*buf) {
1402 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001403 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001404 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001405 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001406 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001407 /* return buffer to caller to free */
1408 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001409 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001410 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001411 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001412 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001413 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001414
1415 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 since file handle passed in no longer valid */
1417 return rc;
1418}
1419
Steve Frenchec637e32005-12-12 20:53:18 -08001420
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421int
1422CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1423 const int netfid, const unsigned int count,
1424 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001425 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426{
1427 int rc = -EACCES;
1428 WRITE_REQ *pSMB = NULL;
1429 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001430 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 __u32 bytes_sent;
1432 __u16 byte_count;
1433
Steve Frencha24e2d72010-04-03 17:20:21 +00001434 *nbytes = 0;
1435
Steve French61de8002008-10-30 20:15:22 +00001436 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001437 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001438 return -ECONNABORTED;
1439
Steve French790fe572007-07-07 19:25:05 +00001440 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001441 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001442 else {
Steve French1c955182005-08-30 20:58:07 -07001443 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001444 if ((offset >> 32) > 0) {
1445 /* can not handle big offset for old srv */
1446 return -EIO;
1447 }
1448 }
Steve French1c955182005-08-30 20:58:07 -07001449
1450 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 (void **) &pSMBr);
1452 if (rc)
1453 return rc;
1454 /* tcon and ses pointer are checked in smb_init */
1455 if (tcon->ses->server == NULL)
1456 return -ECONNABORTED;
1457
1458 pSMB->AndXCommand = 0xFF; /* none */
1459 pSMB->Fid = netfid;
1460 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001461 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001462 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001463
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 pSMB->Reserved = 0xFFFFFFFF;
1465 pSMB->WriteMode = 0;
1466 pSMB->Remaining = 0;
1467
Steve French50c2f752007-07-13 00:33:32 +00001468 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 can send more if LARGE_WRITE_X capability returned by the server and if
1470 our buffer is big enough or if we convert to iovecs on socket writes
1471 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001472 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1474 } else {
1475 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1476 & ~0xFF;
1477 }
1478
1479 if (bytes_sent > count)
1480 bytes_sent = count;
1481 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001482 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001483 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001484 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001485 else if (ubuf) {
1486 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 cifs_buf_release(pSMB);
1488 return -EFAULT;
1489 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001490 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 /* No buffer */
1492 cifs_buf_release(pSMB);
1493 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001494 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001495 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001496 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001497 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001498 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1501 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001502 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001503
Steve French790fe572007-07-07 19:25:05 +00001504 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001505 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001506 else { /* old style write has byte count 4 bytes earlier
1507 so 4 bytes pad */
1508 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001509 (struct smb_com_writex_req *)pSMB;
1510 pSMBW->ByteCount = cpu_to_le16(byte_count);
1511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
1513 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1514 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001515 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 if (rc) {
1517 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 } else {
1519 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1520 *nbytes = (*nbytes) << 16;
1521 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301522
1523 /*
1524 * Mask off high 16 bits when bytes written as returned by the
1525 * server is greater than bytes requested by the client. Some
1526 * OS/2 servers are known to set incorrect CountHigh values.
1527 */
1528 if (*nbytes > count)
1529 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 }
1531
1532 cifs_buf_release(pSMB);
1533
Steve French50c2f752007-07-13 00:33:32 +00001534 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 since file handle passed in no longer valid */
1536
1537 return rc;
1538}
1539
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001540int
1541CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001543 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1544 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
1546 int rc = -EACCES;
1547 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001548 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001549 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001550 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001552 *nbytes = 0;
1553
Steve French790fe572007-07-07 19:25:05 +00001554 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001555
Steve French4c3130e2008-12-09 00:28:16 +00001556 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001557 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001558 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001559 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001560 if ((offset >> 32) > 0) {
1561 /* can not handle big offset for old srv */
1562 return -EIO;
1563 }
1564 }
Steve French8cc64c62005-10-03 13:49:43 -07001565 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if (rc)
1567 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 /* tcon and ses pointer are checked in smb_init */
1569 if (tcon->ses->server == NULL)
1570 return -ECONNABORTED;
1571
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001572 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 pSMB->Fid = netfid;
1574 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001575 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001576 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 pSMB->Reserved = 0xFFFFFFFF;
1578 pSMB->WriteMode = 0;
1579 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001580
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001582 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Steve French3e844692005-10-03 13:37:24 -07001584 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1585 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001586 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001587 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001588 pSMB->hdr.smb_buf_length += count+1;
1589 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001590 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1591 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001592 pSMB->ByteCount = cpu_to_le16(count + 1);
1593 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001594 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001595 (struct smb_com_writex_req *)pSMB;
1596 pSMBW->ByteCount = cpu_to_le16(count + 5);
1597 }
Steve French3e844692005-10-03 13:37:24 -07001598 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001599 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001600 iov[0].iov_len = smb_hdr_len + 4;
1601 else /* wct == 12 pad bigger by four bytes */
1602 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001603
Steve French3e844692005-10-03 13:37:24 -07001604
Steve Frenchec637e32005-12-12 20:53:18 -08001605 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001606 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001607 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001609 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001610 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001611 /* presumably this can not happen, but best to be safe */
1612 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001613 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001614 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001615 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1616 *nbytes = (*nbytes) << 16;
1617 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301618
1619 /*
1620 * Mask off high 16 bits when bytes written as returned by the
1621 * server is greater than bytes requested by the client. OS/2
1622 * servers are known to set incorrect CountHigh values.
1623 */
1624 if (*nbytes > count)
1625 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
Steve French4b8f9302006-02-26 16:41:18 +00001628/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001629 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001630 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001631 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001632 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Steve French50c2f752007-07-13 00:33:32 +00001634 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 since file handle passed in no longer valid */
1636
1637 return rc;
1638}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001639
1640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641int
1642CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1643 const __u16 smb_file_id, const __u64 len,
1644 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001645 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646{
1647 int rc = 0;
1648 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001649/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650 int bytes_returned;
1651 int timeout = 0;
1652 __u16 count;
1653
Steve French4b18f2a2008-04-29 00:06:05 +00001654 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001655 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 if (rc)
1658 return rc;
1659
Steve French790fe572007-07-07 19:25:05 +00001660 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001661 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001663 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001664 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1666 } else {
1667 pSMB->Timeout = 0;
1668 }
1669
1670 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1671 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1672 pSMB->LockType = lockType;
1673 pSMB->AndXCommand = 0xFF; /* none */
1674 pSMB->Fid = smb_file_id; /* netfid stays le */
1675
Steve French790fe572007-07-07 19:25:05 +00001676 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1678 /* BB where to store pid high? */
1679 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1680 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1681 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1682 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1683 count = sizeof(LOCKING_ANDX_RANGE);
1684 } else {
1685 /* oplock break */
1686 count = 0;
1687 }
1688 pSMB->hdr.smb_buf_length += count;
1689 pSMB->ByteCount = cpu_to_le16(count);
1690
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001691 if (waitFlag) {
1692 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001693 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001694 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001695 } else {
Steve French133672e2007-11-13 22:41:37 +00001696 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1697 timeout);
1698 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001699 }
Steve Frencha45443472005-08-24 13:59:35 -07001700 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001701 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
Steve French50c2f752007-07-13 00:33:32 +00001704 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 since file handle passed in no longer valid */
1706 return rc;
1707}
1708
1709int
Steve French08547b02006-02-28 22:39:25 +00001710CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1711 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001712 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001713 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001714{
1715 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1716 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001717 struct cifs_posix_lock *parm_data;
1718 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001719 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001720 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001721 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001722 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001723 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001724
1725 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001726
Steve French790fe572007-07-07 19:25:05 +00001727 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001728 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001729
Steve French08547b02006-02-28 22:39:25 +00001730 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1731
1732 if (rc)
1733 return rc;
1734
1735 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1736
Steve French50c2f752007-07-13 00:33:32 +00001737 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001738 pSMB->MaxSetupCount = 0;
1739 pSMB->Reserved = 0;
1740 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001741 pSMB->Reserved2 = 0;
1742 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1743 offset = param_offset + params;
1744
Steve French08547b02006-02-28 22:39:25 +00001745 count = sizeof(struct cifs_posix_lock);
1746 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001747 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001748 pSMB->SetupCount = 1;
1749 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001750 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001751 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1752 else
1753 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1754 byte_count = 3 /* pad */ + params + count;
1755 pSMB->DataCount = cpu_to_le16(count);
1756 pSMB->ParameterCount = cpu_to_le16(params);
1757 pSMB->TotalDataCount = pSMB->DataCount;
1758 pSMB->TotalParameterCount = pSMB->ParameterCount;
1759 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001760 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001761 (((char *) &pSMB->hdr.Protocol) + offset);
1762
1763 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001764 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001765 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001766 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001767 pSMB->Timeout = cpu_to_le32(-1);
1768 } else
1769 pSMB->Timeout = 0;
1770
Steve French08547b02006-02-28 22:39:25 +00001771 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001772 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001773 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001774
1775 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001776 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001777 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1778 pSMB->Reserved4 = 0;
1779 pSMB->hdr.smb_buf_length += byte_count;
1780 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001781 if (waitFlag) {
1782 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1783 (struct smb_hdr *) pSMBr, &bytes_returned);
1784 } else {
Steve French133672e2007-11-13 22:41:37 +00001785 iov[0].iov_base = (char *)pSMB;
1786 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1787 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1788 &resp_buf_type, timeout);
1789 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1790 not try to free it twice below on exit */
1791 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001792 }
1793
Steve French08547b02006-02-28 22:39:25 +00001794 if (rc) {
1795 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001796 } else if (get_flag) {
1797 /* lock structure can be returned on get */
1798 __u16 data_offset;
1799 __u16 data_count;
1800 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001801
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001802 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1803 rc = -EIO; /* bad smb */
1804 goto plk_err_exit;
1805 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001806 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1807 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001808 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001809 rc = -EIO;
1810 goto plk_err_exit;
1811 }
1812 parm_data = (struct cifs_posix_lock *)
1813 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001814 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001815 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001816 else {
1817 if (parm_data->lock_type ==
1818 __constant_cpu_to_le16(CIFS_RDLCK))
1819 pLockData->fl_type = F_RDLCK;
1820 else if (parm_data->lock_type ==
1821 __constant_cpu_to_le16(CIFS_WRLCK))
1822 pLockData->fl_type = F_WRLCK;
1823
1824 pLockData->fl_start = parm_data->start;
1825 pLockData->fl_end = parm_data->start +
1826 parm_data->length - 1;
1827 pLockData->fl_pid = parm_data->pid;
1828 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001829 }
Steve French50c2f752007-07-13 00:33:32 +00001830
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001831plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001832 if (pSMB)
1833 cifs_small_buf_release(pSMB);
1834
Steve French133672e2007-11-13 22:41:37 +00001835 if (resp_buf_type == CIFS_SMALL_BUFFER)
1836 cifs_small_buf_release(iov[0].iov_base);
1837 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1838 cifs_buf_release(iov[0].iov_base);
1839
Steve French08547b02006-02-28 22:39:25 +00001840 /* Note: On -EAGAIN error only caller can retry on handle based calls
1841 since file handle passed in no longer valid */
1842
1843 return rc;
1844}
1845
1846
1847int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1849{
1850 int rc = 0;
1851 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 cFYI(1, ("In CIFSSMBClose"));
1853
1854/* do not retry on dead session on close */
1855 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001856 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 return 0;
1858 if (rc)
1859 return rc;
1860
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001862 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001864 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001865 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001867 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 /* EINTR is expected when user ctl-c to kill app */
1869 cERROR(1, ("Send error in Close = %d", rc));
1870 }
1871 }
1872
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001874 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875 rc = 0;
1876
1877 return rc;
1878}
1879
1880int
Steve Frenchb298f222009-02-21 21:17:43 +00001881CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1882{
1883 int rc = 0;
1884 FLUSH_REQ *pSMB = NULL;
1885 cFYI(1, ("In CIFSSMBFlush"));
1886
1887 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1888 if (rc)
1889 return rc;
1890
1891 pSMB->FileID = (__u16) smb_file_id;
1892 pSMB->ByteCount = 0;
1893 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1894 cifs_stats_inc(&tcon->num_flushes);
1895 if (rc)
1896 cERROR(1, ("Send error in Flush = %d", rc));
1897
1898 return rc;
1899}
1900
1901int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1903 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001904 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905{
1906 int rc = 0;
1907 RENAME_REQ *pSMB = NULL;
1908 RENAME_RSP *pSMBr = NULL;
1909 int bytes_returned;
1910 int name_len, name_len2;
1911 __u16 count;
1912
1913 cFYI(1, ("In CIFSSMBRename"));
1914renameRetry:
1915 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1916 (void **) &pSMBr);
1917 if (rc)
1918 return rc;
1919
1920 pSMB->BufferFormat = 0x04;
1921 pSMB->SearchAttributes =
1922 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1923 ATTR_DIRECTORY);
1924
1925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1926 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001927 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001928 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 name_len++; /* trailing null */
1930 name_len *= 2;
1931 pSMB->OldFileName[name_len] = 0x04; /* pad */
1932 /* protocol requires ASCII signature byte on Unicode string */
1933 pSMB->OldFileName[name_len + 1] = 0x00;
1934 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001935 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001936 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1938 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001939 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 name_len = strnlen(fromName, PATH_MAX);
1941 name_len++; /* trailing null */
1942 strncpy(pSMB->OldFileName, fromName, name_len);
1943 name_len2 = strnlen(toName, PATH_MAX);
1944 name_len2++; /* trailing null */
1945 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1946 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1947 name_len2++; /* trailing null */
1948 name_len2++; /* signature byte */
1949 }
1950
1951 count = 1 /* 1st signature byte */ + name_len + name_len2;
1952 pSMB->hdr.smb_buf_length += count;
1953 pSMB->ByteCount = cpu_to_le16(count);
1954
1955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001957 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001958 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 cifs_buf_release(pSMB);
1962
1963 if (rc == -EAGAIN)
1964 goto renameRetry;
1965
1966 return rc;
1967}
1968
Steve French50c2f752007-07-13 00:33:32 +00001969int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001970 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001971 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972{
1973 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1974 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001975 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 char *data_offset;
1977 char dummy_string[30];
1978 int rc = 0;
1979 int bytes_returned = 0;
1980 int len_of_str;
1981 __u16 params, param_offset, offset, count, byte_count;
1982
1983 cFYI(1, ("Rename to File by handle"));
1984 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1985 (void **) &pSMBr);
1986 if (rc)
1987 return rc;
1988
1989 params = 6;
1990 pSMB->MaxSetupCount = 0;
1991 pSMB->Reserved = 0;
1992 pSMB->Flags = 0;
1993 pSMB->Timeout = 0;
1994 pSMB->Reserved2 = 0;
1995 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1996 offset = param_offset + params;
1997
1998 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1999 rename_info = (struct set_file_rename *) data_offset;
2000 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002001 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 pSMB->SetupCount = 1;
2003 pSMB->Reserved3 = 0;
2004 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2005 byte_count = 3 /* pad */ + params;
2006 pSMB->ParameterCount = cpu_to_le16(params);
2007 pSMB->TotalParameterCount = pSMB->ParameterCount;
2008 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2009 pSMB->DataOffset = cpu_to_le16(offset);
2010 /* construct random name ".cifs_tmp<inodenum><mid>" */
2011 rename_info->overwrite = cpu_to_le32(1);
2012 rename_info->root_fid = 0;
2013 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002014 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002015 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2016 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002017 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002019 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002020 target_name, PATH_MAX, nls_codepage,
2021 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 }
2023 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002024 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002025 byte_count += count;
2026 pSMB->DataCount = cpu_to_le16(count);
2027 pSMB->TotalDataCount = pSMB->DataCount;
2028 pSMB->Fid = netfid;
2029 pSMB->InformationLevel =
2030 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2031 pSMB->Reserved4 = 0;
2032 pSMB->hdr.smb_buf_length += byte_count;
2033 pSMB->ByteCount = cpu_to_le16(byte_count);
2034 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002035 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002036 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002037 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002038 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002039
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 cifs_buf_release(pSMB);
2041
2042 /* Note: On -EAGAIN error only caller can retry on handle based calls
2043 since file handle passed in no longer valid */
2044
2045 return rc;
2046}
2047
2048int
Steve French50c2f752007-07-13 00:33:32 +00002049CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2050 const __u16 target_tid, const char *toName, const int flags,
2051 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052{
2053 int rc = 0;
2054 COPY_REQ *pSMB = NULL;
2055 COPY_RSP *pSMBr = NULL;
2056 int bytes_returned;
2057 int name_len, name_len2;
2058 __u16 count;
2059
2060 cFYI(1, ("In CIFSSMBCopy"));
2061copyRetry:
2062 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2063 (void **) &pSMBr);
2064 if (rc)
2065 return rc;
2066
2067 pSMB->BufferFormat = 0x04;
2068 pSMB->Tid2 = target_tid;
2069
2070 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2071
2072 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002073 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002074 fromName, PATH_MAX, nls_codepage,
2075 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 name_len++; /* trailing null */
2077 name_len *= 2;
2078 pSMB->OldFileName[name_len] = 0x04; /* pad */
2079 /* protocol requires ASCII signature byte on Unicode string */
2080 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002081 name_len2 =
2082 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002083 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2085 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002086 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 name_len = strnlen(fromName, PATH_MAX);
2088 name_len++; /* trailing null */
2089 strncpy(pSMB->OldFileName, fromName, name_len);
2090 name_len2 = strnlen(toName, PATH_MAX);
2091 name_len2++; /* trailing null */
2092 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2093 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2094 name_len2++; /* trailing null */
2095 name_len2++; /* signature byte */
2096 }
2097
2098 count = 1 /* 1st signature byte */ + name_len + name_len2;
2099 pSMB->hdr.smb_buf_length += count;
2100 pSMB->ByteCount = cpu_to_le16(count);
2101
2102 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2104 if (rc) {
2105 cFYI(1, ("Send error in copy = %d with %d files copied",
2106 rc, le16_to_cpu(pSMBr->CopyCount)));
2107 }
Steve French0d817bc2008-05-22 02:02:03 +00002108 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
2110 if (rc == -EAGAIN)
2111 goto copyRetry;
2112
2113 return rc;
2114}
2115
2116int
2117CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2118 const char *fromName, const char *toName,
2119 const struct nls_table *nls_codepage)
2120{
2121 TRANSACTION2_SPI_REQ *pSMB = NULL;
2122 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2123 char *data_offset;
2124 int name_len;
2125 int name_len_target;
2126 int rc = 0;
2127 int bytes_returned = 0;
2128 __u16 params, param_offset, offset, byte_count;
2129
2130 cFYI(1, ("In Symlink Unix style"));
2131createSymLinkRetry:
2132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2133 (void **) &pSMBr);
2134 if (rc)
2135 return rc;
2136
2137 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2138 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002139 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 /* find define for this maxpathcomponent */
2141 , nls_codepage);
2142 name_len++; /* trailing null */
2143 name_len *= 2;
2144
Steve French50c2f752007-07-13 00:33:32 +00002145 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 name_len = strnlen(fromName, PATH_MAX);
2147 name_len++; /* trailing null */
2148 strncpy(pSMB->FileName, fromName, name_len);
2149 }
2150 params = 6 + name_len;
2151 pSMB->MaxSetupCount = 0;
2152 pSMB->Reserved = 0;
2153 pSMB->Flags = 0;
2154 pSMB->Timeout = 0;
2155 pSMB->Reserved2 = 0;
2156 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002157 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 offset = param_offset + params;
2159
2160 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2162 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002163 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 /* find define for this maxpathcomponent */
2165 , nls_codepage);
2166 name_len_target++; /* trailing null */
2167 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002168 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 name_len_target = strnlen(toName, PATH_MAX);
2170 name_len_target++; /* trailing null */
2171 strncpy(data_offset, toName, name_len_target);
2172 }
2173
2174 pSMB->MaxParameterCount = cpu_to_le16(2);
2175 /* BB find exact max on data count below from sess */
2176 pSMB->MaxDataCount = cpu_to_le16(1000);
2177 pSMB->SetupCount = 1;
2178 pSMB->Reserved3 = 0;
2179 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2180 byte_count = 3 /* pad */ + params + name_len_target;
2181 pSMB->DataCount = cpu_to_le16(name_len_target);
2182 pSMB->ParameterCount = cpu_to_le16(params);
2183 pSMB->TotalDataCount = pSMB->DataCount;
2184 pSMB->TotalParameterCount = pSMB->ParameterCount;
2185 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2186 pSMB->DataOffset = cpu_to_le16(offset);
2187 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2188 pSMB->Reserved4 = 0;
2189 pSMB->hdr.smb_buf_length += byte_count;
2190 pSMB->ByteCount = cpu_to_le16(byte_count);
2191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2192 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002193 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002194 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002195 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
Steve French0d817bc2008-05-22 02:02:03 +00002197 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
2199 if (rc == -EAGAIN)
2200 goto createSymLinkRetry;
2201
2202 return rc;
2203}
2204
2205int
2206CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2207 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002208 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209{
2210 TRANSACTION2_SPI_REQ *pSMB = NULL;
2211 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2212 char *data_offset;
2213 int name_len;
2214 int name_len_target;
2215 int rc = 0;
2216 int bytes_returned = 0;
2217 __u16 params, param_offset, offset, byte_count;
2218
2219 cFYI(1, ("In Create Hard link Unix style"));
2220createHardLinkRetry:
2221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2222 (void **) &pSMBr);
2223 if (rc)
2224 return rc;
2225
2226 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002227 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002228 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 name_len++; /* trailing null */
2230 name_len *= 2;
2231
Steve French50c2f752007-07-13 00:33:32 +00002232 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 name_len = strnlen(toName, PATH_MAX);
2234 name_len++; /* trailing null */
2235 strncpy(pSMB->FileName, toName, name_len);
2236 }
2237 params = 6 + name_len;
2238 pSMB->MaxSetupCount = 0;
2239 pSMB->Reserved = 0;
2240 pSMB->Flags = 0;
2241 pSMB->Timeout = 0;
2242 pSMB->Reserved2 = 0;
2243 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002244 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002245 offset = param_offset + params;
2246
2247 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2249 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002250 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002251 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 name_len_target++; /* trailing null */
2253 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002254 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 name_len_target = strnlen(fromName, PATH_MAX);
2256 name_len_target++; /* trailing null */
2257 strncpy(data_offset, fromName, name_len_target);
2258 }
2259
2260 pSMB->MaxParameterCount = cpu_to_le16(2);
2261 /* BB find exact max on data count below from sess*/
2262 pSMB->MaxDataCount = cpu_to_le16(1000);
2263 pSMB->SetupCount = 1;
2264 pSMB->Reserved3 = 0;
2265 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2266 byte_count = 3 /* pad */ + params + name_len_target;
2267 pSMB->ParameterCount = cpu_to_le16(params);
2268 pSMB->TotalParameterCount = pSMB->ParameterCount;
2269 pSMB->DataCount = cpu_to_le16(name_len_target);
2270 pSMB->TotalDataCount = pSMB->DataCount;
2271 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2272 pSMB->DataOffset = cpu_to_le16(offset);
2273 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2274 pSMB->Reserved4 = 0;
2275 pSMB->hdr.smb_buf_length += byte_count;
2276 pSMB->ByteCount = cpu_to_le16(byte_count);
2277 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2278 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002279 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002280 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282
2283 cifs_buf_release(pSMB);
2284 if (rc == -EAGAIN)
2285 goto createHardLinkRetry;
2286
2287 return rc;
2288}
2289
2290int
2291CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2292 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002293 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294{
2295 int rc = 0;
2296 NT_RENAME_REQ *pSMB = NULL;
2297 RENAME_RSP *pSMBr = NULL;
2298 int bytes_returned;
2299 int name_len, name_len2;
2300 __u16 count;
2301
2302 cFYI(1, ("In CIFSCreateHardLink"));
2303winCreateHardLinkRetry:
2304
2305 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2306 (void **) &pSMBr);
2307 if (rc)
2308 return rc;
2309
2310 pSMB->SearchAttributes =
2311 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2312 ATTR_DIRECTORY);
2313 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2314 pSMB->ClusterCount = 0;
2315
2316 pSMB->BufferFormat = 0x04;
2317
2318 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2319 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002320 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002321 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 name_len++; /* trailing null */
2323 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002324
2325 /* protocol specifies ASCII buffer format (0x04) for unicode */
2326 pSMB->OldFileName[name_len] = 0x04;
2327 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002329 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002330 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2332 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002333 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 name_len = strnlen(fromName, PATH_MAX);
2335 name_len++; /* trailing null */
2336 strncpy(pSMB->OldFileName, fromName, name_len);
2337 name_len2 = strnlen(toName, PATH_MAX);
2338 name_len2++; /* trailing null */
2339 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2340 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2341 name_len2++; /* trailing null */
2342 name_len2++; /* signature byte */
2343 }
2344
2345 count = 1 /* string type byte */ + name_len + name_len2;
2346 pSMB->hdr.smb_buf_length += count;
2347 pSMB->ByteCount = cpu_to_le16(count);
2348
2349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002351 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002352 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 cifs_buf_release(pSMB);
2356 if (rc == -EAGAIN)
2357 goto winCreateHardLinkRetry;
2358
2359 return rc;
2360}
2361
2362int
2363CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002364 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 const struct nls_table *nls_codepage)
2366{
2367/* SMB_QUERY_FILE_UNIX_LINK */
2368 TRANSACTION2_QPI_REQ *pSMB = NULL;
2369 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2370 int rc = 0;
2371 int bytes_returned;
2372 int name_len;
2373 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002374 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
2376 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2377
2378querySymLinkRetry:
2379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2380 (void **) &pSMBr);
2381 if (rc)
2382 return rc;
2383
2384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2385 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002386 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2387 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388 name_len++; /* trailing null */
2389 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002390 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 name_len = strnlen(searchName, PATH_MAX);
2392 name_len++; /* trailing null */
2393 strncpy(pSMB->FileName, searchName, name_len);
2394 }
2395
2396 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2397 pSMB->TotalDataCount = 0;
2398 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002399 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400 pSMB->MaxSetupCount = 0;
2401 pSMB->Reserved = 0;
2402 pSMB->Flags = 0;
2403 pSMB->Timeout = 0;
2404 pSMB->Reserved2 = 0;
2405 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002406 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 pSMB->DataCount = 0;
2408 pSMB->DataOffset = 0;
2409 pSMB->SetupCount = 1;
2410 pSMB->Reserved3 = 0;
2411 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2412 byte_count = params + 1 /* pad */ ;
2413 pSMB->TotalParameterCount = cpu_to_le16(params);
2414 pSMB->ParameterCount = pSMB->TotalParameterCount;
2415 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2416 pSMB->Reserved4 = 0;
2417 pSMB->hdr.smb_buf_length += byte_count;
2418 pSMB->ByteCount = cpu_to_le16(byte_count);
2419
2420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2422 if (rc) {
2423 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2424 } else {
2425 /* decode response */
2426
2427 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002429 if (rc || (pSMBr->ByteCount < 2))
2430 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002432 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002433 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
Jeff Layton460b9692009-04-30 07:17:56 -04002435 data_start = ((char *) &pSMBr->hdr.Protocol) +
2436 le16_to_cpu(pSMBr->t2.DataOffset);
2437
Steve French0e0d2cf2009-05-01 05:27:32 +00002438 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2439 is_unicode = true;
2440 else
2441 is_unicode = false;
2442
Steve French737b7582005-04-28 22:41:06 -07002443 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002444 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002445 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002446 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002447 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
2449 }
2450 cifs_buf_release(pSMB);
2451 if (rc == -EAGAIN)
2452 goto querySymLinkRetry;
2453 return rc;
2454}
2455
Parag Warudkarc9489772007-10-23 18:09:48 +00002456#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002457/* Initialize NT TRANSACT SMB into small smb request buffer.
2458 This assumes that all NT TRANSACTS that we init here have
2459 total parm and data under about 400 bytes (to fit in small cifs
2460 buffer size), which is the case so far, it easily fits. NB:
2461 Setup words themselves and ByteCount
2462 MaxSetupCount (size of returned setup area) and
2463 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002464static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002465smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002466 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002467 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002468{
2469 int rc;
2470 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002471 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002472
2473 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2474 (void **)&pSMB);
2475 if (rc)
2476 return rc;
2477 *ret_buf = (void *)pSMB;
2478 pSMB->Reserved = 0;
2479 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2480 pSMB->TotalDataCount = 0;
2481 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2482 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2483 pSMB->ParameterCount = pSMB->TotalParameterCount;
2484 pSMB->DataCount = pSMB->TotalDataCount;
2485 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2486 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2487 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2488 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2489 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2490 pSMB->SubCommand = cpu_to_le16(sub_command);
2491 return 0;
2492}
2493
2494static int
Steve French50c2f752007-07-13 00:33:32 +00002495validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002496 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002497{
Steve French50c2f752007-07-13 00:33:32 +00002498 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002499 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002500 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002501
Steve French630f3f0c2007-10-25 21:17:17 +00002502 *pdatalen = 0;
2503 *pparmlen = 0;
2504
Steve French790fe572007-07-07 19:25:05 +00002505 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002506 return -EINVAL;
2507
2508 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2509
2510 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002511 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002512 (char *)&pSMBr->ByteCount;
2513
Steve French0a4b92c2006-01-12 15:44:21 -08002514 data_offset = le32_to_cpu(pSMBr->DataOffset);
2515 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002516 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002517 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2518
2519 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2520 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2521
2522 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002523 if (*ppparm > end_of_smb) {
2524 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002525 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002526 } else if (parm_count + *ppparm > end_of_smb) {
2527 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002528 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002529 } else if (*ppdata > end_of_smb) {
2530 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002531 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002532 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002533 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002534 *ppdata, data_count, (data_count + *ppdata),
2535 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002536 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002537 } else if (parm_count + data_count > pSMBr->ByteCount) {
2538 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002539 return -EINVAL;
2540 }
Steve French630f3f0c2007-10-25 21:17:17 +00002541 *pdatalen = data_count;
2542 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002543 return 0;
2544}
2545
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546int
2547CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2548 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002549 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 const struct nls_table *nls_codepage)
2551{
2552 int rc = 0;
2553 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002554 struct smb_com_transaction_ioctl_req *pSMB;
2555 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
2557 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2558 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2559 (void **) &pSMBr);
2560 if (rc)
2561 return rc;
2562
2563 pSMB->TotalParameterCount = 0 ;
2564 pSMB->TotalDataCount = 0;
2565 pSMB->MaxParameterCount = cpu_to_le32(2);
2566 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002567 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2568 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 pSMB->MaxSetupCount = 4;
2570 pSMB->Reserved = 0;
2571 pSMB->ParameterOffset = 0;
2572 pSMB->DataCount = 0;
2573 pSMB->DataOffset = 0;
2574 pSMB->SetupCount = 4;
2575 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2576 pSMB->ParameterCount = pSMB->TotalParameterCount;
2577 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2578 pSMB->IsFsctl = 1; /* FSCTL */
2579 pSMB->IsRootFlag = 0;
2580 pSMB->Fid = fid; /* file handle always le */
2581 pSMB->ByteCount = 0;
2582
2583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2585 if (rc) {
2586 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2587 } else { /* decode response */
2588 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2589 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002590 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 /* BB also check enough total bytes returned */
2592 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002593 goto qreparse_out;
2594 }
2595 if (data_count && (data_count < 2048)) {
2596 char *end_of_smb = 2 /* sizeof byte count */ +
2597 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Steve Frenchafe48c32009-05-02 05:25:46 +00002599 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002600 (struct reparse_data *)
2601 ((char *)&pSMBr->hdr.Protocol
2602 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002603 if ((char *)reparse_buf >= end_of_smb) {
2604 rc = -EIO;
2605 goto qreparse_out;
2606 }
2607 if ((reparse_buf->LinkNamesBuf +
2608 reparse_buf->TargetNameOffset +
2609 reparse_buf->TargetNameLen) > end_of_smb) {
2610 cFYI(1, ("reparse buf beyond SMB"));
2611 rc = -EIO;
2612 goto qreparse_out;
2613 }
Steve French50c2f752007-07-13 00:33:32 +00002614
Steve Frenchafe48c32009-05-02 05:25:46 +00002615 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2616 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002617 (reparse_buf->LinkNamesBuf +
2618 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002619 buflen,
2620 reparse_buf->TargetNameLen,
2621 nls_codepage, 0);
2622 } else { /* ASCII names */
2623 strncpy(symlinkinfo,
2624 reparse_buf->LinkNamesBuf +
2625 reparse_buf->TargetNameOffset,
2626 min_t(const int, buflen,
2627 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002629 } else {
2630 rc = -EIO;
2631 cFYI(1, ("Invalid return data count on "
2632 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002634 symlinkinfo[buflen] = 0; /* just in case so the caller
2635 does not go off the end of the buffer */
2636 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 }
Steve French989c7e52009-05-02 05:32:20 +00002638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002640 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
2642 /* Note: On -EAGAIN error only caller can retry on handle based calls
2643 since file handle passed in no longer valid */
2644
2645 return rc;
2646}
Steve Frenchafe48c32009-05-02 05:25:46 +00002647#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648
2649#ifdef CONFIG_CIFS_POSIX
2650
2651/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002652static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2653 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654{
2655 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002656 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2657 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2658 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2660
2661 return;
2662}
2663
2664/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002665static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2666 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667{
2668 int size = 0;
2669 int i;
2670 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002671 struct cifs_posix_ace *pACE;
2672 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2673 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
2675 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2676 return -EOPNOTSUPP;
2677
Steve French790fe572007-07-07 19:25:05 +00002678 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 count = le16_to_cpu(cifs_acl->access_entry_count);
2680 pACE = &cifs_acl->ace_array[0];
2681 size = sizeof(struct cifs_posix_acl);
2682 size += sizeof(struct cifs_posix_ace) * count;
2683 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002684 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002685 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2686 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 return -EINVAL;
2688 }
Steve French790fe572007-07-07 19:25:05 +00002689 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 count = le16_to_cpu(cifs_acl->access_entry_count);
2691 size = sizeof(struct cifs_posix_acl);
2692 size += sizeof(struct cifs_posix_ace) * count;
2693/* skip past access ACEs to get to default ACEs */
2694 pACE = &cifs_acl->ace_array[count];
2695 count = le16_to_cpu(cifs_acl->default_entry_count);
2696 size += sizeof(struct cifs_posix_ace) * count;
2697 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002698 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 return -EINVAL;
2700 } else {
2701 /* illegal type */
2702 return -EINVAL;
2703 }
2704
2705 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002706 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002707 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002708 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 return -ERANGE;
2710 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002711 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002712 for (i = 0; i < count ; i++) {
2713 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2714 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 }
2716 }
2717 return size;
2718}
2719
Steve French50c2f752007-07-13 00:33:32 +00002720static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2721 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722{
2723 __u16 rc = 0; /* 0 = ACL converted ok */
2724
Steve Frenchff7feac2005-11-15 16:45:16 -08002725 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2726 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002728 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 /* Probably no need to le convert -1 on any arch but can not hurt */
2730 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002731 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002732 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002733 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 return rc;
2735}
2736
2737/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002738static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2739 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740{
2741 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002742 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2743 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 int count;
2745 int i;
2746
Steve French790fe572007-07-07 19:25:05 +00002747 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 return 0;
2749
2750 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002751 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002752 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002753 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002754 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002755 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002756 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return 0;
2758 }
2759 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002760 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002761 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002762 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002763 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 else {
Steve French50c2f752007-07-13 00:33:32 +00002765 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 return 0;
2767 }
Steve French50c2f752007-07-13 00:33:32 +00002768 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2770 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002771 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 /* ACE not converted */
2773 break;
2774 }
2775 }
Steve French790fe572007-07-07 19:25:05 +00002776 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2778 rc += sizeof(struct cifs_posix_acl);
2779 /* BB add check to make sure ACL does not overflow SMB */
2780 }
2781 return rc;
2782}
2783
2784int
2785CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002786 const unsigned char *searchName,
2787 char *acl_inf, const int buflen, const int acl_type,
2788 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789{
2790/* SMB_QUERY_POSIX_ACL */
2791 TRANSACTION2_QPI_REQ *pSMB = NULL;
2792 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2793 int rc = 0;
2794 int bytes_returned;
2795 int name_len;
2796 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002797
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2799
2800queryAclRetry:
2801 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2802 (void **) &pSMBr);
2803 if (rc)
2804 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002805
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2807 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002808 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002809 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 name_len++; /* trailing null */
2811 name_len *= 2;
2812 pSMB->FileName[name_len] = 0;
2813 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002814 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 name_len = strnlen(searchName, PATH_MAX);
2816 name_len++; /* trailing null */
2817 strncpy(pSMB->FileName, searchName, name_len);
2818 }
2819
2820 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2821 pSMB->TotalDataCount = 0;
2822 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002823 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 pSMB->MaxDataCount = cpu_to_le16(4000);
2825 pSMB->MaxSetupCount = 0;
2826 pSMB->Reserved = 0;
2827 pSMB->Flags = 0;
2828 pSMB->Timeout = 0;
2829 pSMB->Reserved2 = 0;
2830 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002831 offsetof(struct smb_com_transaction2_qpi_req,
2832 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 pSMB->DataCount = 0;
2834 pSMB->DataOffset = 0;
2835 pSMB->SetupCount = 1;
2836 pSMB->Reserved3 = 0;
2837 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2838 byte_count = params + 1 /* pad */ ;
2839 pSMB->TotalParameterCount = cpu_to_le16(params);
2840 pSMB->ParameterCount = pSMB->TotalParameterCount;
2841 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2842 pSMB->Reserved4 = 0;
2843 pSMB->hdr.smb_buf_length += byte_count;
2844 pSMB->ByteCount = cpu_to_le16(byte_count);
2845
2846 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2847 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002848 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 if (rc) {
2850 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2851 } else {
2852 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002853
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2855 if (rc || (pSMBr->ByteCount < 2))
2856 /* BB also check enough total bytes returned */
2857 rc = -EIO; /* bad smb */
2858 else {
2859 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2860 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2861 rc = cifs_copy_posix_acl(acl_inf,
2862 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002863 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 }
2865 }
2866 cifs_buf_release(pSMB);
2867 if (rc == -EAGAIN)
2868 goto queryAclRetry;
2869 return rc;
2870}
2871
2872int
2873CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002874 const unsigned char *fileName,
2875 const char *local_acl, const int buflen,
2876 const int acl_type,
2877 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878{
2879 struct smb_com_transaction2_spi_req *pSMB = NULL;
2880 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2881 char *parm_data;
2882 int name_len;
2883 int rc = 0;
2884 int bytes_returned = 0;
2885 __u16 params, byte_count, data_count, param_offset, offset;
2886
2887 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2888setAclRetry:
2889 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002890 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 if (rc)
2892 return rc;
2893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2894 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002895 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002896 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 name_len++; /* trailing null */
2898 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002899 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 name_len = strnlen(fileName, PATH_MAX);
2901 name_len++; /* trailing null */
2902 strncpy(pSMB->FileName, fileName, name_len);
2903 }
2904 params = 6 + name_len;
2905 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002906 /* BB find max SMB size from sess */
2907 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 pSMB->MaxSetupCount = 0;
2909 pSMB->Reserved = 0;
2910 pSMB->Flags = 0;
2911 pSMB->Timeout = 0;
2912 pSMB->Reserved2 = 0;
2913 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002914 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 offset = param_offset + params;
2916 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2917 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2918
2919 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002920 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921
Steve French790fe572007-07-07 19:25:05 +00002922 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 rc = -EOPNOTSUPP;
2924 goto setACLerrorExit;
2925 }
2926 pSMB->DataOffset = cpu_to_le16(offset);
2927 pSMB->SetupCount = 1;
2928 pSMB->Reserved3 = 0;
2929 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2930 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2931 byte_count = 3 /* pad */ + params + data_count;
2932 pSMB->DataCount = cpu_to_le16(data_count);
2933 pSMB->TotalDataCount = pSMB->DataCount;
2934 pSMB->ParameterCount = cpu_to_le16(params);
2935 pSMB->TotalParameterCount = pSMB->ParameterCount;
2936 pSMB->Reserved4 = 0;
2937 pSMB->hdr.smb_buf_length += byte_count;
2938 pSMB->ByteCount = cpu_to_le16(byte_count);
2939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002941 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943
2944setACLerrorExit:
2945 cifs_buf_release(pSMB);
2946 if (rc == -EAGAIN)
2947 goto setAclRetry;
2948 return rc;
2949}
2950
Steve Frenchf654bac2005-04-28 22:41:04 -07002951/* BB fix tabs in this function FIXME BB */
2952int
2953CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002954 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002955{
Steve French50c2f752007-07-13 00:33:32 +00002956 int rc = 0;
2957 struct smb_t2_qfi_req *pSMB = NULL;
2958 struct smb_t2_qfi_rsp *pSMBr = NULL;
2959 int bytes_returned;
2960 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002961
Steve French790fe572007-07-07 19:25:05 +00002962 cFYI(1, ("In GetExtAttr"));
2963 if (tcon == NULL)
2964 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002965
2966GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002967 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2968 (void **) &pSMBr);
2969 if (rc)
2970 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002971
Steve Frenchad7a2922008-02-07 23:25:02 +00002972 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002973 pSMB->t2.TotalDataCount = 0;
2974 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2975 /* BB find exact max data count below from sess structure BB */
2976 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2977 pSMB->t2.MaxSetupCount = 0;
2978 pSMB->t2.Reserved = 0;
2979 pSMB->t2.Flags = 0;
2980 pSMB->t2.Timeout = 0;
2981 pSMB->t2.Reserved2 = 0;
2982 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2983 Fid) - 4);
2984 pSMB->t2.DataCount = 0;
2985 pSMB->t2.DataOffset = 0;
2986 pSMB->t2.SetupCount = 1;
2987 pSMB->t2.Reserved3 = 0;
2988 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2989 byte_count = params + 1 /* pad */ ;
2990 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2991 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2992 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2993 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002994 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002995 pSMB->hdr.smb_buf_length += byte_count;
2996 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002997
Steve French790fe572007-07-07 19:25:05 +00002998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3000 if (rc) {
3001 cFYI(1, ("error %d in GetExtAttr", rc));
3002 } else {
3003 /* decode response */
3004 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3005 if (rc || (pSMBr->ByteCount < 2))
3006 /* BB also check enough total bytes returned */
3007 /* If rc should we check for EOPNOSUPP and
3008 disable the srvino flag? or in caller? */
3009 rc = -EIO; /* bad smb */
3010 else {
3011 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3012 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3013 struct file_chattr_info *pfinfo;
3014 /* BB Do we need a cast or hash here ? */
3015 if (count != 16) {
3016 cFYI(1, ("Illegal size ret in GetExtAttr"));
3017 rc = -EIO;
3018 goto GetExtAttrOut;
3019 }
3020 pfinfo = (struct file_chattr_info *)
3021 (data_offset + (char *) &pSMBr->hdr.Protocol);
3022 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003023 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003024 }
3025 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003026GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003027 cifs_buf_release(pSMB);
3028 if (rc == -EAGAIN)
3029 goto GetExtAttrRetry;
3030 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003031}
3032
Steve Frenchf654bac2005-04-28 22:41:04 -07003033#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034
Steve French297647c2007-10-12 04:11:59 +00003035#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003036/* Get Security Descriptor (by handle) from remote server for a file or dir */
3037int
3038CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003039 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003040{
3041 int rc = 0;
3042 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003043 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003044 struct kvec iov[1];
3045
3046 cFYI(1, ("GetCifsACL"));
3047
Steve French630f3f0c2007-10-25 21:17:17 +00003048 *pbuflen = 0;
3049 *acl_inf = NULL;
3050
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003051 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003052 8 /* parm len */, tcon, (void **) &pSMB);
3053 if (rc)
3054 return rc;
3055
3056 pSMB->MaxParameterCount = cpu_to_le32(4);
3057 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3058 pSMB->MaxSetupCount = 0;
3059 pSMB->Fid = fid; /* file handle always le */
3060 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3061 CIFS_ACL_DACL);
3062 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3063 pSMB->hdr.smb_buf_length += 11;
3064 iov[0].iov_base = (char *)pSMB;
3065 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3066
Steve Frencha761ac52007-10-18 21:45:27 +00003067 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003068 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003069 cifs_stats_inc(&tcon->num_acl_get);
3070 if (rc) {
3071 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3072 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003073 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003074 __u32 parm_len;
3075 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003076 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003077 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003078
3079/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003080 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003081 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003082 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003083 goto qsec_out;
3084 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3085
Steve French630f3f0c2007-10-25 21:17:17 +00003086 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003087
3088 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3089 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003090 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003091 goto qsec_out;
3092 }
3093
3094/* BB check that data area is minimum length and as big as acl_len */
3095
Steve Frenchaf6f4612007-10-16 18:40:37 +00003096 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003097 if (acl_len != *pbuflen) {
3098 cERROR(1, ("acl length %d does not match %d",
3099 acl_len, *pbuflen));
3100 if (*pbuflen > acl_len)
3101 *pbuflen = acl_len;
3102 }
Steve French0a4b92c2006-01-12 15:44:21 -08003103
Steve French630f3f0c2007-10-25 21:17:17 +00003104 /* check if buffer is big enough for the acl
3105 header followed by the smallest SID */
3106 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3107 (*pbuflen >= 64 * 1024)) {
3108 cERROR(1, ("bad acl length %d", *pbuflen));
3109 rc = -EINVAL;
3110 *pbuflen = 0;
3111 } else {
3112 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3113 if (*acl_inf == NULL) {
3114 *pbuflen = 0;
3115 rc = -ENOMEM;
3116 }
3117 memcpy(*acl_inf, pdata, *pbuflen);
3118 }
Steve French0a4b92c2006-01-12 15:44:21 -08003119 }
3120qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003121 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003122 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003123 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003124 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003125/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003126 return rc;
3127}
Steve French97837582007-12-31 07:47:21 +00003128
3129int
3130CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3131 struct cifs_ntsd *pntsd, __u32 acllen)
3132{
3133 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3134 int rc = 0;
3135 int bytes_returned = 0;
3136 SET_SEC_DESC_REQ *pSMB = NULL;
3137 NTRANSACT_RSP *pSMBr = NULL;
3138
3139setCifsAclRetry:
3140 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3141 (void **) &pSMBr);
3142 if (rc)
3143 return (rc);
3144
3145 pSMB->MaxSetupCount = 0;
3146 pSMB->Reserved = 0;
3147
3148 param_count = 8;
3149 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3150 data_count = acllen;
3151 data_offset = param_offset + param_count;
3152 byte_count = 3 /* pad */ + param_count;
3153
3154 pSMB->DataCount = cpu_to_le32(data_count);
3155 pSMB->TotalDataCount = pSMB->DataCount;
3156 pSMB->MaxParameterCount = cpu_to_le32(4);
3157 pSMB->MaxDataCount = cpu_to_le32(16384);
3158 pSMB->ParameterCount = cpu_to_le32(param_count);
3159 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3160 pSMB->TotalParameterCount = pSMB->ParameterCount;
3161 pSMB->DataOffset = cpu_to_le32(data_offset);
3162 pSMB->SetupCount = 0;
3163 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3164 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3165
3166 pSMB->Fid = fid; /* file handle always le */
3167 pSMB->Reserved2 = 0;
3168 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3169
3170 if (pntsd && acllen) {
3171 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3172 (char *) pntsd,
3173 acllen);
3174 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3175
3176 } else
3177 pSMB->hdr.smb_buf_length += byte_count;
3178
3179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3181
3182 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3183 if (rc)
3184 cFYI(1, ("Set CIFS ACL returned %d", rc));
3185 cifs_buf_release(pSMB);
3186
3187 if (rc == -EAGAIN)
3188 goto setCifsAclRetry;
3189
3190 return (rc);
3191}
3192
Steve French297647c2007-10-12 04:11:59 +00003193#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003194
Steve French6b8edfe2005-08-23 20:26:03 -07003195/* Legacy Query Path Information call for lookup to old servers such
3196 as Win9x/WinME */
3197int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003198 const unsigned char *searchName,
3199 FILE_ALL_INFO *pFinfo,
3200 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003201{
Steve Frenchad7a2922008-02-07 23:25:02 +00003202 QUERY_INFORMATION_REQ *pSMB;
3203 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003204 int rc = 0;
3205 int bytes_returned;
3206 int name_len;
3207
Steve French50c2f752007-07-13 00:33:32 +00003208 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003209QInfRetry:
3210 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003211 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003212 if (rc)
3213 return rc;
3214
3215 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3216 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003217 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3218 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003219 name_len++; /* trailing null */
3220 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003221 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003222 name_len = strnlen(searchName, PATH_MAX);
3223 name_len++; /* trailing null */
3224 strncpy(pSMB->FileName, searchName, name_len);
3225 }
3226 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003227 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003228 pSMB->hdr.smb_buf_length += (__u16) name_len;
3229 pSMB->ByteCount = cpu_to_le16(name_len);
3230
3231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003233 if (rc) {
3234 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003235 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003236 struct timespec ts;
3237 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003238
3239 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003240 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003241 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003242 ts.tv_nsec = 0;
3243 ts.tv_sec = time;
3244 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003245 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003246 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3247 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003248 pFinfo->AllocationSize =
3249 cpu_to_le64(le32_to_cpu(pSMBr->size));
3250 pFinfo->EndOfFile = pFinfo->AllocationSize;
3251 pFinfo->Attributes =
3252 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003253 } else
3254 rc = -EIO; /* bad buffer passed in */
3255
3256 cifs_buf_release(pSMB);
3257
3258 if (rc == -EAGAIN)
3259 goto QInfRetry;
3260
3261 return rc;
3262}
3263
Jeff Laytonbcd53572010-02-12 07:44:16 -05003264int
3265CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3266 u16 netfid, FILE_ALL_INFO *pFindData)
3267{
3268 struct smb_t2_qfi_req *pSMB = NULL;
3269 struct smb_t2_qfi_rsp *pSMBr = NULL;
3270 int rc = 0;
3271 int bytes_returned;
3272 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003273
Jeff Laytonbcd53572010-02-12 07:44:16 -05003274QFileInfoRetry:
3275 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3276 (void **) &pSMBr);
3277 if (rc)
3278 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003279
Jeff Laytonbcd53572010-02-12 07:44:16 -05003280 params = 2 /* level */ + 2 /* fid */;
3281 pSMB->t2.TotalDataCount = 0;
3282 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3283 /* BB find exact max data count below from sess structure BB */
3284 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3285 pSMB->t2.MaxSetupCount = 0;
3286 pSMB->t2.Reserved = 0;
3287 pSMB->t2.Flags = 0;
3288 pSMB->t2.Timeout = 0;
3289 pSMB->t2.Reserved2 = 0;
3290 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3291 Fid) - 4);
3292 pSMB->t2.DataCount = 0;
3293 pSMB->t2.DataOffset = 0;
3294 pSMB->t2.SetupCount = 1;
3295 pSMB->t2.Reserved3 = 0;
3296 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3297 byte_count = params + 1 /* pad */ ;
3298 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3299 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3300 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3301 pSMB->Pad = 0;
3302 pSMB->Fid = netfid;
3303 pSMB->hdr.smb_buf_length += byte_count;
3304
3305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3307 if (rc) {
3308 cFYI(1, ("Send error in QPathInfo = %d", rc));
3309 } else { /* decode response */
3310 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3311
3312 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3313 rc = -EIO;
3314 else if (pSMBr->ByteCount < 40)
3315 rc = -EIO; /* bad smb */
3316 else if (pFindData) {
3317 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3318 memcpy((char *) pFindData,
3319 (char *) &pSMBr->hdr.Protocol +
3320 data_offset, sizeof(FILE_ALL_INFO));
3321 } else
3322 rc = -ENOMEM;
3323 }
3324 cifs_buf_release(pSMB);
3325 if (rc == -EAGAIN)
3326 goto QFileInfoRetry;
3327
3328 return rc;
3329}
Steve French6b8edfe2005-08-23 20:26:03 -07003330
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331int
3332CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3333 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003334 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003335 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003336 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337{
3338/* level 263 SMB_QUERY_FILE_ALL_INFO */
3339 TRANSACTION2_QPI_REQ *pSMB = NULL;
3340 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3341 int rc = 0;
3342 int bytes_returned;
3343 int name_len;
3344 __u16 params, byte_count;
3345
3346/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3347QPathInfoRetry:
3348 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3349 (void **) &pSMBr);
3350 if (rc)
3351 return rc;
3352
3353 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3354 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003355 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003356 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 name_len++; /* trailing null */
3358 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003359 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360 name_len = strnlen(searchName, PATH_MAX);
3361 name_len++; /* trailing null */
3362 strncpy(pSMB->FileName, searchName, name_len);
3363 }
3364
Steve French50c2f752007-07-13 00:33:32 +00003365 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 pSMB->TotalDataCount = 0;
3367 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003368 /* BB find exact max SMB PDU from sess structure BB */
3369 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 pSMB->MaxSetupCount = 0;
3371 pSMB->Reserved = 0;
3372 pSMB->Flags = 0;
3373 pSMB->Timeout = 0;
3374 pSMB->Reserved2 = 0;
3375 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003376 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003377 pSMB->DataCount = 0;
3378 pSMB->DataOffset = 0;
3379 pSMB->SetupCount = 1;
3380 pSMB->Reserved3 = 0;
3381 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3382 byte_count = params + 1 /* pad */ ;
3383 pSMB->TotalParameterCount = cpu_to_le16(params);
3384 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003385 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003386 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3387 else
3388 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003389 pSMB->Reserved4 = 0;
3390 pSMB->hdr.smb_buf_length += byte_count;
3391 pSMB->ByteCount = cpu_to_le16(byte_count);
3392
3393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3395 if (rc) {
3396 cFYI(1, ("Send error in QPathInfo = %d", rc));
3397 } else { /* decode response */
3398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3399
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003400 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3401 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003402 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003403 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003404 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003405 rc = -EIO; /* 24 or 26 expected but we do not read
3406 last field */
3407 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003408 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003410
3411 /* On legacy responses we do not read the last field,
3412 EAsize, fortunately since it varies by subdialect and
3413 also note it differs on Set vs. Get, ie two bytes or 4
3414 bytes depending but we don't care here */
3415 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003416 size = sizeof(FILE_INFO_STANDARD);
3417 else
3418 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 memcpy((char *) pFindData,
3420 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003421 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 } else
3423 rc = -ENOMEM;
3424 }
3425 cifs_buf_release(pSMB);
3426 if (rc == -EAGAIN)
3427 goto QPathInfoRetry;
3428
3429 return rc;
3430}
3431
3432int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003433CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3434 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3435{
3436 struct smb_t2_qfi_req *pSMB = NULL;
3437 struct smb_t2_qfi_rsp *pSMBr = NULL;
3438 int rc = 0;
3439 int bytes_returned;
3440 __u16 params, byte_count;
3441
3442UnixQFileInfoRetry:
3443 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3444 (void **) &pSMBr);
3445 if (rc)
3446 return rc;
3447
3448 params = 2 /* level */ + 2 /* fid */;
3449 pSMB->t2.TotalDataCount = 0;
3450 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3451 /* BB find exact max data count below from sess structure BB */
3452 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3453 pSMB->t2.MaxSetupCount = 0;
3454 pSMB->t2.Reserved = 0;
3455 pSMB->t2.Flags = 0;
3456 pSMB->t2.Timeout = 0;
3457 pSMB->t2.Reserved2 = 0;
3458 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3459 Fid) - 4);
3460 pSMB->t2.DataCount = 0;
3461 pSMB->t2.DataOffset = 0;
3462 pSMB->t2.SetupCount = 1;
3463 pSMB->t2.Reserved3 = 0;
3464 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3465 byte_count = params + 1 /* pad */ ;
3466 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3467 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3468 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3469 pSMB->Pad = 0;
3470 pSMB->Fid = netfid;
3471 pSMB->hdr.smb_buf_length += byte_count;
3472
3473 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3474 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3475 if (rc) {
3476 cFYI(1, ("Send error in QPathInfo = %d", rc));
3477 } else { /* decode response */
3478 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3479
3480 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3481 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3482 "Unix Extensions can be disabled on mount "
3483 "by specifying the nosfu mount option."));
3484 rc = -EIO; /* bad smb */
3485 } else {
3486 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3487 memcpy((char *) pFindData,
3488 (char *) &pSMBr->hdr.Protocol +
3489 data_offset,
3490 sizeof(FILE_UNIX_BASIC_INFO));
3491 }
3492 }
3493
3494 cifs_buf_release(pSMB);
3495 if (rc == -EAGAIN)
3496 goto UnixQFileInfoRetry;
3497
3498 return rc;
3499}
3500
3501int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3503 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003504 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003505 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506{
3507/* SMB_QUERY_FILE_UNIX_BASIC */
3508 TRANSACTION2_QPI_REQ *pSMB = NULL;
3509 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3510 int rc = 0;
3511 int bytes_returned = 0;
3512 int name_len;
3513 __u16 params, byte_count;
3514
3515 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3516UnixQPathInfoRetry:
3517 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3518 (void **) &pSMBr);
3519 if (rc)
3520 return rc;
3521
3522 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3523 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003524 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003525 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 name_len++; /* trailing null */
3527 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003528 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 name_len = strnlen(searchName, PATH_MAX);
3530 name_len++; /* trailing null */
3531 strncpy(pSMB->FileName, searchName, name_len);
3532 }
3533
Steve French50c2f752007-07-13 00:33:32 +00003534 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 pSMB->TotalDataCount = 0;
3536 pSMB->MaxParameterCount = cpu_to_le16(2);
3537 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003538 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 pSMB->MaxSetupCount = 0;
3540 pSMB->Reserved = 0;
3541 pSMB->Flags = 0;
3542 pSMB->Timeout = 0;
3543 pSMB->Reserved2 = 0;
3544 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003545 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 pSMB->DataCount = 0;
3547 pSMB->DataOffset = 0;
3548 pSMB->SetupCount = 1;
3549 pSMB->Reserved3 = 0;
3550 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3551 byte_count = params + 1 /* pad */ ;
3552 pSMB->TotalParameterCount = cpu_to_le16(params);
3553 pSMB->ParameterCount = pSMB->TotalParameterCount;
3554 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3555 pSMB->Reserved4 = 0;
3556 pSMB->hdr.smb_buf_length += byte_count;
3557 pSMB->ByteCount = cpu_to_le16(byte_count);
3558
3559 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3560 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3561 if (rc) {
3562 cFYI(1, ("Send error in QPathInfo = %d", rc));
3563 } else { /* decode response */
3564 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3565
3566 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003567 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3568 "Unix Extensions can be disabled on mount "
3569 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570 rc = -EIO; /* bad smb */
3571 } else {
3572 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3573 memcpy((char *) pFindData,
3574 (char *) &pSMBr->hdr.Protocol +
3575 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003576 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 }
3578 }
3579 cifs_buf_release(pSMB);
3580 if (rc == -EAGAIN)
3581 goto UnixQPathInfoRetry;
3582
3583 return rc;
3584}
3585
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586/* xid, tcon, searchName and codepage are input parms, rest are returned */
3587int
3588CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003589 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003591 __u16 *pnetfid,
3592 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593{
3594/* level 257 SMB_ */
3595 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3596 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003597 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 int rc = 0;
3599 int bytes_returned = 0;
3600 int name_len;
3601 __u16 params, byte_count;
3602
Steve French50c2f752007-07-13 00:33:32 +00003603 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604
3605findFirstRetry:
3606 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3607 (void **) &pSMBr);
3608 if (rc)
3609 return rc;
3610
3611 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3612 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003613 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003614 PATH_MAX, nls_codepage, remap);
3615 /* We can not add the asterik earlier in case
3616 it got remapped to 0xF03A as if it were part of the
3617 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003619 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003620 pSMB->FileName[name_len+1] = 0;
3621 pSMB->FileName[name_len+2] = '*';
3622 pSMB->FileName[name_len+3] = 0;
3623 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3625 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003626 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 } else { /* BB add check for overrun of SMB buf BB */
3628 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003630 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 free buffer exit; BB */
3632 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003633 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003634 pSMB->FileName[name_len+1] = '*';
3635 pSMB->FileName[name_len+2] = 0;
3636 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 }
3638
3639 params = 12 + name_len /* includes null */ ;
3640 pSMB->TotalDataCount = 0; /* no EAs */
3641 pSMB->MaxParameterCount = cpu_to_le16(10);
3642 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3643 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3644 pSMB->MaxSetupCount = 0;
3645 pSMB->Reserved = 0;
3646 pSMB->Flags = 0;
3647 pSMB->Timeout = 0;
3648 pSMB->Reserved2 = 0;
3649 byte_count = params + 1 /* pad */ ;
3650 pSMB->TotalParameterCount = cpu_to_le16(params);
3651 pSMB->ParameterCount = pSMB->TotalParameterCount;
3652 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003653 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3654 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 pSMB->DataCount = 0;
3656 pSMB->DataOffset = 0;
3657 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3658 pSMB->Reserved3 = 0;
3659 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3660 pSMB->SearchAttributes =
3661 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3662 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003663 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3664 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665 CIFS_SEARCH_RETURN_RESUME);
3666 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3667
3668 /* BB what should we set StorageType to? Does it matter? BB */
3669 pSMB->SearchStorageType = 0;
3670 pSMB->hdr.smb_buf_length += byte_count;
3671 pSMB->ByteCount = cpu_to_le16(byte_count);
3672
3673 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3674 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003675 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676
Steve French88274812006-03-09 22:21:45 +00003677 if (rc) {/* BB add logic to retry regular search if Unix search
3678 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 /* BB Add code to handle unsupported level rc */
3680 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003681
Steve French88274812006-03-09 22:21:45 +00003682 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683
3684 /* BB eventually could optimize out free and realloc of buf */
3685 /* for this case */
3686 if (rc == -EAGAIN)
3687 goto findFirstRetry;
3688 } else { /* decode response */
3689 /* BB remember to free buffer if error BB */
3690 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003691 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003692 unsigned int lnoff;
3693
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003695 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 else
Steve French4b18f2a2008-04-29 00:06:05 +00003697 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698
3699 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003700 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003701 psrch_inf->srch_entries_start =
3702 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3705 le16_to_cpu(pSMBr->t2.ParameterOffset));
3706
Steve French790fe572007-07-07 19:25:05 +00003707 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003708 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 else
Steve French4b18f2a2008-04-29 00:06:05 +00003710 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711
Steve French50c2f752007-07-13 00:33:32 +00003712 psrch_inf->entries_in_buffer =
3713 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003714 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003716 lnoff = le16_to_cpu(parms->LastNameOffset);
3717 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3718 lnoff) {
3719 cERROR(1, ("ignoring corrupt resume name"));
3720 psrch_inf->last_entry = NULL;
3721 return rc;
3722 }
3723
Steve French0752f152008-10-07 20:03:33 +00003724 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003725 lnoff;
3726
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 *pnetfid = parms->SearchHandle;
3728 } else {
3729 cifs_buf_release(pSMB);
3730 }
3731 }
3732
3733 return rc;
3734}
3735
3736int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003737 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738{
3739 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3740 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003741 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 char *response_data;
3743 int rc = 0;
3744 int bytes_returned, name_len;
3745 __u16 params, byte_count;
3746
3747 cFYI(1, ("In FindNext"));
3748
Steve French4b18f2a2008-04-29 00:06:05 +00003749 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 return -ENOENT;
3751
3752 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3753 (void **) &pSMBr);
3754 if (rc)
3755 return rc;
3756
Steve French50c2f752007-07-13 00:33:32 +00003757 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 byte_count = 0;
3759 pSMB->TotalDataCount = 0; /* no EAs */
3760 pSMB->MaxParameterCount = cpu_to_le16(8);
3761 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003762 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3763 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 pSMB->MaxSetupCount = 0;
3765 pSMB->Reserved = 0;
3766 pSMB->Flags = 0;
3767 pSMB->Timeout = 0;
3768 pSMB->Reserved2 = 0;
3769 pSMB->ParameterOffset = cpu_to_le16(
3770 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3771 pSMB->DataCount = 0;
3772 pSMB->DataOffset = 0;
3773 pSMB->SetupCount = 1;
3774 pSMB->Reserved3 = 0;
3775 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3776 pSMB->SearchHandle = searchHandle; /* always kept as le */
3777 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003778 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3780 pSMB->ResumeKey = psrch_inf->resume_key;
3781 pSMB->SearchFlags =
3782 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3783
3784 name_len = psrch_inf->resume_name_len;
3785 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003786 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3788 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003789 /* 14 byte parm len above enough for 2 byte null terminator */
3790 pSMB->ResumeFileName[name_len] = 0;
3791 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 } else {
3793 rc = -EINVAL;
3794 goto FNext2_err_exit;
3795 }
3796 byte_count = params + 1 /* pad */ ;
3797 pSMB->TotalParameterCount = cpu_to_le16(params);
3798 pSMB->ParameterCount = pSMB->TotalParameterCount;
3799 pSMB->hdr.smb_buf_length += byte_count;
3800 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003801
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3803 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003804 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 if (rc) {
3806 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003807 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003808 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003809 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 } else
3811 cFYI(1, ("FindNext returned = %d", rc));
3812 } else { /* decode response */
3813 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003814
Steve French790fe572007-07-07 19:25:05 +00003815 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003816 unsigned int lnoff;
3817
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818 /* BB fixme add lock for file (srch_info) struct here */
3819 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003820 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 else
Steve French4b18f2a2008-04-29 00:06:05 +00003822 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823 response_data = (char *) &pSMBr->hdr.Protocol +
3824 le16_to_cpu(pSMBr->t2.ParameterOffset);
3825 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3826 response_data = (char *)&pSMBr->hdr.Protocol +
3827 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003828 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003829 cifs_small_buf_release(
3830 psrch_inf->ntwrk_buf_start);
3831 else
3832 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833 psrch_inf->srch_entries_start = response_data;
3834 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003835 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003836 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003837 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 else
Steve French4b18f2a2008-04-29 00:06:05 +00003839 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003840 psrch_inf->entries_in_buffer =
3841 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842 psrch_inf->index_of_last_entry +=
3843 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003844 lnoff = le16_to_cpu(parms->LastNameOffset);
3845 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3846 lnoff) {
3847 cERROR(1, ("ignoring corrupt resume name"));
3848 psrch_inf->last_entry = NULL;
3849 return rc;
3850 } else
3851 psrch_inf->last_entry =
3852 psrch_inf->srch_entries_start + lnoff;
3853
Steve French50c2f752007-07-13 00:33:32 +00003854/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3855 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856
3857 /* BB fixme add unlock here */
3858 }
3859
3860 }
3861
3862 /* BB On error, should we leave previous search buf (and count and
3863 last entry fields) intact or free the previous one? */
3864
3865 /* Note: On -EAGAIN error only caller can retry on handle based calls
3866 since file handle passed in no longer valid */
3867FNext2_err_exit:
3868 if (rc != 0)
3869 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 return rc;
3871}
3872
3873int
Steve French50c2f752007-07-13 00:33:32 +00003874CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3875 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876{
3877 int rc = 0;
3878 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879
3880 cFYI(1, ("In CIFSSMBFindClose"));
3881 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3882
3883 /* no sense returning error if session restarted
3884 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003885 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 return 0;
3887 if (rc)
3888 return rc;
3889
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 pSMB->FileID = searchHandle;
3891 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003892 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003893 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003895
Steve Frencha45443472005-08-24 13:59:35 -07003896 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
3898 /* Since session is dead, search handle closed on server already */
3899 if (rc == -EAGAIN)
3900 rc = 0;
3901
3902 return rc;
3903}
3904
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905int
3906CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003907 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003908 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003909 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910{
3911 int rc = 0;
3912 TRANSACTION2_QPI_REQ *pSMB = NULL;
3913 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3914 int name_len, bytes_returned;
3915 __u16 params, byte_count;
3916
Steve French50c2f752007-07-13 00:33:32 +00003917 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003918 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003919 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920
3921GetInodeNumberRetry:
3922 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003923 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 if (rc)
3925 return rc;
3926
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3928 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003929 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003930 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931 name_len++; /* trailing null */
3932 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003933 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 name_len = strnlen(searchName, PATH_MAX);
3935 name_len++; /* trailing null */
3936 strncpy(pSMB->FileName, searchName, name_len);
3937 }
3938
3939 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3940 pSMB->TotalDataCount = 0;
3941 pSMB->MaxParameterCount = cpu_to_le16(2);
3942 /* BB find exact max data count below from sess structure BB */
3943 pSMB->MaxDataCount = cpu_to_le16(4000);
3944 pSMB->MaxSetupCount = 0;
3945 pSMB->Reserved = 0;
3946 pSMB->Flags = 0;
3947 pSMB->Timeout = 0;
3948 pSMB->Reserved2 = 0;
3949 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003950 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 pSMB->DataCount = 0;
3952 pSMB->DataOffset = 0;
3953 pSMB->SetupCount = 1;
3954 pSMB->Reserved3 = 0;
3955 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3956 byte_count = params + 1 /* pad */ ;
3957 pSMB->TotalParameterCount = cpu_to_le16(params);
3958 pSMB->ParameterCount = pSMB->TotalParameterCount;
3959 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3960 pSMB->Reserved4 = 0;
3961 pSMB->hdr.smb_buf_length += byte_count;
3962 pSMB->ByteCount = cpu_to_le16(byte_count);
3963
3964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3966 if (rc) {
3967 cFYI(1, ("error %d in QueryInternalInfo", rc));
3968 } else {
3969 /* decode response */
3970 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3971 if (rc || (pSMBr->ByteCount < 2))
3972 /* BB also check enough total bytes returned */
3973 /* If rc should we check for EOPNOSUPP and
3974 disable the srvino flag? or in caller? */
3975 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003976 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3978 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003979 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003981 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3983 rc = -EIO;
3984 goto GetInodeNumOut;
3985 }
3986 pfinfo = (struct file_internal_info *)
3987 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003988 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 }
3990 }
3991GetInodeNumOut:
3992 cifs_buf_release(pSMB);
3993 if (rc == -EAGAIN)
3994 goto GetInodeNumberRetry;
3995 return rc;
3996}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997
Igor Mammedovfec45852008-05-16 13:06:30 +04003998/* parses DFS refferal V3 structure
3999 * caller is responsible for freeing target_nodes
4000 * returns:
4001 * on success - 0
4002 * on failure - errno
4003 */
4004static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004005parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004006 unsigned int *num_of_nodes,
4007 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004008 const struct nls_table *nls_codepage, int remap,
4009 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004010{
4011 int i, rc = 0;
4012 char *data_end;
4013 bool is_unicode;
4014 struct dfs_referral_level_3 *ref;
4015
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004016 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4017 is_unicode = true;
4018 else
4019 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004020 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4021
4022 if (*num_of_nodes < 1) {
4023 cERROR(1, ("num_referrals: must be at least > 0,"
4024 "but we get num_referrals = %d\n", *num_of_nodes));
4025 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004026 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004027 }
4028
4029 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004030 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04004031 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01004032 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04004033 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004034 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004035 }
4036
4037 /* get the upper boundary of the resp buffer */
4038 data_end = (char *)(&(pSMBr->PathConsumed)) +
4039 le16_to_cpu(pSMBr->t2.DataCount);
4040
4041 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
4042 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00004043 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04004044
4045 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4046 *num_of_nodes, GFP_KERNEL);
4047 if (*target_nodes == NULL) {
4048 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
4049 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004050 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004051 }
4052
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004053 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004054 for (i = 0; i < *num_of_nodes; i++) {
4055 char *temp;
4056 int max_len;
4057 struct dfs_info3_param *node = (*target_nodes)+i;
4058
Steve French0e0d2cf2009-05-01 05:27:32 +00004059 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004060 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004061 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4062 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004063 if (tmp == NULL) {
4064 rc = -ENOMEM;
4065 goto parse_DFS_referrals_exit;
4066 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004067 cifsConvertToUCS((__le16 *) tmp, searchName,
4068 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004069 node->path_consumed = cifs_ucs2_bytes(tmp,
4070 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004071 nls_codepage);
4072 kfree(tmp);
4073 } else
4074 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4075
Igor Mammedovfec45852008-05-16 13:06:30 +04004076 node->server_type = le16_to_cpu(ref->ServerType);
4077 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4078
4079 /* copy DfsPath */
4080 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4081 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004082 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4083 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004084 if (!node->path_name) {
4085 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004086 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004087 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004088
4089 /* copy link target UNC */
4090 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4091 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004092 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4093 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004094 if (!node->node_name)
4095 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004096 }
4097
Steve Frencha1fe78f2008-05-16 18:48:38 +00004098parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004099 if (rc) {
4100 free_dfs_info_array(*target_nodes, *num_of_nodes);
4101 *target_nodes = NULL;
4102 *num_of_nodes = 0;
4103 }
4104 return rc;
4105}
4106
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107int
4108CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4109 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004110 struct dfs_info3_param **target_nodes,
4111 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004112 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113{
4114/* TRANS2_GET_DFS_REFERRAL */
4115 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4116 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 int rc = 0;
4118 int bytes_returned;
4119 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004121 *num_of_nodes = 0;
4122 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123
4124 cFYI(1, ("In GetDFSRefer the path %s", searchName));
4125 if (ses == NULL)
4126 return -ENODEV;
4127getDFSRetry:
4128 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4129 (void **) &pSMBr);
4130 if (rc)
4131 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004132
4133 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004134 but should never be null here anyway */
4135 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 pSMB->hdr.Tid = ses->ipc_tid;
4137 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004138 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004140 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143 if (ses->capabilities & CAP_UNICODE) {
4144 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4145 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004146 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004147 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 name_len++; /* trailing null */
4149 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004150 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 name_len = strnlen(searchName, PATH_MAX);
4152 name_len++; /* trailing null */
4153 strncpy(pSMB->RequestFileName, searchName, name_len);
4154 }
4155
Steve French790fe572007-07-07 19:25:05 +00004156 if (ses->server) {
4157 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004158 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4159 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4160 }
4161
Steve French50c2f752007-07-13 00:33:32 +00004162 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004163
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 params = 2 /* level */ + name_len /*includes null */ ;
4165 pSMB->TotalDataCount = 0;
4166 pSMB->DataCount = 0;
4167 pSMB->DataOffset = 0;
4168 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004169 /* BB find exact max SMB PDU from sess structure BB */
4170 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 pSMB->MaxSetupCount = 0;
4172 pSMB->Reserved = 0;
4173 pSMB->Flags = 0;
4174 pSMB->Timeout = 0;
4175 pSMB->Reserved2 = 0;
4176 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004177 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 pSMB->SetupCount = 1;
4179 pSMB->Reserved3 = 0;
4180 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4181 byte_count = params + 3 /* pad */ ;
4182 pSMB->ParameterCount = cpu_to_le16(params);
4183 pSMB->TotalParameterCount = pSMB->ParameterCount;
4184 pSMB->MaxReferralLevel = cpu_to_le16(3);
4185 pSMB->hdr.smb_buf_length += byte_count;
4186 pSMB->ByteCount = cpu_to_le16(byte_count);
4187
4188 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4190 if (rc) {
4191 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004192 goto GetDFSRefExit;
4193 }
4194 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004196 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004197 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004198 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004199 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004201
4202 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4203 pSMBr->ByteCount,
4204 le16_to_cpu(pSMBr->t2.DataOffset)));
4205
4206 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004207 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004208 target_nodes, nls_codepage, remap,
4209 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004210
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004212 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213
4214 if (rc == -EAGAIN)
4215 goto getDFSRetry;
4216
4217 return rc;
4218}
4219
Steve French20962432005-09-21 22:05:57 -07004220/* Query File System Info such as free space to old servers such as Win 9x */
4221int
4222SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4223{
4224/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4225 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4226 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4227 FILE_SYSTEM_ALLOC_INFO *response_data;
4228 int rc = 0;
4229 int bytes_returned = 0;
4230 __u16 params, byte_count;
4231
4232 cFYI(1, ("OldQFSInfo"));
4233oldQFSInfoRetry:
4234 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4235 (void **) &pSMBr);
4236 if (rc)
4237 return rc;
Steve French20962432005-09-21 22:05:57 -07004238
4239 params = 2; /* level */
4240 pSMB->TotalDataCount = 0;
4241 pSMB->MaxParameterCount = cpu_to_le16(2);
4242 pSMB->MaxDataCount = cpu_to_le16(1000);
4243 pSMB->MaxSetupCount = 0;
4244 pSMB->Reserved = 0;
4245 pSMB->Flags = 0;
4246 pSMB->Timeout = 0;
4247 pSMB->Reserved2 = 0;
4248 byte_count = params + 1 /* pad */ ;
4249 pSMB->TotalParameterCount = cpu_to_le16(params);
4250 pSMB->ParameterCount = pSMB->TotalParameterCount;
4251 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4252 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4253 pSMB->DataCount = 0;
4254 pSMB->DataOffset = 0;
4255 pSMB->SetupCount = 1;
4256 pSMB->Reserved3 = 0;
4257 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4258 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4259 pSMB->hdr.smb_buf_length += byte_count;
4260 pSMB->ByteCount = cpu_to_le16(byte_count);
4261
4262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4264 if (rc) {
4265 cFYI(1, ("Send error in QFSInfo = %d", rc));
4266 } else { /* decode response */
4267 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4268
4269 if (rc || (pSMBr->ByteCount < 18))
4270 rc = -EIO; /* bad smb */
4271 else {
4272 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004273 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004274 pSMBr->ByteCount, data_offset));
4275
Steve French50c2f752007-07-13 00:33:32 +00004276 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004277 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4278 FSData->f_bsize =
4279 le16_to_cpu(response_data->BytesPerSector) *
4280 le32_to_cpu(response_data->
4281 SectorsPerAllocationUnit);
4282 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004283 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004284 FSData->f_bfree = FSData->f_bavail =
4285 le32_to_cpu(response_data->FreeAllocationUnits);
4286 cFYI(1,
4287 ("Blocks: %lld Free: %lld Block size %ld",
4288 (unsigned long long)FSData->f_blocks,
4289 (unsigned long long)FSData->f_bfree,
4290 FSData->f_bsize));
4291 }
4292 }
4293 cifs_buf_release(pSMB);
4294
4295 if (rc == -EAGAIN)
4296 goto oldQFSInfoRetry;
4297
4298 return rc;
4299}
4300
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301int
Steve French737b7582005-04-28 22:41:06 -07004302CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303{
4304/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4305 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4306 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4307 FILE_SYSTEM_INFO *response_data;
4308 int rc = 0;
4309 int bytes_returned = 0;
4310 __u16 params, byte_count;
4311
4312 cFYI(1, ("In QFSInfo"));
4313QFSInfoRetry:
4314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4315 (void **) &pSMBr);
4316 if (rc)
4317 return rc;
4318
4319 params = 2; /* level */
4320 pSMB->TotalDataCount = 0;
4321 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004322 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 pSMB->MaxSetupCount = 0;
4324 pSMB->Reserved = 0;
4325 pSMB->Flags = 0;
4326 pSMB->Timeout = 0;
4327 pSMB->Reserved2 = 0;
4328 byte_count = params + 1 /* pad */ ;
4329 pSMB->TotalParameterCount = cpu_to_le16(params);
4330 pSMB->ParameterCount = pSMB->TotalParameterCount;
4331 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004332 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 pSMB->DataCount = 0;
4334 pSMB->DataOffset = 0;
4335 pSMB->SetupCount = 1;
4336 pSMB->Reserved3 = 0;
4337 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4338 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4339 pSMB->hdr.smb_buf_length += byte_count;
4340 pSMB->ByteCount = cpu_to_le16(byte_count);
4341
4342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4344 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004345 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004347 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348
Steve French20962432005-09-21 22:05:57 -07004349 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 rc = -EIO; /* bad smb */
4351 else {
4352 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353
4354 response_data =
4355 (FILE_SYSTEM_INFO
4356 *) (((char *) &pSMBr->hdr.Protocol) +
4357 data_offset);
4358 FSData->f_bsize =
4359 le32_to_cpu(response_data->BytesPerSector) *
4360 le32_to_cpu(response_data->
4361 SectorsPerAllocationUnit);
4362 FSData->f_blocks =
4363 le64_to_cpu(response_data->TotalAllocationUnits);
4364 FSData->f_bfree = FSData->f_bavail =
4365 le64_to_cpu(response_data->FreeAllocationUnits);
4366 cFYI(1,
4367 ("Blocks: %lld Free: %lld Block size %ld",
4368 (unsigned long long)FSData->f_blocks,
4369 (unsigned long long)FSData->f_bfree,
4370 FSData->f_bsize));
4371 }
4372 }
4373 cifs_buf_release(pSMB);
4374
4375 if (rc == -EAGAIN)
4376 goto QFSInfoRetry;
4377
4378 return rc;
4379}
4380
4381int
Steve French737b7582005-04-28 22:41:06 -07004382CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383{
4384/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4385 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4386 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4387 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4388 int rc = 0;
4389 int bytes_returned = 0;
4390 __u16 params, byte_count;
4391
4392 cFYI(1, ("In QFSAttributeInfo"));
4393QFSAttributeRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4398
4399 params = 2; /* level */
4400 pSMB->TotalDataCount = 0;
4401 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004402 /* BB find exact max SMB PDU from sess structure BB */
4403 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 pSMB->MaxSetupCount = 0;
4405 pSMB->Reserved = 0;
4406 pSMB->Flags = 0;
4407 pSMB->Timeout = 0;
4408 pSMB->Reserved2 = 0;
4409 byte_count = params + 1 /* pad */ ;
4410 pSMB->TotalParameterCount = cpu_to_le16(params);
4411 pSMB->ParameterCount = pSMB->TotalParameterCount;
4412 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004413 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 pSMB->DataCount = 0;
4415 pSMB->DataOffset = 0;
4416 pSMB->SetupCount = 1;
4417 pSMB->Reserved3 = 0;
4418 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4419 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4420 pSMB->hdr.smb_buf_length += byte_count;
4421 pSMB->ByteCount = cpu_to_le16(byte_count);
4422
4423 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4425 if (rc) {
4426 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4427 } else { /* decode response */
4428 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4429
Steve French50c2f752007-07-13 00:33:32 +00004430 if (rc || (pSMBr->ByteCount < 13)) {
4431 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 rc = -EIO; /* bad smb */
4433 } else {
4434 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4435 response_data =
4436 (FILE_SYSTEM_ATTRIBUTE_INFO
4437 *) (((char *) &pSMBr->hdr.Protocol) +
4438 data_offset);
4439 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004440 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 }
4442 }
4443 cifs_buf_release(pSMB);
4444
4445 if (rc == -EAGAIN)
4446 goto QFSAttributeRetry;
4447
4448 return rc;
4449}
4450
4451int
Steve French737b7582005-04-28 22:41:06 -07004452CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453{
4454/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4455 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4456 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4457 FILE_SYSTEM_DEVICE_INFO *response_data;
4458 int rc = 0;
4459 int bytes_returned = 0;
4460 __u16 params, byte_count;
4461
4462 cFYI(1, ("In QFSDeviceInfo"));
4463QFSDeviceRetry:
4464 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4465 (void **) &pSMBr);
4466 if (rc)
4467 return rc;
4468
4469 params = 2; /* level */
4470 pSMB->TotalDataCount = 0;
4471 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004472 /* BB find exact max SMB PDU from sess structure BB */
4473 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 pSMB->MaxSetupCount = 0;
4475 pSMB->Reserved = 0;
4476 pSMB->Flags = 0;
4477 pSMB->Timeout = 0;
4478 pSMB->Reserved2 = 0;
4479 byte_count = params + 1 /* pad */ ;
4480 pSMB->TotalParameterCount = cpu_to_le16(params);
4481 pSMB->ParameterCount = pSMB->TotalParameterCount;
4482 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004483 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484
4485 pSMB->DataCount = 0;
4486 pSMB->DataOffset = 0;
4487 pSMB->SetupCount = 1;
4488 pSMB->Reserved3 = 0;
4489 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4490 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4491 pSMB->hdr.smb_buf_length += byte_count;
4492 pSMB->ByteCount = cpu_to_le16(byte_count);
4493
4494 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4495 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4496 if (rc) {
4497 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4498 } else { /* decode response */
4499 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4500
Steve French630f3f0c2007-10-25 21:17:17 +00004501 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 rc = -EIO; /* bad smb */
4503 else {
4504 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4505 response_data =
Steve French737b7582005-04-28 22:41:06 -07004506 (FILE_SYSTEM_DEVICE_INFO *)
4507 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 data_offset);
4509 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004510 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 }
4512 }
4513 cifs_buf_release(pSMB);
4514
4515 if (rc == -EAGAIN)
4516 goto QFSDeviceRetry;
4517
4518 return rc;
4519}
4520
4521int
Steve French737b7582005-04-28 22:41:06 -07004522CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523{
4524/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4525 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4526 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4527 FILE_SYSTEM_UNIX_INFO *response_data;
4528 int rc = 0;
4529 int bytes_returned = 0;
4530 __u16 params, byte_count;
4531
4532 cFYI(1, ("In QFSUnixInfo"));
4533QFSUnixRetry:
4534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4535 (void **) &pSMBr);
4536 if (rc)
4537 return rc;
4538
4539 params = 2; /* level */
4540 pSMB->TotalDataCount = 0;
4541 pSMB->DataCount = 0;
4542 pSMB->DataOffset = 0;
4543 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004544 /* BB find exact max SMB PDU from sess structure BB */
4545 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 pSMB->MaxSetupCount = 0;
4547 pSMB->Reserved = 0;
4548 pSMB->Flags = 0;
4549 pSMB->Timeout = 0;
4550 pSMB->Reserved2 = 0;
4551 byte_count = params + 1 /* pad */ ;
4552 pSMB->ParameterCount = cpu_to_le16(params);
4553 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004554 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4555 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 pSMB->SetupCount = 1;
4557 pSMB->Reserved3 = 0;
4558 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4560 pSMB->hdr.smb_buf_length += byte_count;
4561 pSMB->ByteCount = cpu_to_le16(byte_count);
4562
4563 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4564 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4565 if (rc) {
4566 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4567 } else { /* decode response */
4568 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4569
4570 if (rc || (pSMBr->ByteCount < 13)) {
4571 rc = -EIO; /* bad smb */
4572 } else {
4573 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4574 response_data =
4575 (FILE_SYSTEM_UNIX_INFO
4576 *) (((char *) &pSMBr->hdr.Protocol) +
4577 data_offset);
4578 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004579 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 }
4581 }
4582 cifs_buf_release(pSMB);
4583
4584 if (rc == -EAGAIN)
4585 goto QFSUnixRetry;
4586
4587
4588 return rc;
4589}
4590
Jeremy Allisonac670552005-06-22 17:26:35 -07004591int
Steve French45abc6e2005-06-23 13:42:03 -05004592CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004593{
4594/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4595 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4596 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4597 int rc = 0;
4598 int bytes_returned = 0;
4599 __u16 params, param_offset, offset, byte_count;
4600
4601 cFYI(1, ("In SETFSUnixInfo"));
4602SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004603 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004604 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4605 (void **) &pSMBr);
4606 if (rc)
4607 return rc;
4608
4609 params = 4; /* 2 bytes zero followed by info level. */
4610 pSMB->MaxSetupCount = 0;
4611 pSMB->Reserved = 0;
4612 pSMB->Flags = 0;
4613 pSMB->Timeout = 0;
4614 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004615 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4616 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004617 offset = param_offset + params;
4618
4619 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004620 /* BB find exact max SMB PDU from sess structure BB */
4621 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004622 pSMB->SetupCount = 1;
4623 pSMB->Reserved3 = 0;
4624 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4625 byte_count = 1 /* pad */ + params + 12;
4626
4627 pSMB->DataCount = cpu_to_le16(12);
4628 pSMB->ParameterCount = cpu_to_le16(params);
4629 pSMB->TotalDataCount = pSMB->DataCount;
4630 pSMB->TotalParameterCount = pSMB->ParameterCount;
4631 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4632 pSMB->DataOffset = cpu_to_le16(offset);
4633
4634 /* Params. */
4635 pSMB->FileNum = 0;
4636 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4637
4638 /* Data. */
4639 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4640 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4641 pSMB->ClientUnixCap = cpu_to_le64(cap);
4642
4643 pSMB->hdr.smb_buf_length += byte_count;
4644 pSMB->ByteCount = cpu_to_le16(byte_count);
4645
4646 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4647 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4648 if (rc) {
4649 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4650 } else { /* decode response */
4651 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004652 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004653 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004654 }
4655 cifs_buf_release(pSMB);
4656
4657 if (rc == -EAGAIN)
4658 goto SETFSUnixRetry;
4659
4660 return rc;
4661}
4662
4663
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664
4665int
4666CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004667 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668{
4669/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4670 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4671 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4672 FILE_SYSTEM_POSIX_INFO *response_data;
4673 int rc = 0;
4674 int bytes_returned = 0;
4675 __u16 params, byte_count;
4676
4677 cFYI(1, ("In QFSPosixInfo"));
4678QFSPosixRetry:
4679 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4680 (void **) &pSMBr);
4681 if (rc)
4682 return rc;
4683
4684 params = 2; /* level */
4685 pSMB->TotalDataCount = 0;
4686 pSMB->DataCount = 0;
4687 pSMB->DataOffset = 0;
4688 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004689 /* BB find exact max SMB PDU from sess structure BB */
4690 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 pSMB->MaxSetupCount = 0;
4692 pSMB->Reserved = 0;
4693 pSMB->Flags = 0;
4694 pSMB->Timeout = 0;
4695 pSMB->Reserved2 = 0;
4696 byte_count = params + 1 /* pad */ ;
4697 pSMB->ParameterCount = cpu_to_le16(params);
4698 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004699 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4700 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 pSMB->SetupCount = 1;
4702 pSMB->Reserved3 = 0;
4703 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4704 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4705 pSMB->hdr.smb_buf_length += byte_count;
4706 pSMB->ByteCount = cpu_to_le16(byte_count);
4707
4708 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4709 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4710 if (rc) {
4711 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4712 } else { /* decode response */
4713 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4714
4715 if (rc || (pSMBr->ByteCount < 13)) {
4716 rc = -EIO; /* bad smb */
4717 } else {
4718 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4719 response_data =
4720 (FILE_SYSTEM_POSIX_INFO
4721 *) (((char *) &pSMBr->hdr.Protocol) +
4722 data_offset);
4723 FSData->f_bsize =
4724 le32_to_cpu(response_data->BlockSize);
4725 FSData->f_blocks =
4726 le64_to_cpu(response_data->TotalBlocks);
4727 FSData->f_bfree =
4728 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004729 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 FSData->f_bavail = FSData->f_bfree;
4731 } else {
4732 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004733 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 }
Steve French790fe572007-07-07 19:25:05 +00004735 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004737 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004738 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004740 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 }
4742 }
4743 cifs_buf_release(pSMB);
4744
4745 if (rc == -EAGAIN)
4746 goto QFSPosixRetry;
4747
4748 return rc;
4749}
4750
4751
Steve French50c2f752007-07-13 00:33:32 +00004752/* We can not use write of zero bytes trick to
4753 set file size due to need for large file support. Also note that
4754 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 routine which is only needed to work around a sharing violation bug
4756 in Samba which this routine can run into */
4757
4758int
4759CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004760 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004761 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762{
4763 struct smb_com_transaction2_spi_req *pSMB = NULL;
4764 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4765 struct file_end_of_file_info *parm_data;
4766 int name_len;
4767 int rc = 0;
4768 int bytes_returned = 0;
4769 __u16 params, byte_count, data_count, param_offset, offset;
4770
4771 cFYI(1, ("In SetEOF"));
4772SetEOFRetry:
4773 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4774 (void **) &pSMBr);
4775 if (rc)
4776 return rc;
4777
4778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4779 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004780 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004781 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 name_len++; /* trailing null */
4783 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004784 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 name_len = strnlen(fileName, PATH_MAX);
4786 name_len++; /* trailing null */
4787 strncpy(pSMB->FileName, fileName, name_len);
4788 }
4789 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004790 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004792 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793 pSMB->MaxSetupCount = 0;
4794 pSMB->Reserved = 0;
4795 pSMB->Flags = 0;
4796 pSMB->Timeout = 0;
4797 pSMB->Reserved2 = 0;
4798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004799 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004801 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004802 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4803 pSMB->InformationLevel =
4804 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4805 else
4806 pSMB->InformationLevel =
4807 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4808 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4810 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004811 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 else
4813 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004814 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 }
4816
4817 parm_data =
4818 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4819 offset);
4820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4821 pSMB->DataOffset = cpu_to_le16(offset);
4822 pSMB->SetupCount = 1;
4823 pSMB->Reserved3 = 0;
4824 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4825 byte_count = 3 /* pad */ + params + data_count;
4826 pSMB->DataCount = cpu_to_le16(data_count);
4827 pSMB->TotalDataCount = pSMB->DataCount;
4828 pSMB->ParameterCount = cpu_to_le16(params);
4829 pSMB->TotalParameterCount = pSMB->ParameterCount;
4830 pSMB->Reserved4 = 0;
4831 pSMB->hdr.smb_buf_length += byte_count;
4832 parm_data->FileSize = cpu_to_le64(size);
4833 pSMB->ByteCount = cpu_to_le16(byte_count);
4834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004836 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838
4839 cifs_buf_release(pSMB);
4840
4841 if (rc == -EAGAIN)
4842 goto SetEOFRetry;
4843
4844 return rc;
4845}
4846
4847int
Steve French50c2f752007-07-13 00:33:32 +00004848CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004849 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850{
4851 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 char *data_offset;
4853 struct file_end_of_file_info *parm_data;
4854 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855 __u16 params, param_offset, offset, byte_count, count;
4856
4857 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4858 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004859 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4860
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861 if (rc)
4862 return rc;
4863
4864 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4865 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004866
Linus Torvalds1da177e2005-04-16 15:20:36 -07004867 params = 6;
4868 pSMB->MaxSetupCount = 0;
4869 pSMB->Reserved = 0;
4870 pSMB->Flags = 0;
4871 pSMB->Timeout = 0;
4872 pSMB->Reserved2 = 0;
4873 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4874 offset = param_offset + params;
4875
Steve French50c2f752007-07-13 00:33:32 +00004876 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877
4878 count = sizeof(struct file_end_of_file_info);
4879 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004880 /* BB find exact max SMB PDU from sess structure BB */
4881 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 pSMB->SetupCount = 1;
4883 pSMB->Reserved3 = 0;
4884 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4885 byte_count = 3 /* pad */ + params + count;
4886 pSMB->DataCount = cpu_to_le16(count);
4887 pSMB->ParameterCount = cpu_to_le16(params);
4888 pSMB->TotalDataCount = pSMB->DataCount;
4889 pSMB->TotalParameterCount = pSMB->ParameterCount;
4890 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4891 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004892 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4893 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 pSMB->DataOffset = cpu_to_le16(offset);
4895 parm_data->FileSize = cpu_to_le64(size);
4896 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004897 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4899 pSMB->InformationLevel =
4900 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4901 else
4902 pSMB->InformationLevel =
4903 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004904 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4906 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004907 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 else
4909 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004910 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911 }
4912 pSMB->Reserved4 = 0;
4913 pSMB->hdr.smb_buf_length += byte_count;
4914 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004915 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 if (rc) {
4917 cFYI(1,
4918 ("Send error in SetFileInfo (SetFileSize) = %d",
4919 rc));
4920 }
4921
Steve French50c2f752007-07-13 00:33:32 +00004922 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 since file handle passed in no longer valid */
4924
4925 return rc;
4926}
4927
Steve French50c2f752007-07-13 00:33:32 +00004928/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004929 an open handle, rather than by pathname - this is awkward due to
4930 potential access conflicts on the open, but it is unavoidable for these
4931 old servers since the only other choice is to go from 100 nanosecond DCE
4932 time and resort to the original setpathinfo level which takes the ancient
4933 DOS time format with 2 second granularity */
4934int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004935CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4936 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004937{
4938 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 char *data_offset;
4940 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004941 __u16 params, param_offset, offset, byte_count, count;
4942
4943 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004944 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4945
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 if (rc)
4947 return rc;
4948
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004949 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4950 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004951
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 params = 6;
4953 pSMB->MaxSetupCount = 0;
4954 pSMB->Reserved = 0;
4955 pSMB->Flags = 0;
4956 pSMB->Timeout = 0;
4957 pSMB->Reserved2 = 0;
4958 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4959 offset = param_offset + params;
4960
Steve French50c2f752007-07-13 00:33:32 +00004961 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962
Steve French26f57362007-08-30 22:09:15 +00004963 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004965 /* BB find max SMB PDU from sess */
4966 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 pSMB->SetupCount = 1;
4968 pSMB->Reserved3 = 0;
4969 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4970 byte_count = 3 /* pad */ + params + count;
4971 pSMB->DataCount = cpu_to_le16(count);
4972 pSMB->ParameterCount = cpu_to_le16(params);
4973 pSMB->TotalDataCount = pSMB->DataCount;
4974 pSMB->TotalParameterCount = pSMB->ParameterCount;
4975 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4976 pSMB->DataOffset = cpu_to_le16(offset);
4977 pSMB->Fid = fid;
4978 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4979 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4980 else
4981 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4982 pSMB->Reserved4 = 0;
4983 pSMB->hdr.smb_buf_length += byte_count;
4984 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004985 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004986 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004987 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004988 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004989
Steve French50c2f752007-07-13 00:33:32 +00004990 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004991 since file handle passed in no longer valid */
4992
4993 return rc;
4994}
4995
Jeff Layton6d22f092008-09-23 11:48:35 -04004996int
4997CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4998 bool delete_file, __u16 fid, __u32 pid_of_opener)
4999{
5000 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5001 char *data_offset;
5002 int rc = 0;
5003 __u16 params, param_offset, offset, byte_count, count;
5004
5005 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
5006 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5007
5008 if (rc)
5009 return rc;
5010
5011 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5012 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5013
5014 params = 6;
5015 pSMB->MaxSetupCount = 0;
5016 pSMB->Reserved = 0;
5017 pSMB->Flags = 0;
5018 pSMB->Timeout = 0;
5019 pSMB->Reserved2 = 0;
5020 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5021 offset = param_offset + params;
5022
5023 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5024
5025 count = 1;
5026 pSMB->MaxParameterCount = cpu_to_le16(2);
5027 /* BB find max SMB PDU from sess */
5028 pSMB->MaxDataCount = cpu_to_le16(1000);
5029 pSMB->SetupCount = 1;
5030 pSMB->Reserved3 = 0;
5031 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5032 byte_count = 3 /* pad */ + params + count;
5033 pSMB->DataCount = cpu_to_le16(count);
5034 pSMB->ParameterCount = cpu_to_le16(params);
5035 pSMB->TotalDataCount = pSMB->DataCount;
5036 pSMB->TotalParameterCount = pSMB->ParameterCount;
5037 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5038 pSMB->DataOffset = cpu_to_le16(offset);
5039 pSMB->Fid = fid;
5040 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5041 pSMB->Reserved4 = 0;
5042 pSMB->hdr.smb_buf_length += byte_count;
5043 pSMB->ByteCount = cpu_to_le16(byte_count);
5044 *data_offset = delete_file ? 1 : 0;
5045 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5046 if (rc)
5047 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
5048
5049 return rc;
5050}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051
5052int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005053CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5054 const char *fileName, const FILE_BASIC_INFO *data,
5055 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056{
5057 TRANSACTION2_SPI_REQ *pSMB = NULL;
5058 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5059 int name_len;
5060 int rc = 0;
5061 int bytes_returned = 0;
5062 char *data_offset;
5063 __u16 params, param_offset, offset, byte_count, count;
5064
5065 cFYI(1, ("In SetTimes"));
5066
5067SetTimesRetry:
5068 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5069 (void **) &pSMBr);
5070 if (rc)
5071 return rc;
5072
5073 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5074 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005075 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005076 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 name_len++; /* trailing null */
5078 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005079 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 name_len = strnlen(fileName, PATH_MAX);
5081 name_len++; /* trailing null */
5082 strncpy(pSMB->FileName, fileName, name_len);
5083 }
5084
5085 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005086 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005088 /* BB find max SMB PDU from sess structure BB */
5089 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 pSMB->MaxSetupCount = 0;
5091 pSMB->Reserved = 0;
5092 pSMB->Flags = 0;
5093 pSMB->Timeout = 0;
5094 pSMB->Reserved2 = 0;
5095 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005096 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 offset = param_offset + params;
5098 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5099 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5100 pSMB->DataOffset = cpu_to_le16(offset);
5101 pSMB->SetupCount = 1;
5102 pSMB->Reserved3 = 0;
5103 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5104 byte_count = 3 /* pad */ + params + count;
5105
5106 pSMB->DataCount = cpu_to_le16(count);
5107 pSMB->ParameterCount = cpu_to_le16(params);
5108 pSMB->TotalDataCount = pSMB->DataCount;
5109 pSMB->TotalParameterCount = pSMB->ParameterCount;
5110 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5111 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5112 else
5113 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5114 pSMB->Reserved4 = 0;
5115 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005116 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 pSMB->ByteCount = cpu_to_le16(byte_count);
5118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005120 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122
5123 cifs_buf_release(pSMB);
5124
5125 if (rc == -EAGAIN)
5126 goto SetTimesRetry;
5127
5128 return rc;
5129}
5130
5131/* Can not be used to set time stamps yet (due to old DOS time format) */
5132/* Can be used to set attributes */
5133#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5134 handling it anyway and NT4 was what we thought it would be needed for
5135 Do not delete it until we prove whether needed for Win9x though */
5136int
5137CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5138 __u16 dos_attrs, const struct nls_table *nls_codepage)
5139{
5140 SETATTR_REQ *pSMB = NULL;
5141 SETATTR_RSP *pSMBr = NULL;
5142 int rc = 0;
5143 int bytes_returned;
5144 int name_len;
5145
5146 cFYI(1, ("In SetAttrLegacy"));
5147
5148SetAttrLgcyRetry:
5149 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5150 (void **) &pSMBr);
5151 if (rc)
5152 return rc;
5153
5154 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5155 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005156 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 PATH_MAX, nls_codepage);
5158 name_len++; /* trailing null */
5159 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005160 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 name_len = strnlen(fileName, PATH_MAX);
5162 name_len++; /* trailing null */
5163 strncpy(pSMB->fileName, fileName, name_len);
5164 }
5165 pSMB->attr = cpu_to_le16(dos_attrs);
5166 pSMB->BufferFormat = 0x04;
5167 pSMB->hdr.smb_buf_length += name_len + 1;
5168 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005171 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005172 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173
5174 cifs_buf_release(pSMB);
5175
5176 if (rc == -EAGAIN)
5177 goto SetAttrLgcyRetry;
5178
5179 return rc;
5180}
5181#endif /* temporarily unneeded SetAttr legacy function */
5182
Jeff Layton654cf142009-07-09 20:02:49 -04005183static void
5184cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5185 const struct cifs_unix_set_info_args *args)
5186{
5187 u64 mode = args->mode;
5188
5189 /*
5190 * Samba server ignores set of file size to zero due to bugs in some
5191 * older clients, but we should be precise - we use SetFileSize to
5192 * set file size and do not want to truncate file size to zero
5193 * accidently as happened on one Samba server beta by putting
5194 * zero instead of -1 here
5195 */
5196 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5197 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5198 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5199 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5200 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5201 data_offset->Uid = cpu_to_le64(args->uid);
5202 data_offset->Gid = cpu_to_le64(args->gid);
5203 /* better to leave device as zero when it is */
5204 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5205 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5206 data_offset->Permissions = cpu_to_le64(mode);
5207
5208 if (S_ISREG(mode))
5209 data_offset->Type = cpu_to_le32(UNIX_FILE);
5210 else if (S_ISDIR(mode))
5211 data_offset->Type = cpu_to_le32(UNIX_DIR);
5212 else if (S_ISLNK(mode))
5213 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5214 else if (S_ISCHR(mode))
5215 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5216 else if (S_ISBLK(mode))
5217 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5218 else if (S_ISFIFO(mode))
5219 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5220 else if (S_ISSOCK(mode))
5221 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5222}
5223
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005225CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5226 const struct cifs_unix_set_info_args *args,
5227 u16 fid, u32 pid_of_opener)
5228{
5229 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5230 FILE_UNIX_BASIC_INFO *data_offset;
5231 int rc = 0;
5232 u16 params, param_offset, offset, byte_count, count;
5233
5234 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5235 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5236
5237 if (rc)
5238 return rc;
5239
5240 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5241 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5242
5243 params = 6;
5244 pSMB->MaxSetupCount = 0;
5245 pSMB->Reserved = 0;
5246 pSMB->Flags = 0;
5247 pSMB->Timeout = 0;
5248 pSMB->Reserved2 = 0;
5249 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5250 offset = param_offset + params;
5251
5252 data_offset = (FILE_UNIX_BASIC_INFO *)
5253 ((char *)(&pSMB->hdr.Protocol) + offset);
5254 count = sizeof(FILE_UNIX_BASIC_INFO);
5255
5256 pSMB->MaxParameterCount = cpu_to_le16(2);
5257 /* BB find max SMB PDU from sess */
5258 pSMB->MaxDataCount = cpu_to_le16(1000);
5259 pSMB->SetupCount = 1;
5260 pSMB->Reserved3 = 0;
5261 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5262 byte_count = 3 /* pad */ + params + count;
5263 pSMB->DataCount = cpu_to_le16(count);
5264 pSMB->ParameterCount = cpu_to_le16(params);
5265 pSMB->TotalDataCount = pSMB->DataCount;
5266 pSMB->TotalParameterCount = pSMB->ParameterCount;
5267 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5268 pSMB->DataOffset = cpu_to_le16(offset);
5269 pSMB->Fid = fid;
5270 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5271 pSMB->Reserved4 = 0;
5272 pSMB->hdr.smb_buf_length += byte_count;
5273 pSMB->ByteCount = cpu_to_le16(byte_count);
5274
5275 cifs_fill_unix_set_info(data_offset, args);
5276
5277 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5278 if (rc)
5279 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5280
5281 /* Note: On -EAGAIN error only caller can retry on handle based calls
5282 since file handle passed in no longer valid */
5283
5284 return rc;
5285}
5286
5287int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005288CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5289 const struct cifs_unix_set_info_args *args,
5290 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291{
5292 TRANSACTION2_SPI_REQ *pSMB = NULL;
5293 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5294 int name_len;
5295 int rc = 0;
5296 int bytes_returned = 0;
5297 FILE_UNIX_BASIC_INFO *data_offset;
5298 __u16 params, param_offset, offset, count, byte_count;
5299
5300 cFYI(1, ("In SetUID/GID/Mode"));
5301setPermsRetry:
5302 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5303 (void **) &pSMBr);
5304 if (rc)
5305 return rc;
5306
5307 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5308 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005309 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005310 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 name_len++; /* trailing null */
5312 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005313 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 name_len = strnlen(fileName, PATH_MAX);
5315 name_len++; /* trailing null */
5316 strncpy(pSMB->FileName, fileName, name_len);
5317 }
5318
5319 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005320 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005322 /* BB find max SMB PDU from sess structure BB */
5323 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 pSMB->MaxSetupCount = 0;
5325 pSMB->Reserved = 0;
5326 pSMB->Flags = 0;
5327 pSMB->Timeout = 0;
5328 pSMB->Reserved2 = 0;
5329 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005330 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005331 offset = param_offset + params;
5332 data_offset =
5333 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5334 offset);
5335 memset(data_offset, 0, count);
5336 pSMB->DataOffset = cpu_to_le16(offset);
5337 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5338 pSMB->SetupCount = 1;
5339 pSMB->Reserved3 = 0;
5340 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5341 byte_count = 3 /* pad */ + params + count;
5342 pSMB->ParameterCount = cpu_to_le16(params);
5343 pSMB->DataCount = cpu_to_le16(count);
5344 pSMB->TotalParameterCount = pSMB->ParameterCount;
5345 pSMB->TotalDataCount = pSMB->DataCount;
5346 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5347 pSMB->Reserved4 = 0;
5348 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005349
Jeff Layton654cf142009-07-09 20:02:49 -04005350 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351
5352 pSMB->ByteCount = cpu_to_le16(byte_count);
5353 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5354 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005355 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357
Steve French0d817bc2008-05-22 02:02:03 +00005358 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 if (rc == -EAGAIN)
5360 goto setPermsRetry;
5361 return rc;
5362}
5363
Steve French50c2f752007-07-13 00:33:32 +00005364int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005365 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005366 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005367 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368{
5369 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005370 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5371 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005372 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 int bytes_returned;
5374
Steve French50c2f752007-07-13 00:33:32 +00005375 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005377 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 if (rc)
5379 return rc;
5380
5381 pSMB->TotalParameterCount = 0 ;
5382 pSMB->TotalDataCount = 0;
5383 pSMB->MaxParameterCount = cpu_to_le32(2);
5384 /* BB find exact data count max from sess structure BB */
5385 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005386/* BB VERIFY verify which is correct for above BB */
5387 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5388 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5389
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 pSMB->MaxSetupCount = 4;
5391 pSMB->Reserved = 0;
5392 pSMB->ParameterOffset = 0;
5393 pSMB->DataCount = 0;
5394 pSMB->DataOffset = 0;
5395 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5396 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5397 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005398 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5400 pSMB->Reserved2 = 0;
5401 pSMB->CompletionFilter = cpu_to_le32(filter);
5402 pSMB->Fid = netfid; /* file handle always le */
5403 pSMB->ByteCount = 0;
5404
5405 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005406 (struct smb_hdr *)pSMBr, &bytes_returned,
5407 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 if (rc) {
5409 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005410 } else {
5411 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005412 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005413 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005414 sizeof(struct dir_notify_req),
5415 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005416 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005417 dnotify_req->Pid = pSMB->hdr.Pid;
5418 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5419 dnotify_req->Mid = pSMB->hdr.Mid;
5420 dnotify_req->Tid = pSMB->hdr.Tid;
5421 dnotify_req->Uid = pSMB->hdr.Uid;
5422 dnotify_req->netfid = netfid;
5423 dnotify_req->pfile = pfile;
5424 dnotify_req->filter = filter;
5425 dnotify_req->multishot = multishot;
5426 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005427 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005428 &GlobalDnotifyReqList);
5429 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005430 } else
Steve French47c786e2005-10-11 20:03:18 -07005431 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 }
5433 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005434 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435}
Jeff Layton31c05192010-02-10 16:18:26 -05005436
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005438/*
5439 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5440 * function used by listxattr and getxattr type calls. When ea_name is set,
5441 * it looks for that attribute name and stuffs that value into the EAData
5442 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5443 * buffer. In both cases, the return value is either the length of the
5444 * resulting data or a negative error code. If EAData is a NULL pointer then
5445 * the data isn't copied to it, but the length is returned.
5446 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447ssize_t
5448CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005449 const unsigned char *searchName, const unsigned char *ea_name,
5450 char *EAData, size_t buf_size,
5451 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452{
5453 /* BB assumes one setup word */
5454 TRANSACTION2_QPI_REQ *pSMB = NULL;
5455 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5456 int rc = 0;
5457 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005458 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005459 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005460 struct fea *temp_fea;
5461 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005462 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005463 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
5465 cFYI(1, ("In Query All EAs path %s", searchName));
5466QAllEAsRetry:
5467 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5468 (void **) &pSMBr);
5469 if (rc)
5470 return rc;
5471
5472 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005473 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005474 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005475 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005476 list_len++; /* trailing null */
5477 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005479 list_len = strnlen(searchName, PATH_MAX);
5480 list_len++; /* trailing null */
5481 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 }
5483
Jeff Layton6e462b92010-02-10 16:18:26 -05005484 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 pSMB->TotalDataCount = 0;
5486 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005487 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005488 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 pSMB->MaxSetupCount = 0;
5490 pSMB->Reserved = 0;
5491 pSMB->Flags = 0;
5492 pSMB->Timeout = 0;
5493 pSMB->Reserved2 = 0;
5494 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005495 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496 pSMB->DataCount = 0;
5497 pSMB->DataOffset = 0;
5498 pSMB->SetupCount = 1;
5499 pSMB->Reserved3 = 0;
5500 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5501 byte_count = params + 1 /* pad */ ;
5502 pSMB->TotalParameterCount = cpu_to_le16(params);
5503 pSMB->ParameterCount = pSMB->TotalParameterCount;
5504 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5505 pSMB->Reserved4 = 0;
5506 pSMB->hdr.smb_buf_length += byte_count;
5507 pSMB->ByteCount = cpu_to_le16(byte_count);
5508
5509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5511 if (rc) {
5512 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
Jeff Laytonf0d38682010-02-10 16:18:26 -05005513 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005515
5516
5517 /* BB also check enough total bytes returned */
5518 /* BB we need to improve the validity checking
5519 of these trans2 responses */
5520
5521 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5522 if (rc || (pSMBr->ByteCount < 4)) {
5523 rc = -EIO; /* bad smb */
5524 goto QAllEAsOut;
5525 }
5526
5527 /* check that length of list is not more than bcc */
5528 /* check that each entry does not go beyond length
5529 of list */
5530 /* check that each element of each entry does not
5531 go beyond end of list */
5532 /* validate_trans2_offsets() */
5533 /* BB check if start of smb + data_offset > &bcc+ bcc */
5534
5535 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5536 ea_response_data = (struct fealist *)
5537 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5538
Jeff Layton6e462b92010-02-10 16:18:26 -05005539 list_len = le32_to_cpu(ea_response_data->list_len);
5540 cFYI(1, ("ea length %d", list_len));
5541 if (list_len <= 8) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005542 cFYI(1, ("empty EA list returned from server"));
5543 goto QAllEAsOut;
5544 }
5545
Jeff Layton0cd126b2010-02-10 16:18:26 -05005546 /* make sure list_len doesn't go past end of SMB */
5547 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5548 if ((char *)ea_response_data + list_len > end_of_smb) {
5549 cFYI(1, ("EA list appears to go beyond SMB"));
5550 rc = -EIO;
5551 goto QAllEAsOut;
5552 }
5553
Jeff Laytonf0d38682010-02-10 16:18:26 -05005554 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005555 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005556 temp_fea = ea_response_data->list;
5557 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005558 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005559 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005560 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005561
Jeff Layton6e462b92010-02-10 16:18:26 -05005562 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005563 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005564 /* make sure we can read name_len and value_len */
5565 if (list_len < 0) {
5566 cFYI(1, ("EA entry goes beyond length of list"));
5567 rc = -EIO;
5568 goto QAllEAsOut;
5569 }
5570
5571 name_len = temp_fea->name_len;
5572 value_len = le16_to_cpu(temp_fea->value_len);
5573 list_len -= name_len + 1 + value_len;
5574 if (list_len < 0) {
5575 cFYI(1, ("EA entry goes beyond length of list"));
5576 rc = -EIO;
5577 goto QAllEAsOut;
5578 }
5579
Jeff Layton31c05192010-02-10 16:18:26 -05005580 if (ea_name) {
5581 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5582 temp_ptr += name_len + 1;
5583 rc = value_len;
5584 if (buf_size == 0)
5585 goto QAllEAsOut;
5586 if ((size_t)value_len > buf_size) {
5587 rc = -ERANGE;
5588 goto QAllEAsOut;
5589 }
5590 memcpy(EAData, temp_ptr, value_len);
5591 goto QAllEAsOut;
5592 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005593 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005594 /* account for prefix user. and trailing null */
5595 rc += (5 + 1 + name_len);
5596 if (rc < (int) buf_size) {
5597 memcpy(EAData, "user.", 5);
5598 EAData += 5;
5599 memcpy(EAData, temp_ptr, name_len);
5600 EAData += name_len;
5601 /* null terminate name */
5602 *EAData = 0;
5603 ++EAData;
5604 } else if (buf_size == 0) {
5605 /* skip copy - calc size only */
5606 } else {
5607 /* stop before overrun buffer */
5608 rc = -ERANGE;
5609 break;
5610 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005611 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005612 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005613 temp_fea = (struct fea *)temp_ptr;
5614 }
5615
Jeff Layton31c05192010-02-10 16:18:26 -05005616 /* didn't find the named attribute */
5617 if (ea_name)
5618 rc = -ENODATA;
5619
Jeff Laytonf0d38682010-02-10 16:18:26 -05005620QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005621 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 if (rc == -EAGAIN)
5623 goto QAllEAsRetry;
5624
5625 return (ssize_t)rc;
5626}
5627
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628int
5629CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005630 const char *ea_name, const void *ea_value,
5631 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5632 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633{
5634 struct smb_com_transaction2_spi_req *pSMB = NULL;
5635 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5636 struct fealist *parm_data;
5637 int name_len;
5638 int rc = 0;
5639 int bytes_returned = 0;
5640 __u16 params, param_offset, byte_count, offset, count;
5641
5642 cFYI(1, ("In SetEA"));
5643SetEARetry:
5644 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5645 (void **) &pSMBr);
5646 if (rc)
5647 return rc;
5648
5649 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5650 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005651 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005652 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 name_len++; /* trailing null */
5654 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005655 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 name_len = strnlen(fileName, PATH_MAX);
5657 name_len++; /* trailing null */
5658 strncpy(pSMB->FileName, fileName, name_len);
5659 }
5660
5661 params = 6 + name_len;
5662
5663 /* done calculating parms using name_len of file name,
5664 now use name_len to calculate length of ea name
5665 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005666 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 name_len = 0;
5668 else
Steve French50c2f752007-07-13 00:33:32 +00005669 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005671 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005672 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005673 /* BB find max SMB PDU from sess */
5674 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675 pSMB->MaxSetupCount = 0;
5676 pSMB->Reserved = 0;
5677 pSMB->Flags = 0;
5678 pSMB->Timeout = 0;
5679 pSMB->Reserved2 = 0;
5680 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005681 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682 offset = param_offset + params;
5683 pSMB->InformationLevel =
5684 cpu_to_le16(SMB_SET_FILE_EA);
5685
5686 parm_data =
5687 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5688 offset);
5689 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5690 pSMB->DataOffset = cpu_to_le16(offset);
5691 pSMB->SetupCount = 1;
5692 pSMB->Reserved3 = 0;
5693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5694 byte_count = 3 /* pad */ + params + count;
5695 pSMB->DataCount = cpu_to_le16(count);
5696 parm_data->list_len = cpu_to_le32(count);
5697 parm_data->list[0].EA_flags = 0;
5698 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005699 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005700 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005701 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005702 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703 parm_data->list[0].name[name_len] = 0;
5704 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5705 /* caller ensures that ea_value_len is less than 64K but
5706 we need to ensure that it fits within the smb */
5707
Steve French50c2f752007-07-13 00:33:32 +00005708 /*BB add length check to see if it would fit in
5709 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005710 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5711 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005712 memcpy(parm_data->list[0].name+name_len+1,
5713 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005714
5715 pSMB->TotalDataCount = pSMB->DataCount;
5716 pSMB->ParameterCount = cpu_to_le16(params);
5717 pSMB->TotalParameterCount = pSMB->ParameterCount;
5718 pSMB->Reserved4 = 0;
5719 pSMB->hdr.smb_buf_length += byte_count;
5720 pSMB->ByteCount = cpu_to_le16(byte_count);
5721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005723 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005724 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
5726 cifs_buf_release(pSMB);
5727
5728 if (rc == -EAGAIN)
5729 goto SetEARetry;
5730
5731 return rc;
5732}
5733
5734#endif