blob: ae5e451a0d089a274245d8a2eed40edeab5fd8d0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
35#include <asm/uaccess.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000038#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42
43#ifdef CONFIG_CIFS_POSIX
44static struct {
45 int index;
46 char *name;
47} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000048#ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000050 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000051#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000052 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000053 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 {BAD_PROT, "\2"}
55};
56#else
57static struct {
58 int index;
59 char *name;
60} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000061#ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000063 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000064#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000065 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 {BAD_PROT, "\2"}
67};
68#endif
69
Steve French39798772006-05-31 22:40:51 +000070/* define the number of elements in the cifs dialect array */
71#ifdef CONFIG_CIFS_POSIX
72#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000073#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000074#else
75#define CIFS_NUM_PROT 2
76#endif /* CIFS_WEAK_PW_HASH */
77#else /* not posix */
78#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000079#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000080#else
81#define CIFS_NUM_PROT 1
82#endif /* CONFIG_CIFS_WEAK_PW_HASH */
83#endif /* CIFS_POSIX */
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -040094 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 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 }
Jeff Layton44772882010-10-15 15:34:03 -0400100 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Jeff Layton9162ab22009-09-03 12:07:17 -0400105/* reconnect the socket, tcon, and smb session if needed */
106static int
107cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
108{
109 int rc = 0;
110 struct cifsSesInfo *ses;
111 struct TCP_Server_Info *server;
112 struct nls_table *nls_codepage;
113
114 /*
115 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
116 * tcp and smb session status done differently for those three - in the
117 * calling routine
118 */
119 if (!tcon)
120 return 0;
121
122 ses = tcon->ses;
123 server = ses->server;
124
125 /*
126 * only tree disconnect, open, and write, (and ulogoff which does not
127 * have tcon) are allowed as we start force umount
128 */
129 if (tcon->tidStatus == CifsExiting) {
130 if (smb_command != SMB_COM_WRITE_ANDX &&
131 smb_command != SMB_COM_OPEN_ANDX &&
132 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000133 cFYI(1, "can not send cmd %d while umounting",
134 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400135 return -ENODEV;
136 }
137 }
138
Jeff Layton9162ab22009-09-03 12:07:17 -0400139 /*
140 * Give demultiplex thread up to 10 seconds to reconnect, should be
141 * greater than cifs socket timeout which is 7 seconds
142 */
143 while (server->tcpStatus == CifsNeedReconnect) {
144 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000145 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400146
Steve Frenchfd88ce92011-04-12 01:01:14 +0000147 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400148 if (server->tcpStatus != CifsNeedReconnect)
149 break;
150
151 /*
152 * on "soft" mounts we wait once. Hard mounts keep
153 * retrying until process is killed or server comes
154 * back on-line
155 */
Jeff Laytond4025392011-02-07 08:54:35 -0500156 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000157 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400158 return -EHOSTDOWN;
159 }
160 }
161
162 if (!ses->need_reconnect && !tcon->need_reconnect)
163 return 0;
164
165 nls_codepage = load_nls_default();
166
167 /*
168 * need to prevent multiple threads trying to simultaneously
169 * reconnect the same SMB session
170 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000171 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400172 rc = cifs_negotiate_protocol(0, ses);
173 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400174 rc = cifs_setup_session(0, ses, nls_codepage);
175
176 /* do we need to reconnect tcon? */
177 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000178 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400179 goto out;
180 }
181
182 mark_open_files_invalid(tcon);
183 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000184 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000185 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400186
187 if (rc)
188 goto out;
189
190 /*
191 * FIXME: check if wsize needs updated due to negotiated smb buffer
192 * size shrinking
193 */
194 atomic_inc(&tconInfoReconnectCount);
195
196 /* tell server Unix caps we support */
197 if (ses->capabilities & CAP_UNIX)
198 reset_cifs_unix_caps(0, tcon, NULL, NULL);
199
200 /*
201 * Removed call to reopen open files here. It is safer (and faster) to
202 * reopen files one at a time as needed in read and write.
203 *
204 * FIXME: what about file locks? don't we need to reclaim them ASAP?
205 */
206
207out:
208 /*
209 * Check if handle based operation so we know whether we can continue
210 * or not without returning to caller to reset file handle
211 */
212 switch (smb_command) {
213 case SMB_COM_READ_ANDX:
214 case SMB_COM_WRITE_ANDX:
215 case SMB_COM_CLOSE:
216 case SMB_COM_FIND_CLOSE2:
217 case SMB_COM_LOCKING_ANDX:
218 rc = -EAGAIN;
219 }
220
221 unload_nls(nls_codepage);
222 return rc;
223}
224
Steve Frenchad7a2922008-02-07 23:25:02 +0000225/* Allocate and return pointer to an SMB request buffer, and set basic
226 SMB information in the SMB header. If the return code is zero, this
227 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228static int
229small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000230 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Jeff Laytonf5695992010-09-29 15:27:08 -0400232 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Jeff Layton9162ab22009-09-03 12:07:17 -0400234 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000235 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 return rc;
237
238 *request_buf = cifs_small_buf_get();
239 if (*request_buf == NULL) {
240 /* BB should we add a retry in here if not a writepage? */
241 return -ENOMEM;
242 }
243
Steve French63135e02007-07-17 17:34:02 +0000244 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000245 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Steve French790fe572007-07-07 19:25:05 +0000247 if (tcon != NULL)
248 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700249
Jeff Laytonf5695992010-09-29 15:27:08 -0400250 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000251}
252
Steve French12b3b8f2006-02-09 21:12:47 +0000253int
Steve French50c2f752007-07-13 00:33:32 +0000254small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000255 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000256{
257 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000258 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000259
Steve French5815449d2006-02-14 01:36:20 +0000260 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000261 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000262 return rc;
263
Steve French04fdabe2006-02-10 05:52:50 +0000264 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000265 buffer->Mid = GetNextMid(ses->server);
266 if (ses->capabilities & CAP_UNICODE)
267 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000268 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
270
271 /* uid, tid can stay at zero as set in header assemble */
272
Steve French50c2f752007-07-13 00:33:32 +0000273 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000274 this function is used after 1st of session setup requests */
275
276 return rc;
277}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279/* If the return code is zero, this function must fill in request_buf pointer */
280static int
Jeff Laytonf5695992010-09-29 15:27:08 -0400281__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
282 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 *request_buf = cifs_buf_get();
285 if (*request_buf == NULL) {
286 /* BB should we add a retry in here if not a writepage? */
287 return -ENOMEM;
288 }
289 /* Although the original thought was we needed the response buf for */
290 /* potential retries of smb operations it turns out we can determine */
291 /* from the mid flags when the request buffer can be resent without */
292 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000293 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000294 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
296 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000297 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Steve French790fe572007-07-07 19:25:05 +0000299 if (tcon != NULL)
300 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700301
Jeff Laytonf5695992010-09-29 15:27:08 -0400302 return 0;
303}
304
305/* If the return code is zero, this function must fill in request_buf pointer */
306static int
307smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
308 void **request_buf, void **response_buf)
309{
310 int rc;
311
312 rc = cifs_reconnect_tcon(tcon, smb_command);
313 if (rc)
314 return rc;
315
316 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
317}
318
319static int
320smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
321 void **request_buf, void **response_buf)
322{
323 if (tcon->ses->need_reconnect || tcon->need_reconnect)
324 return -EHOSTDOWN;
325
326 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Steve French50c2f752007-07-13 00:33:32 +0000329static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Jeff Layton12df83c2011-01-20 13:36:51 -0500331 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Jeff Layton12df83c2011-01-20 13:36:51 -0500333 /* check for plausible wct */
334 if (pSMB->hdr.WordCount < 10)
335 goto vt2_err;
336
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500338 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
339 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
340 goto vt2_err;
341
342 /* check that bcc is at least as big as parms + data */
343 /* check that bcc is less than negotiated smb buffer */
344 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
345 if (total_size >= 512)
346 goto vt2_err;
347
348 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
349 if (total_size > get_bcc(&pSMB->hdr) ||
350 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
351 goto vt2_err;
352
353 return 0;
354vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000355 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500357 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358}
Jeff Layton690c5222011-01-20 13:36:51 -0500359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360int
361CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
362{
363 NEGOTIATE_REQ *pSMB;
364 NEGOTIATE_RSP *pSMBr;
365 int rc = 0;
366 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000367 int i;
Steve French50c2f752007-07-13 00:33:32 +0000368 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000370 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
Steve French790fe572007-07-07 19:25:05 +0000372 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 server = ses->server;
374 else {
375 rc = -EIO;
376 return rc;
377 }
378 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
379 (void **) &pSMB, (void **) &pSMBr);
380 if (rc)
381 return rc;
Steve French750d1152006-06-27 06:28:30 +0000382
383 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000384 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000385 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000386 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400387 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000388
Joe Perchesb6b38f72010-04-21 03:50:45 +0000389 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000390
Steve French1982c342005-08-17 12:38:22 -0700391 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000392 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000393
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000394 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000395 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000396 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000397 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000398 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500399 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000400 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
401 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000402 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000403 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
404 }
Steve French50c2f752007-07-13 00:33:32 +0000405
Steve French39798772006-05-31 22:40:51 +0000406 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000407 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000408 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
409 count += strlen(protocols[i].name) + 1;
410 /* null at end of source and target buffers anyway */
411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 pSMB->hdr.smb_buf_length += count;
413 pSMB->ByteCount = cpu_to_le16(count);
414
415 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000417 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000418 goto neg_err_exit;
419
Jeff Layton9bf67e52010-04-24 07:57:46 -0400420 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
421 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000422 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400423 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000424 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000425 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000426 could not negotiate a common dialect */
427 rc = -EOPNOTSUPP;
428 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000429#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000430 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400431 && ((server->dialect == LANMAN_PROT)
432 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000433 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000434 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000435
Steve French790fe572007-07-07 19:25:05 +0000436 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000437 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000438 server->secType = LANMAN;
439 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000440 cERROR(1, "mount failed weak security disabled"
441 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000442 rc = -EOPNOTSUPP;
443 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000444 }
Steve French254e55e2006-06-04 05:53:15 +0000445 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
446 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
447 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000448 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000449 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000450 /* even though we do not use raw we might as well set this
451 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000452 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000453 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000454 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
455 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000456 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000457 server->capabilities = CAP_MPX_MODE;
458 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000459 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000460 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000461 /* OS/2 often does not set timezone therefore
462 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000463 * Could deviate slightly from the right zone.
464 * Smallest defined timezone difference is 15 minutes
465 * (i.e. Nepal). Rounding up/down is done to match
466 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000467 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000468 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000469 struct timespec ts, utc;
470 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400471 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
472 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000473 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000474 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000475 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000477 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000478 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000479 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000480 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000481 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000482 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000483 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000484 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000485 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000486 server->timeAdj = (int)tmp;
487 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000488 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000489 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000490
Steve French39798772006-05-31 22:40:51 +0000491
Steve French254e55e2006-06-04 05:53:15 +0000492 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000493 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000494
Steve French50c2f752007-07-13 00:33:32 +0000495 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000496 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500497 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000498 CIFS_CRYPTO_KEY_SIZE);
499 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
500 rc = -EIO; /* need cryptkey unless plain text */
501 goto neg_err_exit;
502 }
Steve French39798772006-05-31 22:40:51 +0000503
Steve Frenchf19159d2010-04-21 04:12:10 +0000504 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000505 /* we will not end up setting signing flags - as no signing
506 was in LANMAN and server did not return the flags on */
507 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000508#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000509 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000510 cERROR(1, "mount failed, cifs module not built "
511 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300512 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000513#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000514 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000515 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000516 /* unknown wct */
517 rc = -EOPNOTSUPP;
518 goto neg_err_exit;
519 }
520 /* else wct == 17 NTLM */
521 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000522 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000523 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000524
Steve French790fe572007-07-07 19:25:05 +0000525 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000526#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000527 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000528#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000529 cERROR(1, "Server requests plain text password"
530 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000531
Steve French790fe572007-07-07 19:25:05 +0000532 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000533 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000534 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000535 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000536 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000537 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000538 else if (secFlags & CIFSSEC_MAY_KRB5)
539 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000540 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000541 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000542 else if (secFlags & CIFSSEC_MAY_LANMAN)
543 server->secType = LANMAN;
544/* #ifdef CONFIG_CIFS_EXPERIMENTAL
545 else if (secFlags & CIFSSEC_MAY_PLNTXT)
546 server->secType = ??
547#endif */
548 else {
549 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000550 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000551 goto neg_err_exit;
552 }
553 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000554
Steve French254e55e2006-06-04 05:53:15 +0000555 /* one byte, so no need to convert this or EncryptionKeyLen from
556 little endian */
557 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
558 /* probably no need to store and check maxvcs */
559 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000561 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000562 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000563 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000564 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
565 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000566 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500567 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000568 CIFS_CRYPTO_KEY_SIZE);
569 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
570 && (pSMBr->EncryptionKeyLength == 0)) {
571 /* decode security blob */
572 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
573 rc = -EIO; /* no crypt key only if plain text pwd */
574 goto neg_err_exit;
575 }
576
577 /* BB might be helpful to save off the domain of server here */
578
Steve French50c2f752007-07-13 00:33:32 +0000579 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000580 (server->capabilities & CAP_EXTENDED_SECURITY)) {
581 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000582 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000584 goto neg_err_exit;
585 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530586 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500587 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530588 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000589 if (memcmp(server->server_GUID,
590 pSMBr->u.extended_response.
591 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000592 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000593 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000594 pSMBr->u.extended_response.GUID,
595 16);
596 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500597 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530598 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000599 memcpy(server->server_GUID,
600 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500601 }
Jeff Laytone187e442007-10-16 17:10:44 +0000602
603 if (count == 16) {
604 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000605 } else {
606 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400607 SecurityBlob, count - 16,
608 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000609 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000610 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000611 else
Steve French254e55e2006-06-04 05:53:15 +0000612 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500613 if (server->secType == Kerberos) {
614 if (!server->sec_kerberos &&
615 !server->sec_mskerberos)
616 rc = -EOPNOTSUPP;
617 } else if (server->secType == RawNTLMSSP) {
618 if (!server->sec_ntlmssp)
619 rc = -EOPNOTSUPP;
620 } else
621 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 }
Steve French254e55e2006-06-04 05:53:15 +0000623 } else
624 server->capabilities &= ~CAP_EXTENDED_SECURITY;
625
Steve French6344a422006-06-12 04:18:35 +0000626#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000627signing_check:
Steve French6344a422006-06-12 04:18:35 +0000628#endif
Steve French762e5ab2007-06-28 18:41:42 +0000629 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
630 /* MUST_SIGN already includes the MAY_SIGN FLAG
631 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000632 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000633 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000634 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000635 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000637 rc = -EOPNOTSUPP;
638 }
Steve French50c2f752007-07-13 00:33:32 +0000639 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000640 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000641 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
642 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000643 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000644 if ((server->secMode &
645 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000646 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000647 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000648 } else
649 server->secMode |= SECMODE_SIGN_REQUIRED;
650 } else {
651 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000652 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000653 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000654 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Steve French50c2f752007-07-13 00:33:32 +0000656
657neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700658 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000659
Joe Perchesb6b38f72010-04-21 03:50:45 +0000660 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return rc;
662}
663
664int
665CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
666{
667 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Joe Perchesb6b38f72010-04-21 03:50:45 +0000670 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500671
672 /* BB: do we need to check this? These should never be NULL. */
673 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
674 return -EIO;
675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500677 * No need to return error on this operation if tid invalidated and
678 * closed on server already e.g. due to tcp session crashing. Also,
679 * the tcon is no longer on the list, so no need to take lock before
680 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 */
Steve French268875b2009-06-25 00:29:21 +0000682 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Steve French50c2f752007-07-13 00:33:32 +0000685 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700686 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500687 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return rc;
Steve French133672e2007-11-13 22:41:37 +0000689
690 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000692 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Steve French50c2f752007-07-13 00:33:32 +0000694 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500695 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (rc == -EAGAIN)
697 rc = 0;
698
699 return rc;
700}
701
Jeff Layton766fdbb2011-01-11 07:24:21 -0500702/*
703 * This is a no-op for now. We're not really interested in the reply, but
704 * rather in the fact that the server sent one and that server->lstrp
705 * gets updated.
706 *
707 * FIXME: maybe we should consider checking that the reply matches request?
708 */
709static void
710cifs_echo_callback(struct mid_q_entry *mid)
711{
712 struct TCP_Server_Info *server = mid->callback_data;
713
714 DeleteMidQEntry(mid);
715 atomic_dec(&server->inFlight);
716 wake_up(&server->request_q);
717}
718
719int
720CIFSSMBEcho(struct TCP_Server_Info *server)
721{
722 ECHO_REQ *smb;
723 int rc = 0;
724
725 cFYI(1, "In echo request");
726
727 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
728 if (rc)
729 return rc;
730
731 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000732 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500733 smb->hdr.WordCount = 1;
734 put_unaligned_le16(1, &smb->EchoCount);
735 put_bcc_le(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500736 smb->Data[0] = 'a';
737 smb->hdr.smb_buf_length += 3;
738
739 rc = cifs_call_async(server, (struct smb_hdr *)smb,
740 cifs_echo_callback, server);
741 if (rc)
742 cFYI(1, "Echo request failed: %d", rc);
743
744 cifs_small_buf_release(smb);
745
746 return rc;
747}
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749int
750CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
751{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 LOGOFF_ANDX_REQ *pSMB;
753 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Joe Perchesb6b38f72010-04-21 03:50:45 +0000755 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500756
757 /*
758 * BB: do we need to check validity of ses and server? They should
759 * always be valid since we have an active reference. If not, that
760 * should probably be a BUG()
761 */
762 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return -EIO;
764
Steve Frenchd7b619c2010-02-25 05:36:46 +0000765 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000766 if (ses->need_reconnect)
767 goto session_already_dead; /* no need to send SMBlogoff if uid
768 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
770 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000771 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return rc;
773 }
774
Steve French3b795212008-11-13 19:45:32 +0000775 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700776
Steve French3b795212008-11-13 19:45:32 +0000777 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
779 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 pSMB->hdr.Uid = ses->Suid;
782
783 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000784 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000785session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000786 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000789 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 error */
791 if (rc == -EAGAIN)
792 rc = 0;
793 return rc;
794}
795
796int
Steve French2d785a52007-07-15 01:48:57 +0000797CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
798 __u16 type, const struct nls_table *nls_codepage, int remap)
799{
800 TRANSACTION2_SPI_REQ *pSMB = NULL;
801 TRANSACTION2_SPI_RSP *pSMBr = NULL;
802 struct unlink_psx_rq *pRqD;
803 int name_len;
804 int rc = 0;
805 int bytes_returned = 0;
806 __u16 params, param_offset, offset, byte_count;
807
Joe Perchesb6b38f72010-04-21 03:50:45 +0000808 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000809PsxDelete:
810 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
811 (void **) &pSMBr);
812 if (rc)
813 return rc;
814
815 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
816 name_len =
817 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
818 PATH_MAX, nls_codepage, remap);
819 name_len++; /* trailing null */
820 name_len *= 2;
821 } else { /* BB add path length overrun check */
822 name_len = strnlen(fileName, PATH_MAX);
823 name_len++; /* trailing null */
824 strncpy(pSMB->FileName, fileName, name_len);
825 }
826
827 params = 6 + name_len;
828 pSMB->MaxParameterCount = cpu_to_le16(2);
829 pSMB->MaxDataCount = 0; /* BB double check this with jra */
830 pSMB->MaxSetupCount = 0;
831 pSMB->Reserved = 0;
832 pSMB->Flags = 0;
833 pSMB->Timeout = 0;
834 pSMB->Reserved2 = 0;
835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
836 InformationLevel) - 4;
837 offset = param_offset + params;
838
839 /* Setup pointer to Request Data (inode type) */
840 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
841 pRqD->type = cpu_to_le16(type);
842 pSMB->ParameterOffset = cpu_to_le16(param_offset);
843 pSMB->DataOffset = cpu_to_le16(offset);
844 pSMB->SetupCount = 1;
845 pSMB->Reserved3 = 0;
846 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
847 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
848
849 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
850 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
851 pSMB->ParameterCount = cpu_to_le16(params);
852 pSMB->TotalParameterCount = pSMB->ParameterCount;
853 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
854 pSMB->Reserved4 = 0;
855 pSMB->hdr.smb_buf_length += byte_count;
856 pSMB->ByteCount = cpu_to_le16(byte_count);
857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000859 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000860 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000861 cifs_buf_release(pSMB);
862
863 cifs_stats_inc(&tcon->num_deletes);
864
865 if (rc == -EAGAIN)
866 goto PsxDelete;
867
868 return rc;
869}
870
871int
Steve French737b7582005-04-28 22:41:06 -0700872CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
873 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
875 DELETE_FILE_REQ *pSMB = NULL;
876 DELETE_FILE_RSP *pSMBr = NULL;
877 int rc = 0;
878 int bytes_returned;
879 int name_len;
880
881DelFileRetry:
882 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
883 (void **) &pSMBr);
884 if (rc)
885 return rc;
886
887 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
888 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000889 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700890 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 name_len++; /* trailing null */
892 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700893 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 name_len = strnlen(fileName, PATH_MAX);
895 name_len++; /* trailing null */
896 strncpy(pSMB->fileName, fileName, name_len);
897 }
898 pSMB->SearchAttributes =
899 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
900 pSMB->BufferFormat = 0x04;
901 pSMB->hdr.smb_buf_length += name_len + 1;
902 pSMB->ByteCount = cpu_to_le16(name_len + 1);
903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700905 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000906 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000907 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909 cifs_buf_release(pSMB);
910 if (rc == -EAGAIN)
911 goto DelFileRetry;
912
913 return rc;
914}
915
916int
Steve French50c2f752007-07-13 00:33:32 +0000917CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700918 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
920 DELETE_DIRECTORY_REQ *pSMB = NULL;
921 DELETE_DIRECTORY_RSP *pSMBr = NULL;
922 int rc = 0;
923 int bytes_returned;
924 int name_len;
925
Joe Perchesb6b38f72010-04-21 03:50:45 +0000926 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927RmDirRetry:
928 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
929 (void **) &pSMBr);
930 if (rc)
931 return rc;
932
933 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700934 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
935 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 name_len++; /* trailing null */
937 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700938 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 name_len = strnlen(dirName, PATH_MAX);
940 name_len++; /* trailing null */
941 strncpy(pSMB->DirName, dirName, name_len);
942 }
943
944 pSMB->BufferFormat = 0x04;
945 pSMB->hdr.smb_buf_length += name_len + 1;
946 pSMB->ByteCount = cpu_to_le16(name_len + 1);
947 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700949 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000950 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000951 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 cifs_buf_release(pSMB);
954 if (rc == -EAGAIN)
955 goto RmDirRetry;
956 return rc;
957}
958
959int
960CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700961 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 int rc = 0;
964 CREATE_DIRECTORY_REQ *pSMB = NULL;
965 CREATE_DIRECTORY_RSP *pSMBr = NULL;
966 int bytes_returned;
967 int name_len;
968
Joe Perchesb6b38f72010-04-21 03:50:45 +0000969 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970MkDirRetry:
971 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
972 (void **) &pSMBr);
973 if (rc)
974 return rc;
975
976 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000977 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700978 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 name_len++; /* trailing null */
980 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700981 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 name_len = strnlen(name, PATH_MAX);
983 name_len++; /* trailing null */
984 strncpy(pSMB->DirName, name, name_len);
985 }
986
987 pSMB->BufferFormat = 0x04;
988 pSMB->hdr.smb_buf_length += name_len + 1;
989 pSMB->ByteCount = cpu_to_le16(name_len + 1);
990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700992 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000993 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000994 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700995
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 cifs_buf_release(pSMB);
997 if (rc == -EAGAIN)
998 goto MkDirRetry;
999 return rc;
1000}
1001
Steve French2dd29d32007-04-23 22:07:35 +00001002int
1003CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001004 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001005 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001006 const struct nls_table *nls_codepage, int remap)
1007{
1008 TRANSACTION2_SPI_REQ *pSMB = NULL;
1009 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1010 int name_len;
1011 int rc = 0;
1012 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001013 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001014 OPEN_PSX_REQ *pdata;
1015 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001016
Joe Perchesb6b38f72010-04-21 03:50:45 +00001017 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001018PsxCreat:
1019 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1020 (void **) &pSMBr);
1021 if (rc)
1022 return rc;
1023
1024 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1025 name_len =
1026 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1027 PATH_MAX, nls_codepage, remap);
1028 name_len++; /* trailing null */
1029 name_len *= 2;
1030 } else { /* BB improve the check for buffer overruns BB */
1031 name_len = strnlen(name, PATH_MAX);
1032 name_len++; /* trailing null */
1033 strncpy(pSMB->FileName, name, name_len);
1034 }
1035
1036 params = 6 + name_len;
1037 count = sizeof(OPEN_PSX_REQ);
1038 pSMB->MaxParameterCount = cpu_to_le16(2);
1039 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1040 pSMB->MaxSetupCount = 0;
1041 pSMB->Reserved = 0;
1042 pSMB->Flags = 0;
1043 pSMB->Timeout = 0;
1044 pSMB->Reserved2 = 0;
1045 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001046 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001047 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001048 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001049 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001050 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001051 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001052 pdata->OpenFlags = cpu_to_le32(*pOplock);
1053 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1054 pSMB->DataOffset = cpu_to_le16(offset);
1055 pSMB->SetupCount = 1;
1056 pSMB->Reserved3 = 0;
1057 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1058 byte_count = 3 /* pad */ + params + count;
1059
1060 pSMB->DataCount = cpu_to_le16(count);
1061 pSMB->ParameterCount = cpu_to_le16(params);
1062 pSMB->TotalDataCount = pSMB->DataCount;
1063 pSMB->TotalParameterCount = pSMB->ParameterCount;
1064 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1065 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001066 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001067 pSMB->ByteCount = cpu_to_le16(byte_count);
1068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1070 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001071 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001072 goto psx_create_err;
1073 }
1074
Joe Perchesb6b38f72010-04-21 03:50:45 +00001075 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1077
1078 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1079 rc = -EIO; /* bad smb */
1080 goto psx_create_err;
1081 }
1082
1083 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001084 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001085 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001086
Steve French2dd29d32007-04-23 22:07:35 +00001087 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001088 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001089 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1090 /* Let caller know file was created so we can set the mode. */
1091 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001092 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001093 *pOplock |= CIFS_CREATE_ACTION;
1094 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001095 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1096 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001097 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001098 } else {
Steve French790fe572007-07-07 19:25:05 +00001099 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001100 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001101 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001103 goto psx_create_err;
1104 }
Steve French50c2f752007-07-13 00:33:32 +00001105 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001106 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001107 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001108 }
Steve French2dd29d32007-04-23 22:07:35 +00001109
1110psx_create_err:
1111 cifs_buf_release(pSMB);
1112
Steve French65bc98b2009-07-10 15:27:25 +00001113 if (posix_flags & SMB_O_DIRECTORY)
1114 cifs_stats_inc(&tcon->num_posixmkdirs);
1115 else
1116 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001117
1118 if (rc == -EAGAIN)
1119 goto PsxCreat;
1120
Steve French50c2f752007-07-13 00:33:32 +00001121 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001122}
1123
Steve Frencha9d02ad2005-08-24 23:06:05 -07001124static __u16 convert_disposition(int disposition)
1125{
1126 __u16 ofun = 0;
1127
1128 switch (disposition) {
1129 case FILE_SUPERSEDE:
1130 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1131 break;
1132 case FILE_OPEN:
1133 ofun = SMBOPEN_OAPPEND;
1134 break;
1135 case FILE_CREATE:
1136 ofun = SMBOPEN_OCREATE;
1137 break;
1138 case FILE_OPEN_IF:
1139 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_OVERWRITE:
1142 ofun = SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OVERWRITE_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001148 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001149 ofun = SMBOPEN_OAPPEND; /* regular open */
1150 }
1151 return ofun;
1152}
1153
Jeff Layton35fc37d2008-05-14 10:22:03 -07001154static int
1155access_flags_to_smbopen_mode(const int access_flags)
1156{
1157 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1158
1159 if (masked_flags == GENERIC_READ)
1160 return SMBOPEN_READ;
1161 else if (masked_flags == GENERIC_WRITE)
1162 return SMBOPEN_WRITE;
1163
1164 /* just go for read/write */
1165 return SMBOPEN_READWRITE;
1166}
1167
Steve Frencha9d02ad2005-08-24 23:06:05 -07001168int
1169SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1170 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001171 const int access_flags, const int create_options, __u16 *netfid,
1172 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 const struct nls_table *nls_codepage, int remap)
1174{
1175 int rc = -EACCES;
1176 OPENX_REQ *pSMB = NULL;
1177 OPENX_RSP *pSMBr = NULL;
1178 int bytes_returned;
1179 int name_len;
1180 __u16 count;
1181
1182OldOpenRetry:
1183 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1184 (void **) &pSMBr);
1185 if (rc)
1186 return rc;
1187
1188 pSMB->AndXCommand = 0xFF; /* none */
1189
1190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1191 count = 1; /* account for one byte pad to word boundary */
1192 name_len =
1193 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1194 fileName, PATH_MAX, nls_codepage, remap);
1195 name_len++; /* trailing null */
1196 name_len *= 2;
1197 } else { /* BB improve check for buffer overruns BB */
1198 count = 0; /* no pad */
1199 name_len = strnlen(fileName, PATH_MAX);
1200 name_len++; /* trailing null */
1201 strncpy(pSMB->fileName, fileName, name_len);
1202 }
1203 if (*pOplock & REQ_OPLOCK)
1204 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001205 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001207
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001209 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1211 /* set file as system file if special file such
1212 as fifo and server expecting SFU style and
1213 no Unix extensions */
1214
Steve French790fe572007-07-07 19:25:05 +00001215 if (create_options & CREATE_OPTION_SPECIAL)
1216 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001217 else /* BB FIXME BB */
1218 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219
Jeff Layton67750fb2008-05-09 22:28:02 +00001220 if (create_options & CREATE_OPTION_READONLY)
1221 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222
1223 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001224/* pSMB->CreateOptions = cpu_to_le32(create_options &
1225 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001227
1228 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001229 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 count += name_len;
1231 pSMB->hdr.smb_buf_length += count;
1232
1233 pSMB->ByteCount = cpu_to_le16(count);
1234 /* long_op set to 1 to allow for oplock break timeouts */
1235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001236 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 cifs_stats_inc(&tcon->num_opens);
1238 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001239 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 } else {
1241 /* BB verify if wct == 15 */
1242
Steve French582d21e2008-05-13 04:54:12 +00001243/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244
1245 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1246 /* Let caller know file was created so we can set the mode. */
1247 /* Do we care about the CreateAction in any other cases? */
1248 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001249/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 *pOplock |= CIFS_CREATE_ACTION; */
1251 /* BB FIXME END */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255 pfile_info->LastAccessTime = 0; /* BB fixme */
1256 pfile_info->LastWriteTime = 0; /* BB fixme */
1257 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001258 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001259 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001261 pfile_info->AllocationSize =
1262 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001265 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 }
1267 }
1268
1269 cifs_buf_release(pSMB);
1270 if (rc == -EAGAIN)
1271 goto OldOpenRetry;
1272 return rc;
1273}
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275int
1276CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1277 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001278 const int access_flags, const int create_options, __u16 *netfid,
1279 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001280 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281{
1282 int rc = -EACCES;
1283 OPEN_REQ *pSMB = NULL;
1284 OPEN_RSP *pSMBr = NULL;
1285 int bytes_returned;
1286 int name_len;
1287 __u16 count;
1288
1289openRetry:
1290 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1291 (void **) &pSMBr);
1292 if (rc)
1293 return rc;
1294
1295 pSMB->AndXCommand = 0xFF; /* none */
1296
1297 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1298 count = 1; /* account for one byte pad to word boundary */
1299 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001300 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001301 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 name_len++; /* trailing null */
1303 name_len *= 2;
1304 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001305 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 count = 0; /* no pad */
1307 name_len = strnlen(fileName, PATH_MAX);
1308 name_len++; /* trailing null */
1309 pSMB->NameLength = cpu_to_le16(name_len);
1310 strncpy(pSMB->fileName, fileName, name_len);
1311 }
1312 if (*pOplock & REQ_OPLOCK)
1313 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001314 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1317 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001318 /* set file as system file if special file such
1319 as fifo and server expecting SFU style and
1320 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001321 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001322 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1323 else
1324 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 /* XP does not handle ATTR_POSIX_SEMANTICS */
1327 /* but it helps speed up case sensitive checks for other
1328 servers such as Samba */
1329 if (tcon->ses->capabilities & CAP_UNIX)
1330 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1331
Jeff Layton67750fb2008-05-09 22:28:02 +00001332 if (create_options & CREATE_OPTION_READONLY)
1333 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1336 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001337 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001338 /* BB Expirement with various impersonation levels and verify */
1339 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->SecurityFlags =
1341 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1342
1343 count += name_len;
1344 pSMB->hdr.smb_buf_length += count;
1345
1346 pSMB->ByteCount = cpu_to_le16(count);
1347 /* long_op set to 1 to allow for oplock break timeouts */
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001349 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001350 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001352 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 } else {
Steve French09d1db52005-04-28 22:41:08 -07001354 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1356 /* Let caller know file was created so we can set the mode. */
1357 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001358 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001359 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001360 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001361 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1362 36 /* CreationTime to Attributes */);
1363 /* the file_info buf is endian converted by caller */
1364 pfile_info->AllocationSize = pSMBr->AllocationSize;
1365 pfile_info->EndOfFile = pSMBr->EndOfFile;
1366 pfile_info->NumberOfLinks = cpu_to_le32(1);
1367 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 cifs_buf_release(pSMB);
1372 if (rc == -EAGAIN)
1373 goto openRetry;
1374 return rc;
1375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377int
Steve French50c2f752007-07-13 00:33:32 +00001378CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1379 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1380 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
1382 int rc = -EACCES;
1383 READ_REQ *pSMB = NULL;
1384 READ_RSP *pSMBr = NULL;
1385 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001386 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001387 int resp_buf_type = 0;
1388 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Joe Perchesb6b38f72010-04-21 03:50:45 +00001390 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001391 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001392 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001393 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001394 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001395 if ((lseek >> 32) > 0) {
1396 /* can not handle this big offset for old */
1397 return -EIO;
1398 }
1399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
1401 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001402 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 if (rc)
1404 return rc;
1405
1406 /* tcon and ses pointer are checked in smb_init */
1407 if (tcon->ses->server == NULL)
1408 return -ECONNABORTED;
1409
Steve Frenchec637e32005-12-12 20:53:18 -08001410 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 pSMB->Fid = netfid;
1412 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001413 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 pSMB->Remaining = 0;
1417 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1418 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001419 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001420 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1421 else {
1422 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001423 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001424 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001425 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001426 }
Steve Frenchec637e32005-12-12 20:53:18 -08001427
1428 iov[0].iov_base = (char *)pSMB;
1429 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001430 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001431 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001432 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001433 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001435 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 } else {
1437 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1438 data_length = data_length << 16;
1439 data_length += le16_to_cpu(pSMBr->DataLength);
1440 *nbytes = data_length;
1441
1442 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001443 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001445 cFYI(1, "bad length %d for count %d",
1446 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 rc = -EIO;
1448 *nbytes = 0;
1449 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001450 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001451 le16_to_cpu(pSMBr->DataOffset);
1452/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001453 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001454 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001455 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001456 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001457 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 }
1459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
Steve French4b8f9302006-02-26 16:41:18 +00001461/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001462 if (*buf) {
1463 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001464 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001465 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001466 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001467 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001468 /* return buffer to caller to free */
1469 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001470 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001471 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001472 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001473 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001474 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001475
1476 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 since file handle passed in no longer valid */
1478 return rc;
1479}
1480
Steve Frenchec637e32005-12-12 20:53:18 -08001481
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482int
1483CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1484 const int netfid, const unsigned int count,
1485 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001486 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487{
1488 int rc = -EACCES;
1489 WRITE_REQ *pSMB = NULL;
1490 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001491 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 __u32 bytes_sent;
1493 __u16 byte_count;
1494
Steve Frencha24e2d72010-04-03 17:20:21 +00001495 *nbytes = 0;
1496
Joe Perchesb6b38f72010-04-21 03:50:45 +00001497 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001498 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001499 return -ECONNABORTED;
1500
Steve French790fe572007-07-07 19:25:05 +00001501 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001502 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001503 else {
Steve French1c955182005-08-30 20:58:07 -07001504 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001505 if ((offset >> 32) > 0) {
1506 /* can not handle big offset for old srv */
1507 return -EIO;
1508 }
1509 }
Steve French1c955182005-08-30 20:58:07 -07001510
1511 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 (void **) &pSMBr);
1513 if (rc)
1514 return rc;
1515 /* tcon and ses pointer are checked in smb_init */
1516 if (tcon->ses->server == NULL)
1517 return -ECONNABORTED;
1518
1519 pSMB->AndXCommand = 0xFF; /* none */
1520 pSMB->Fid = netfid;
1521 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001522 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001523 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001524
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 pSMB->Reserved = 0xFFFFFFFF;
1526 pSMB->WriteMode = 0;
1527 pSMB->Remaining = 0;
1528
Steve French50c2f752007-07-13 00:33:32 +00001529 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 can send more if LARGE_WRITE_X capability returned by the server and if
1531 our buffer is big enough or if we convert to iovecs on socket writes
1532 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001533 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1535 } else {
1536 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1537 & ~0xFF;
1538 }
1539
1540 if (bytes_sent > count)
1541 bytes_sent = count;
1542 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001543 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001544 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001545 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001546 else if (ubuf) {
1547 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 cifs_buf_release(pSMB);
1549 return -EFAULT;
1550 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001551 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 /* No buffer */
1553 cifs_buf_release(pSMB);
1554 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001555 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001556 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001557 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001558 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001559 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001560
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1562 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001563 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001564
Steve French790fe572007-07-07 19:25:05 +00001565 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001566 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001567 else { /* old style write has byte count 4 bytes earlier
1568 so 4 bytes pad */
1569 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001570 (struct smb_com_writex_req *)pSMB;
1571 pSMBW->ByteCount = cpu_to_le16(byte_count);
1572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
1574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1575 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001576 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001578 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 } else {
1580 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1581 *nbytes = (*nbytes) << 16;
1582 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301583
1584 /*
1585 * Mask off high 16 bits when bytes written as returned by the
1586 * server is greater than bytes requested by the client. Some
1587 * OS/2 servers are known to set incorrect CountHigh values.
1588 */
1589 if (*nbytes > count)
1590 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 }
1592
1593 cifs_buf_release(pSMB);
1594
Steve French50c2f752007-07-13 00:33:32 +00001595 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 since file handle passed in no longer valid */
1597
1598 return rc;
1599}
1600
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001601int
1602CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001604 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1605 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606{
1607 int rc = -EACCES;
1608 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001609 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001610 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001611 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001613 *nbytes = 0;
1614
Joe Perchesb6b38f72010-04-21 03:50:45 +00001615 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001616
Steve French4c3130e2008-12-09 00:28:16 +00001617 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001618 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001619 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001620 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001621 if ((offset >> 32) > 0) {
1622 /* can not handle big offset for old srv */
1623 return -EIO;
1624 }
1625 }
Steve French8cc64c62005-10-03 13:49:43 -07001626 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 if (rc)
1628 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 /* tcon and ses pointer are checked in smb_init */
1630 if (tcon->ses->server == NULL)
1631 return -ECONNABORTED;
1632
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001633 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 pSMB->Fid = netfid;
1635 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001636 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001637 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 pSMB->Reserved = 0xFFFFFFFF;
1639 pSMB->WriteMode = 0;
1640 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001641
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001643 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644
Steve French3e844692005-10-03 13:37:24 -07001645 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1646 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001647 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001648 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001649 pSMB->hdr.smb_buf_length += count+1;
1650 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001651 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1652 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001653 pSMB->ByteCount = cpu_to_le16(count + 1);
1654 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001655 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001656 (struct smb_com_writex_req *)pSMB;
1657 pSMBW->ByteCount = cpu_to_le16(count + 5);
1658 }
Steve French3e844692005-10-03 13:37:24 -07001659 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001660 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001661 iov[0].iov_len = smb_hdr_len + 4;
1662 else /* wct == 12 pad bigger by four bytes */
1663 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001664
Steve French3e844692005-10-03 13:37:24 -07001665
Steve Frenchec637e32005-12-12 20:53:18 -08001666 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001667 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001668 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001670 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001671 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001672 /* presumably this can not happen, but best to be safe */
1673 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001674 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001675 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001676 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1677 *nbytes = (*nbytes) << 16;
1678 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301679
1680 /*
1681 * Mask off high 16 bits when bytes written as returned by the
1682 * server is greater than bytes requested by the client. OS/2
1683 * servers are known to set incorrect CountHigh values.
1684 */
1685 if (*nbytes > count)
1686 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688
Steve French4b8f9302006-02-26 16:41:18 +00001689/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001690 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001691 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001692 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001693 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694
Steve French50c2f752007-07-13 00:33:32 +00001695 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 since file handle passed in no longer valid */
1697
1698 return rc;
1699}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001700
1701
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702int
1703CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1704 const __u16 smb_file_id, const __u64 len,
1705 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001706 const __u32 numLock, const __u8 lockType,
1707 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708{
1709 int rc = 0;
1710 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001711/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 int bytes_returned;
1713 int timeout = 0;
1714 __u16 count;
1715
Joe Perchesb6b38f72010-04-21 03:50:45 +00001716 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001717 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1718
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 if (rc)
1720 return rc;
1721
Steve French790fe572007-07-07 19:25:05 +00001722 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001723 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001725 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001726 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1728 } else {
1729 pSMB->Timeout = 0;
1730 }
1731
1732 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1733 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1734 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001735 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 pSMB->AndXCommand = 0xFF; /* none */
1737 pSMB->Fid = smb_file_id; /* netfid stays le */
1738
Steve French790fe572007-07-07 19:25:05 +00001739 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1741 /* BB where to store pid high? */
1742 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1743 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1744 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1745 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1746 count = sizeof(LOCKING_ANDX_RANGE);
1747 } else {
1748 /* oplock break */
1749 count = 0;
1750 }
1751 pSMB->hdr.smb_buf_length += count;
1752 pSMB->ByteCount = cpu_to_le16(count);
1753
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001754 if (waitFlag) {
1755 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001756 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001757 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001758 } else {
Steve French133672e2007-11-13 22:41:37 +00001759 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1760 timeout);
1761 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001762 }
Steve Frencha4544342005-08-24 13:59:35 -07001763 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001764 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001765 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766
Steve French50c2f752007-07-13 00:33:32 +00001767 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 since file handle passed in no longer valid */
1769 return rc;
1770}
1771
1772int
Steve French08547b02006-02-28 22:39:25 +00001773CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1774 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001775 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001776 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001777{
1778 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1779 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001780 struct cifs_posix_lock *parm_data;
1781 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001782 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001783 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001784 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001785 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001786 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001787
Joe Perchesb6b38f72010-04-21 03:50:45 +00001788 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001789
Steve French790fe572007-07-07 19:25:05 +00001790 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001791 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001792
Steve French08547b02006-02-28 22:39:25 +00001793 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1794
1795 if (rc)
1796 return rc;
1797
1798 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1799
Steve French50c2f752007-07-13 00:33:32 +00001800 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001801 pSMB->MaxSetupCount = 0;
1802 pSMB->Reserved = 0;
1803 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001804 pSMB->Reserved2 = 0;
1805 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1806 offset = param_offset + params;
1807
Steve French08547b02006-02-28 22:39:25 +00001808 count = sizeof(struct cifs_posix_lock);
1809 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001810 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001811 pSMB->SetupCount = 1;
1812 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001813 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001814 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1815 else
1816 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1817 byte_count = 3 /* pad */ + params + count;
1818 pSMB->DataCount = cpu_to_le16(count);
1819 pSMB->ParameterCount = cpu_to_le16(params);
1820 pSMB->TotalDataCount = pSMB->DataCount;
1821 pSMB->TotalParameterCount = pSMB->ParameterCount;
1822 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001823 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001824 (((char *) &pSMB->hdr.Protocol) + offset);
1825
1826 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001827 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001828 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001829 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001830 pSMB->Timeout = cpu_to_le32(-1);
1831 } else
1832 pSMB->Timeout = 0;
1833
Steve French08547b02006-02-28 22:39:25 +00001834 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001835 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001836 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001837
1838 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001839 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001840 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1841 pSMB->Reserved4 = 0;
1842 pSMB->hdr.smb_buf_length += byte_count;
1843 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001844 if (waitFlag) {
1845 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1846 (struct smb_hdr *) pSMBr, &bytes_returned);
1847 } else {
Steve French133672e2007-11-13 22:41:37 +00001848 iov[0].iov_base = (char *)pSMB;
1849 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1850 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1851 &resp_buf_type, timeout);
1852 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1853 not try to free it twice below on exit */
1854 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001855 }
1856
Steve French08547b02006-02-28 22:39:25 +00001857 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001858 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001859 } else if (get_flag) {
1860 /* lock structure can be returned on get */
1861 __u16 data_offset;
1862 __u16 data_count;
1863 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001864
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001865 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1866 rc = -EIO; /* bad smb */
1867 goto plk_err_exit;
1868 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001869 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1870 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001871 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001872 rc = -EIO;
1873 goto plk_err_exit;
1874 }
1875 parm_data = (struct cifs_posix_lock *)
1876 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001877 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001878 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001879 else {
1880 if (parm_data->lock_type ==
1881 __constant_cpu_to_le16(CIFS_RDLCK))
1882 pLockData->fl_type = F_RDLCK;
1883 else if (parm_data->lock_type ==
1884 __constant_cpu_to_le16(CIFS_WRLCK))
1885 pLockData->fl_type = F_WRLCK;
1886
Steve French5443d132011-03-13 05:08:25 +00001887 pLockData->fl_start = le64_to_cpu(parm_data->start);
1888 pLockData->fl_end = pLockData->fl_start +
1889 le64_to_cpu(parm_data->length) - 1;
1890 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001891 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001892 }
Steve French50c2f752007-07-13 00:33:32 +00001893
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001894plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001895 if (pSMB)
1896 cifs_small_buf_release(pSMB);
1897
Steve French133672e2007-11-13 22:41:37 +00001898 if (resp_buf_type == CIFS_SMALL_BUFFER)
1899 cifs_small_buf_release(iov[0].iov_base);
1900 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1901 cifs_buf_release(iov[0].iov_base);
1902
Steve French08547b02006-02-28 22:39:25 +00001903 /* Note: On -EAGAIN error only caller can retry on handle based calls
1904 since file handle passed in no longer valid */
1905
1906 return rc;
1907}
1908
1909
1910int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1912{
1913 int rc = 0;
1914 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001915 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916
1917/* do not retry on dead session on close */
1918 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001919 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 return 0;
1921 if (rc)
1922 return rc;
1923
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001925 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001927 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001928 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001930 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001932 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 }
1934 }
1935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001937 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 rc = 0;
1939
1940 return rc;
1941}
1942
1943int
Steve Frenchb298f222009-02-21 21:17:43 +00001944CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1945{
1946 int rc = 0;
1947 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001948 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001949
1950 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1951 if (rc)
1952 return rc;
1953
1954 pSMB->FileID = (__u16) smb_file_id;
1955 pSMB->ByteCount = 0;
1956 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1957 cifs_stats_inc(&tcon->num_flushes);
1958 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001959 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001960
1961 return rc;
1962}
1963
1964int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1966 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001967 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968{
1969 int rc = 0;
1970 RENAME_REQ *pSMB = NULL;
1971 RENAME_RSP *pSMBr = NULL;
1972 int bytes_returned;
1973 int name_len, name_len2;
1974 __u16 count;
1975
Joe Perchesb6b38f72010-04-21 03:50:45 +00001976 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977renameRetry:
1978 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1979 (void **) &pSMBr);
1980 if (rc)
1981 return rc;
1982
1983 pSMB->BufferFormat = 0x04;
1984 pSMB->SearchAttributes =
1985 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1986 ATTR_DIRECTORY);
1987
1988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1989 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001990 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001991 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 name_len++; /* trailing null */
1993 name_len *= 2;
1994 pSMB->OldFileName[name_len] = 0x04; /* pad */
1995 /* protocol requires ASCII signature byte on Unicode string */
1996 pSMB->OldFileName[name_len + 1] = 0x00;
1997 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001998 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001999 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2001 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002002 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 name_len = strnlen(fromName, PATH_MAX);
2004 name_len++; /* trailing null */
2005 strncpy(pSMB->OldFileName, fromName, name_len);
2006 name_len2 = strnlen(toName, PATH_MAX);
2007 name_len2++; /* trailing null */
2008 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2009 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2010 name_len2++; /* trailing null */
2011 name_len2++; /* signature byte */
2012 }
2013
2014 count = 1 /* 1st signature byte */ + name_len + name_len2;
2015 pSMB->hdr.smb_buf_length += count;
2016 pSMB->ByteCount = cpu_to_le16(count);
2017
2018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002020 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002021 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002022 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 cifs_buf_release(pSMB);
2025
2026 if (rc == -EAGAIN)
2027 goto renameRetry;
2028
2029 return rc;
2030}
2031
Steve French50c2f752007-07-13 00:33:32 +00002032int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002033 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002034 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035{
2036 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2037 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002038 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 char *data_offset;
2040 char dummy_string[30];
2041 int rc = 0;
2042 int bytes_returned = 0;
2043 int len_of_str;
2044 __u16 params, param_offset, offset, count, byte_count;
2045
Joe Perchesb6b38f72010-04-21 03:50:45 +00002046 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2048 (void **) &pSMBr);
2049 if (rc)
2050 return rc;
2051
2052 params = 6;
2053 pSMB->MaxSetupCount = 0;
2054 pSMB->Reserved = 0;
2055 pSMB->Flags = 0;
2056 pSMB->Timeout = 0;
2057 pSMB->Reserved2 = 0;
2058 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2059 offset = param_offset + params;
2060
2061 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2062 rename_info = (struct set_file_rename *) data_offset;
2063 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002064 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 pSMB->SetupCount = 1;
2066 pSMB->Reserved3 = 0;
2067 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2068 byte_count = 3 /* pad */ + params;
2069 pSMB->ParameterCount = cpu_to_le16(params);
2070 pSMB->TotalParameterCount = pSMB->ParameterCount;
2071 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2072 pSMB->DataOffset = cpu_to_le16(offset);
2073 /* construct random name ".cifs_tmp<inodenum><mid>" */
2074 rename_info->overwrite = cpu_to_le32(1);
2075 rename_info->root_fid = 0;
2076 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002077 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002078 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2079 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002080 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002082 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002083 target_name, PATH_MAX, nls_codepage,
2084 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 }
2086 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002087 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 byte_count += count;
2089 pSMB->DataCount = cpu_to_le16(count);
2090 pSMB->TotalDataCount = pSMB->DataCount;
2091 pSMB->Fid = netfid;
2092 pSMB->InformationLevel =
2093 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2094 pSMB->Reserved4 = 0;
2095 pSMB->hdr.smb_buf_length += byte_count;
2096 pSMB->ByteCount = cpu_to_le16(byte_count);
2097 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002099 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002100 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002101 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002102
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 cifs_buf_release(pSMB);
2104
2105 /* Note: On -EAGAIN error only caller can retry on handle based calls
2106 since file handle passed in no longer valid */
2107
2108 return rc;
2109}
2110
2111int
Steve French50c2f752007-07-13 00:33:32 +00002112CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2113 const __u16 target_tid, const char *toName, const int flags,
2114 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115{
2116 int rc = 0;
2117 COPY_REQ *pSMB = NULL;
2118 COPY_RSP *pSMBr = NULL;
2119 int bytes_returned;
2120 int name_len, name_len2;
2121 __u16 count;
2122
Joe Perchesb6b38f72010-04-21 03:50:45 +00002123 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124copyRetry:
2125 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2126 (void **) &pSMBr);
2127 if (rc)
2128 return rc;
2129
2130 pSMB->BufferFormat = 0x04;
2131 pSMB->Tid2 = target_tid;
2132
2133 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2134
2135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002136 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002137 fromName, PATH_MAX, nls_codepage,
2138 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 name_len++; /* trailing null */
2140 name_len *= 2;
2141 pSMB->OldFileName[name_len] = 0x04; /* pad */
2142 /* protocol requires ASCII signature byte on Unicode string */
2143 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002144 name_len2 =
2145 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002146 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2148 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002149 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 name_len = strnlen(fromName, PATH_MAX);
2151 name_len++; /* trailing null */
2152 strncpy(pSMB->OldFileName, fromName, name_len);
2153 name_len2 = strnlen(toName, PATH_MAX);
2154 name_len2++; /* trailing null */
2155 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2156 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2157 name_len2++; /* trailing null */
2158 name_len2++; /* signature byte */
2159 }
2160
2161 count = 1 /* 1st signature byte */ + name_len + name_len2;
2162 pSMB->hdr.smb_buf_length += count;
2163 pSMB->ByteCount = cpu_to_le16(count);
2164
2165 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2166 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2167 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002168 cFYI(1, "Send error in copy = %d with %d files copied",
2169 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170 }
Steve French0d817bc2008-05-22 02:02:03 +00002171 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
2173 if (rc == -EAGAIN)
2174 goto copyRetry;
2175
2176 return rc;
2177}
2178
2179int
2180CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2181 const char *fromName, const char *toName,
2182 const struct nls_table *nls_codepage)
2183{
2184 TRANSACTION2_SPI_REQ *pSMB = NULL;
2185 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2186 char *data_offset;
2187 int name_len;
2188 int name_len_target;
2189 int rc = 0;
2190 int bytes_returned = 0;
2191 __u16 params, param_offset, offset, byte_count;
2192
Joe Perchesb6b38f72010-04-21 03:50:45 +00002193 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194createSymLinkRetry:
2195 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2196 (void **) &pSMBr);
2197 if (rc)
2198 return rc;
2199
2200 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2201 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002202 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 /* find define for this maxpathcomponent */
2204 , nls_codepage);
2205 name_len++; /* trailing null */
2206 name_len *= 2;
2207
Steve French50c2f752007-07-13 00:33:32 +00002208 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 name_len = strnlen(fromName, PATH_MAX);
2210 name_len++; /* trailing null */
2211 strncpy(pSMB->FileName, fromName, name_len);
2212 }
2213 params = 6 + name_len;
2214 pSMB->MaxSetupCount = 0;
2215 pSMB->Reserved = 0;
2216 pSMB->Flags = 0;
2217 pSMB->Timeout = 0;
2218 pSMB->Reserved2 = 0;
2219 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002220 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 offset = param_offset + params;
2222
2223 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2225 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002226 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 /* find define for this maxpathcomponent */
2228 , nls_codepage);
2229 name_len_target++; /* trailing null */
2230 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002231 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232 name_len_target = strnlen(toName, PATH_MAX);
2233 name_len_target++; /* trailing null */
2234 strncpy(data_offset, toName, name_len_target);
2235 }
2236
2237 pSMB->MaxParameterCount = cpu_to_le16(2);
2238 /* BB find exact max on data count below from sess */
2239 pSMB->MaxDataCount = cpu_to_le16(1000);
2240 pSMB->SetupCount = 1;
2241 pSMB->Reserved3 = 0;
2242 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2243 byte_count = 3 /* pad */ + params + name_len_target;
2244 pSMB->DataCount = cpu_to_le16(name_len_target);
2245 pSMB->ParameterCount = cpu_to_le16(params);
2246 pSMB->TotalDataCount = pSMB->DataCount;
2247 pSMB->TotalParameterCount = pSMB->ParameterCount;
2248 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2249 pSMB->DataOffset = cpu_to_le16(offset);
2250 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2251 pSMB->Reserved4 = 0;
2252 pSMB->hdr.smb_buf_length += byte_count;
2253 pSMB->ByteCount = cpu_to_le16(byte_count);
2254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002256 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002257 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002258 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259
Steve French0d817bc2008-05-22 02:02:03 +00002260 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261
2262 if (rc == -EAGAIN)
2263 goto createSymLinkRetry;
2264
2265 return rc;
2266}
2267
2268int
2269CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2270 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002271 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272{
2273 TRANSACTION2_SPI_REQ *pSMB = NULL;
2274 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2275 char *data_offset;
2276 int name_len;
2277 int name_len_target;
2278 int rc = 0;
2279 int bytes_returned = 0;
2280 __u16 params, param_offset, offset, byte_count;
2281
Joe Perchesb6b38f72010-04-21 03:50:45 +00002282 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283createHardLinkRetry:
2284 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2285 (void **) &pSMBr);
2286 if (rc)
2287 return rc;
2288
2289 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002290 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002291 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 name_len++; /* trailing null */
2293 name_len *= 2;
2294
Steve French50c2f752007-07-13 00:33:32 +00002295 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 name_len = strnlen(toName, PATH_MAX);
2297 name_len++; /* trailing null */
2298 strncpy(pSMB->FileName, toName, name_len);
2299 }
2300 params = 6 + name_len;
2301 pSMB->MaxSetupCount = 0;
2302 pSMB->Reserved = 0;
2303 pSMB->Flags = 0;
2304 pSMB->Timeout = 0;
2305 pSMB->Reserved2 = 0;
2306 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002307 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 offset = param_offset + params;
2309
2310 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2311 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2312 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002313 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002314 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315 name_len_target++; /* trailing null */
2316 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002317 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318 name_len_target = strnlen(fromName, PATH_MAX);
2319 name_len_target++; /* trailing null */
2320 strncpy(data_offset, fromName, name_len_target);
2321 }
2322
2323 pSMB->MaxParameterCount = cpu_to_le16(2);
2324 /* BB find exact max on data count below from sess*/
2325 pSMB->MaxDataCount = cpu_to_le16(1000);
2326 pSMB->SetupCount = 1;
2327 pSMB->Reserved3 = 0;
2328 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2329 byte_count = 3 /* pad */ + params + name_len_target;
2330 pSMB->ParameterCount = cpu_to_le16(params);
2331 pSMB->TotalParameterCount = pSMB->ParameterCount;
2332 pSMB->DataCount = cpu_to_le16(name_len_target);
2333 pSMB->TotalDataCount = pSMB->DataCount;
2334 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2335 pSMB->DataOffset = cpu_to_le16(offset);
2336 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2337 pSMB->Reserved4 = 0;
2338 pSMB->hdr.smb_buf_length += byte_count;
2339 pSMB->ByteCount = cpu_to_le16(byte_count);
2340 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2341 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002342 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002343 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002344 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
2346 cifs_buf_release(pSMB);
2347 if (rc == -EAGAIN)
2348 goto createHardLinkRetry;
2349
2350 return rc;
2351}
2352
2353int
2354CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2355 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002356 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357{
2358 int rc = 0;
2359 NT_RENAME_REQ *pSMB = NULL;
2360 RENAME_RSP *pSMBr = NULL;
2361 int bytes_returned;
2362 int name_len, name_len2;
2363 __u16 count;
2364
Joe Perchesb6b38f72010-04-21 03:50:45 +00002365 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366winCreateHardLinkRetry:
2367
2368 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2369 (void **) &pSMBr);
2370 if (rc)
2371 return rc;
2372
2373 pSMB->SearchAttributes =
2374 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2375 ATTR_DIRECTORY);
2376 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2377 pSMB->ClusterCount = 0;
2378
2379 pSMB->BufferFormat = 0x04;
2380
2381 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2382 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002383 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002384 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 name_len++; /* trailing null */
2386 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002387
2388 /* protocol specifies ASCII buffer format (0x04) for unicode */
2389 pSMB->OldFileName[name_len] = 0x04;
2390 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002392 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002393 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2395 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002396 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 name_len = strnlen(fromName, PATH_MAX);
2398 name_len++; /* trailing null */
2399 strncpy(pSMB->OldFileName, fromName, name_len);
2400 name_len2 = strnlen(toName, PATH_MAX);
2401 name_len2++; /* trailing null */
2402 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2403 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2404 name_len2++; /* trailing null */
2405 name_len2++; /* signature byte */
2406 }
2407
2408 count = 1 /* string type byte */ + name_len + name_len2;
2409 pSMB->hdr.smb_buf_length += count;
2410 pSMB->ByteCount = cpu_to_le16(count);
2411
2412 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2413 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002414 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002415 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002416 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002417
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 cifs_buf_release(pSMB);
2419 if (rc == -EAGAIN)
2420 goto winCreateHardLinkRetry;
2421
2422 return rc;
2423}
2424
2425int
2426CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002427 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002428 const struct nls_table *nls_codepage)
2429{
2430/* SMB_QUERY_FILE_UNIX_LINK */
2431 TRANSACTION2_QPI_REQ *pSMB = NULL;
2432 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2433 int rc = 0;
2434 int bytes_returned;
2435 int name_len;
2436 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002437 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
Joe Perchesb6b38f72010-04-21 03:50:45 +00002439 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
2441querySymLinkRetry:
2442 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2443 (void **) &pSMBr);
2444 if (rc)
2445 return rc;
2446
2447 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2448 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002449 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2450 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 name_len++; /* trailing null */
2452 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002453 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 name_len = strnlen(searchName, PATH_MAX);
2455 name_len++; /* trailing null */
2456 strncpy(pSMB->FileName, searchName, name_len);
2457 }
2458
2459 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2460 pSMB->TotalDataCount = 0;
2461 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002462 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 pSMB->MaxSetupCount = 0;
2464 pSMB->Reserved = 0;
2465 pSMB->Flags = 0;
2466 pSMB->Timeout = 0;
2467 pSMB->Reserved2 = 0;
2468 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002469 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 pSMB->DataCount = 0;
2471 pSMB->DataOffset = 0;
2472 pSMB->SetupCount = 1;
2473 pSMB->Reserved3 = 0;
2474 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2475 byte_count = params + 1 /* pad */ ;
2476 pSMB->TotalParameterCount = cpu_to_le16(params);
2477 pSMB->ParameterCount = pSMB->TotalParameterCount;
2478 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2479 pSMB->Reserved4 = 0;
2480 pSMB->hdr.smb_buf_length += byte_count;
2481 pSMB->ByteCount = cpu_to_le16(byte_count);
2482
2483 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2484 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2485 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002486 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 } else {
2488 /* decode response */
2489
2490 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002492 if (rc || (pSMBr->ByteCount < 2))
2493 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002495 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002496 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497
Jeff Layton460b9692009-04-30 07:17:56 -04002498 data_start = ((char *) &pSMBr->hdr.Protocol) +
2499 le16_to_cpu(pSMBr->t2.DataOffset);
2500
Steve French0e0d2cf2009-05-01 05:27:32 +00002501 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2502 is_unicode = true;
2503 else
2504 is_unicode = false;
2505
Steve French737b7582005-04-28 22:41:06 -07002506 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002507 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002508 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002509 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002510 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 }
2512 }
2513 cifs_buf_release(pSMB);
2514 if (rc == -EAGAIN)
2515 goto querySymLinkRetry;
2516 return rc;
2517}
2518
Steve Frenchc52a95542011-02-24 06:16:22 +00002519#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2520/*
2521 * Recent Windows versions now create symlinks more frequently
2522 * and they use the "reparse point" mechanism below. We can of course
2523 * do symlinks nicely to Samba and other servers which support the
2524 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2525 * "MF" symlinks optionally, but for recent Windows we really need to
2526 * reenable the code below and fix the cifs_symlink callers to handle this.
2527 * In the interim this code has been moved to its own config option so
2528 * it is not compiled in by default until callers fixed up and more tested.
2529 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530int
2531CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2532 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002533 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 const struct nls_table *nls_codepage)
2535{
2536 int rc = 0;
2537 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002538 struct smb_com_transaction_ioctl_req *pSMB;
2539 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
Joe Perchesb6b38f72010-04-21 03:50:45 +00002541 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2543 (void **) &pSMBr);
2544 if (rc)
2545 return rc;
2546
2547 pSMB->TotalParameterCount = 0 ;
2548 pSMB->TotalDataCount = 0;
2549 pSMB->MaxParameterCount = cpu_to_le32(2);
2550 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002551 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2552 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553 pSMB->MaxSetupCount = 4;
2554 pSMB->Reserved = 0;
2555 pSMB->ParameterOffset = 0;
2556 pSMB->DataCount = 0;
2557 pSMB->DataOffset = 0;
2558 pSMB->SetupCount = 4;
2559 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2560 pSMB->ParameterCount = pSMB->TotalParameterCount;
2561 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2562 pSMB->IsFsctl = 1; /* FSCTL */
2563 pSMB->IsRootFlag = 0;
2564 pSMB->Fid = fid; /* file handle always le */
2565 pSMB->ByteCount = 0;
2566
2567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2569 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002570 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 } else { /* decode response */
2572 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2573 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002574 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 /* BB also check enough total bytes returned */
2576 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002577 goto qreparse_out;
2578 }
2579 if (data_count && (data_count < 2048)) {
2580 char *end_of_smb = 2 /* sizeof byte count */ +
2581 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
Steve Frenchafe48c32009-05-02 05:25:46 +00002583 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002584 (struct reparse_data *)
2585 ((char *)&pSMBr->hdr.Protocol
2586 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002587 if ((char *)reparse_buf >= end_of_smb) {
2588 rc = -EIO;
2589 goto qreparse_out;
2590 }
2591 if ((reparse_buf->LinkNamesBuf +
2592 reparse_buf->TargetNameOffset +
2593 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002594 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002595 rc = -EIO;
2596 goto qreparse_out;
2597 }
Steve French50c2f752007-07-13 00:33:32 +00002598
Steve Frenchafe48c32009-05-02 05:25:46 +00002599 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2600 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002601 (reparse_buf->LinkNamesBuf +
2602 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002603 buflen,
2604 reparse_buf->TargetNameLen,
2605 nls_codepage, 0);
2606 } else { /* ASCII names */
2607 strncpy(symlinkinfo,
2608 reparse_buf->LinkNamesBuf +
2609 reparse_buf->TargetNameOffset,
2610 min_t(const int, buflen,
2611 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002613 } else {
2614 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002615 cFYI(1, "Invalid return data count on "
2616 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002618 symlinkinfo[buflen] = 0; /* just in case so the caller
2619 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002620 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 }
Steve French989c7e52009-05-02 05:32:20 +00002622
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002624 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 /* Note: On -EAGAIN error only caller can retry on handle based calls
2627 since file handle passed in no longer valid */
2628
2629 return rc;
2630}
Steve Frenchc52a95542011-02-24 06:16:22 +00002631#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
2633#ifdef CONFIG_CIFS_POSIX
2634
2635/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002636static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2637 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638{
2639 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002640 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2641 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2642 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002643 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 return;
2646}
2647
2648/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002649static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2650 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651{
2652 int size = 0;
2653 int i;
2654 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002655 struct cifs_posix_ace *pACE;
2656 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2657 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
2659 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2660 return -EOPNOTSUPP;
2661
Steve French790fe572007-07-07 19:25:05 +00002662 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 count = le16_to_cpu(cifs_acl->access_entry_count);
2664 pACE = &cifs_acl->ace_array[0];
2665 size = sizeof(struct cifs_posix_acl);
2666 size += sizeof(struct cifs_posix_ace) * count;
2667 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002668 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002669 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2670 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 return -EINVAL;
2672 }
Steve French790fe572007-07-07 19:25:05 +00002673 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 count = le16_to_cpu(cifs_acl->access_entry_count);
2675 size = sizeof(struct cifs_posix_acl);
2676 size += sizeof(struct cifs_posix_ace) * count;
2677/* skip past access ACEs to get to default ACEs */
2678 pACE = &cifs_acl->ace_array[count];
2679 count = le16_to_cpu(cifs_acl->default_entry_count);
2680 size += sizeof(struct cifs_posix_ace) * count;
2681 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002682 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 return -EINVAL;
2684 } else {
2685 /* illegal type */
2686 return -EINVAL;
2687 }
2688
2689 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002690 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002691 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002692 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 return -ERANGE;
2694 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002695 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002696 for (i = 0; i < count ; i++) {
2697 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2698 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 }
2700 }
2701 return size;
2702}
2703
Steve French50c2f752007-07-13 00:33:32 +00002704static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2705 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706{
2707 __u16 rc = 0; /* 0 = ACL converted ok */
2708
Steve Frenchff7feac2005-11-15 16:45:16 -08002709 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2710 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002712 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 /* Probably no need to le convert -1 on any arch but can not hurt */
2714 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002715 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002716 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002717 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return rc;
2719}
2720
2721/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002722static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2723 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724{
2725 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002726 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2727 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 int count;
2729 int i;
2730
Steve French790fe572007-07-07 19:25:05 +00002731 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 return 0;
2733
2734 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002735 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002736 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002737 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002738 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002739 cFYI(1, "unknown POSIX ACL version %d",
2740 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 return 0;
2742 }
2743 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002744 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002745 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002746 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002747 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002749 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 return 0;
2751 }
Steve French50c2f752007-07-13 00:33:32 +00002752 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2754 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002755 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 /* ACE not converted */
2757 break;
2758 }
2759 }
Steve French790fe572007-07-07 19:25:05 +00002760 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2762 rc += sizeof(struct cifs_posix_acl);
2763 /* BB add check to make sure ACL does not overflow SMB */
2764 }
2765 return rc;
2766}
2767
2768int
2769CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002770 const unsigned char *searchName,
2771 char *acl_inf, const int buflen, const int acl_type,
2772 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773{
2774/* SMB_QUERY_POSIX_ACL */
2775 TRANSACTION2_QPI_REQ *pSMB = NULL;
2776 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2777 int rc = 0;
2778 int bytes_returned;
2779 int name_len;
2780 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002781
Joe Perchesb6b38f72010-04-21 03:50:45 +00002782 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
2784queryAclRetry:
2785 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2786 (void **) &pSMBr);
2787 if (rc)
2788 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002789
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2791 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002792 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002793 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 name_len++; /* trailing null */
2795 name_len *= 2;
2796 pSMB->FileName[name_len] = 0;
2797 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002798 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 name_len = strnlen(searchName, PATH_MAX);
2800 name_len++; /* trailing null */
2801 strncpy(pSMB->FileName, searchName, name_len);
2802 }
2803
2804 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2805 pSMB->TotalDataCount = 0;
2806 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002807 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 pSMB->MaxDataCount = cpu_to_le16(4000);
2809 pSMB->MaxSetupCount = 0;
2810 pSMB->Reserved = 0;
2811 pSMB->Flags = 0;
2812 pSMB->Timeout = 0;
2813 pSMB->Reserved2 = 0;
2814 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002815 offsetof(struct smb_com_transaction2_qpi_req,
2816 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 pSMB->DataCount = 0;
2818 pSMB->DataOffset = 0;
2819 pSMB->SetupCount = 1;
2820 pSMB->Reserved3 = 0;
2821 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2822 byte_count = params + 1 /* pad */ ;
2823 pSMB->TotalParameterCount = cpu_to_le16(params);
2824 pSMB->ParameterCount = pSMB->TotalParameterCount;
2825 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2826 pSMB->Reserved4 = 0;
2827 pSMB->hdr.smb_buf_length += byte_count;
2828 pSMB->ByteCount = cpu_to_le16(byte_count);
2829
2830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002832 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002834 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 } else {
2836 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002837
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2839 if (rc || (pSMBr->ByteCount < 2))
2840 /* BB also check enough total bytes returned */
2841 rc = -EIO; /* bad smb */
2842 else {
2843 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2844 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2845 rc = cifs_copy_posix_acl(acl_inf,
2846 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002847 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 }
2849 }
2850 cifs_buf_release(pSMB);
2851 if (rc == -EAGAIN)
2852 goto queryAclRetry;
2853 return rc;
2854}
2855
2856int
2857CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002858 const unsigned char *fileName,
2859 const char *local_acl, const int buflen,
2860 const int acl_type,
2861 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862{
2863 struct smb_com_transaction2_spi_req *pSMB = NULL;
2864 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2865 char *parm_data;
2866 int name_len;
2867 int rc = 0;
2868 int bytes_returned = 0;
2869 __u16 params, byte_count, data_count, param_offset, offset;
2870
Joe Perchesb6b38f72010-04-21 03:50:45 +00002871 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872setAclRetry:
2873 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002874 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (rc)
2876 return rc;
2877 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2878 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002879 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002880 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 name_len++; /* trailing null */
2882 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002883 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 name_len = strnlen(fileName, PATH_MAX);
2885 name_len++; /* trailing null */
2886 strncpy(pSMB->FileName, fileName, name_len);
2887 }
2888 params = 6 + name_len;
2889 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002890 /* BB find max SMB size from sess */
2891 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 pSMB->MaxSetupCount = 0;
2893 pSMB->Reserved = 0;
2894 pSMB->Flags = 0;
2895 pSMB->Timeout = 0;
2896 pSMB->Reserved2 = 0;
2897 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002898 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 offset = param_offset + params;
2900 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2901 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2902
2903 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002904 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
Steve French790fe572007-07-07 19:25:05 +00002906 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 rc = -EOPNOTSUPP;
2908 goto setACLerrorExit;
2909 }
2910 pSMB->DataOffset = cpu_to_le16(offset);
2911 pSMB->SetupCount = 1;
2912 pSMB->Reserved3 = 0;
2913 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2914 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2915 byte_count = 3 /* pad */ + params + data_count;
2916 pSMB->DataCount = cpu_to_le16(data_count);
2917 pSMB->TotalDataCount = pSMB->DataCount;
2918 pSMB->ParameterCount = cpu_to_le16(params);
2919 pSMB->TotalParameterCount = pSMB->ParameterCount;
2920 pSMB->Reserved4 = 0;
2921 pSMB->hdr.smb_buf_length += byte_count;
2922 pSMB->ByteCount = cpu_to_le16(byte_count);
2923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002925 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002926 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
2928setACLerrorExit:
2929 cifs_buf_release(pSMB);
2930 if (rc == -EAGAIN)
2931 goto setAclRetry;
2932 return rc;
2933}
2934
Steve Frenchf654bac2005-04-28 22:41:04 -07002935/* BB fix tabs in this function FIXME BB */
2936int
2937CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002938 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002939{
Steve French50c2f752007-07-13 00:33:32 +00002940 int rc = 0;
2941 struct smb_t2_qfi_req *pSMB = NULL;
2942 struct smb_t2_qfi_rsp *pSMBr = NULL;
2943 int bytes_returned;
2944 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002945
Joe Perchesb6b38f72010-04-21 03:50:45 +00002946 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002947 if (tcon == NULL)
2948 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002949
2950GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002951 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2952 (void **) &pSMBr);
2953 if (rc)
2954 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002955
Steve Frenchad7a2922008-02-07 23:25:02 +00002956 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002957 pSMB->t2.TotalDataCount = 0;
2958 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2959 /* BB find exact max data count below from sess structure BB */
2960 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2961 pSMB->t2.MaxSetupCount = 0;
2962 pSMB->t2.Reserved = 0;
2963 pSMB->t2.Flags = 0;
2964 pSMB->t2.Timeout = 0;
2965 pSMB->t2.Reserved2 = 0;
2966 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2967 Fid) - 4);
2968 pSMB->t2.DataCount = 0;
2969 pSMB->t2.DataOffset = 0;
2970 pSMB->t2.SetupCount = 1;
2971 pSMB->t2.Reserved3 = 0;
2972 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2973 byte_count = params + 1 /* pad */ ;
2974 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2975 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2976 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2977 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002978 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002979 pSMB->hdr.smb_buf_length += byte_count;
2980 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002981
Steve French790fe572007-07-07 19:25:05 +00002982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2984 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002985 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00002986 } else {
2987 /* decode response */
2988 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2989 if (rc || (pSMBr->ByteCount < 2))
2990 /* BB also check enough total bytes returned */
2991 /* If rc should we check for EOPNOSUPP and
2992 disable the srvino flag? or in caller? */
2993 rc = -EIO; /* bad smb */
2994 else {
2995 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2996 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2997 struct file_chattr_info *pfinfo;
2998 /* BB Do we need a cast or hash here ? */
2999 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003000 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003001 rc = -EIO;
3002 goto GetExtAttrOut;
3003 }
3004 pfinfo = (struct file_chattr_info *)
3005 (data_offset + (char *) &pSMBr->hdr.Protocol);
3006 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003007 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003008 }
3009 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003010GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003011 cifs_buf_release(pSMB);
3012 if (rc == -EAGAIN)
3013 goto GetExtAttrRetry;
3014 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003015}
3016
Steve Frenchf654bac2005-04-28 22:41:04 -07003017#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018
Jeff Layton79df1ba2010-12-06 12:52:08 -05003019#ifdef CONFIG_CIFS_ACL
3020/*
3021 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3022 * all NT TRANSACTS that we init here have total parm and data under about 400
3023 * bytes (to fit in small cifs buffer size), which is the case so far, it
3024 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3025 * returned setup area) and MaxParameterCount (returned parms size) must be set
3026 * by caller
3027 */
3028static int
3029smb_init_nttransact(const __u16 sub_command, const int setup_count,
3030 const int parm_len, struct cifsTconInfo *tcon,
3031 void **ret_buf)
3032{
3033 int rc;
3034 __u32 temp_offset;
3035 struct smb_com_ntransact_req *pSMB;
3036
3037 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3038 (void **)&pSMB);
3039 if (rc)
3040 return rc;
3041 *ret_buf = (void *)pSMB;
3042 pSMB->Reserved = 0;
3043 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3044 pSMB->TotalDataCount = 0;
3045 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3046 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3047 pSMB->ParameterCount = pSMB->TotalParameterCount;
3048 pSMB->DataCount = pSMB->TotalDataCount;
3049 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3050 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3051 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3052 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3053 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3054 pSMB->SubCommand = cpu_to_le16(sub_command);
3055 return 0;
3056}
3057
3058static int
3059validate_ntransact(char *buf, char **ppparm, char **ppdata,
3060 __u32 *pparmlen, __u32 *pdatalen)
3061{
3062 char *end_of_smb;
3063 __u32 data_count, data_offset, parm_count, parm_offset;
3064 struct smb_com_ntransact_rsp *pSMBr;
3065
3066 *pdatalen = 0;
3067 *pparmlen = 0;
3068
3069 if (buf == NULL)
3070 return -EINVAL;
3071
3072 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3073
3074 /* ByteCount was converted from little endian in SendReceive */
3075 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
3076 (char *)&pSMBr->ByteCount;
3077
3078 data_offset = le32_to_cpu(pSMBr->DataOffset);
3079 data_count = le32_to_cpu(pSMBr->DataCount);
3080 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3081 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3082
3083 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3084 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3085
3086 /* should we also check that parm and data areas do not overlap? */
3087 if (*ppparm > end_of_smb) {
3088 cFYI(1, "parms start after end of smb");
3089 return -EINVAL;
3090 } else if (parm_count + *ppparm > end_of_smb) {
3091 cFYI(1, "parm end after end of smb");
3092 return -EINVAL;
3093 } else if (*ppdata > end_of_smb) {
3094 cFYI(1, "data starts after end of smb");
3095 return -EINVAL;
3096 } else if (data_count + *ppdata > end_of_smb) {
3097 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3098 *ppdata, data_count, (data_count + *ppdata),
3099 end_of_smb, pSMBr);
3100 return -EINVAL;
3101 } else if (parm_count + data_count > pSMBr->ByteCount) {
3102 cFYI(1, "parm count and data count larger than SMB");
3103 return -EINVAL;
3104 }
3105 *pdatalen = data_count;
3106 *pparmlen = parm_count;
3107 return 0;
3108}
3109
Steve French0a4b92c2006-01-12 15:44:21 -08003110/* Get Security Descriptor (by handle) from remote server for a file or dir */
3111int
3112CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003113 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003114{
3115 int rc = 0;
3116 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003117 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003118 struct kvec iov[1];
3119
Joe Perchesb6b38f72010-04-21 03:50:45 +00003120 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003121
Steve French630f3f0c2007-10-25 21:17:17 +00003122 *pbuflen = 0;
3123 *acl_inf = NULL;
3124
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003125 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003126 8 /* parm len */, tcon, (void **) &pSMB);
3127 if (rc)
3128 return rc;
3129
3130 pSMB->MaxParameterCount = cpu_to_le32(4);
3131 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3132 pSMB->MaxSetupCount = 0;
3133 pSMB->Fid = fid; /* file handle always le */
3134 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3135 CIFS_ACL_DACL);
3136 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3137 pSMB->hdr.smb_buf_length += 11;
3138 iov[0].iov_base = (char *)pSMB;
3139 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3140
Steve Frencha761ac52007-10-18 21:45:27 +00003141 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003142 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003143 cifs_stats_inc(&tcon->num_acl_get);
3144 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003145 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003146 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003147 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003148 __u32 parm_len;
3149 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003150 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003151 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003152
3153/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003154 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003155 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003156 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003157 goto qsec_out;
3158 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3159
Joe Perchesb6b38f72010-04-21 03:50:45 +00003160 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003161
3162 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3163 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003164 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003165 goto qsec_out;
3166 }
3167
3168/* BB check that data area is minimum length and as big as acl_len */
3169
Steve Frenchaf6f4612007-10-16 18:40:37 +00003170 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003171 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003172 cERROR(1, "acl length %d does not match %d",
3173 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003174 if (*pbuflen > acl_len)
3175 *pbuflen = acl_len;
3176 }
Steve French0a4b92c2006-01-12 15:44:21 -08003177
Steve French630f3f0c2007-10-25 21:17:17 +00003178 /* check if buffer is big enough for the acl
3179 header followed by the smallest SID */
3180 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3181 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003182 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003183 rc = -EINVAL;
3184 *pbuflen = 0;
3185 } else {
3186 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3187 if (*acl_inf == NULL) {
3188 *pbuflen = 0;
3189 rc = -ENOMEM;
3190 }
3191 memcpy(*acl_inf, pdata, *pbuflen);
3192 }
Steve French0a4b92c2006-01-12 15:44:21 -08003193 }
3194qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003195 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003196 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003197 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003198 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003199/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003200 return rc;
3201}
Steve French97837582007-12-31 07:47:21 +00003202
3203int
3204CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3205 struct cifs_ntsd *pntsd, __u32 acllen)
3206{
3207 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3208 int rc = 0;
3209 int bytes_returned = 0;
3210 SET_SEC_DESC_REQ *pSMB = NULL;
3211 NTRANSACT_RSP *pSMBr = NULL;
3212
3213setCifsAclRetry:
3214 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3215 (void **) &pSMBr);
3216 if (rc)
3217 return (rc);
3218
3219 pSMB->MaxSetupCount = 0;
3220 pSMB->Reserved = 0;
3221
3222 param_count = 8;
3223 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3224 data_count = acllen;
3225 data_offset = param_offset + param_count;
3226 byte_count = 3 /* pad */ + param_count;
3227
3228 pSMB->DataCount = cpu_to_le32(data_count);
3229 pSMB->TotalDataCount = pSMB->DataCount;
3230 pSMB->MaxParameterCount = cpu_to_le32(4);
3231 pSMB->MaxDataCount = cpu_to_le32(16384);
3232 pSMB->ParameterCount = cpu_to_le32(param_count);
3233 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3234 pSMB->TotalParameterCount = pSMB->ParameterCount;
3235 pSMB->DataOffset = cpu_to_le32(data_offset);
3236 pSMB->SetupCount = 0;
3237 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3238 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3239
3240 pSMB->Fid = fid; /* file handle always le */
3241 pSMB->Reserved2 = 0;
3242 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3243
3244 if (pntsd && acllen) {
3245 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3246 (char *) pntsd,
3247 acllen);
3248 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3249
3250 } else
3251 pSMB->hdr.smb_buf_length += byte_count;
3252
3253 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3254 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3255
Joe Perchesb6b38f72010-04-21 03:50:45 +00003256 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003257 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003258 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003259 cifs_buf_release(pSMB);
3260
3261 if (rc == -EAGAIN)
3262 goto setCifsAclRetry;
3263
3264 return (rc);
3265}
3266
Jeff Layton79df1ba2010-12-06 12:52:08 -05003267#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003268
Steve French6b8edfe2005-08-23 20:26:03 -07003269/* Legacy Query Path Information call for lookup to old servers such
3270 as Win9x/WinME */
3271int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003272 const unsigned char *searchName,
3273 FILE_ALL_INFO *pFinfo,
3274 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003275{
Steve Frenchad7a2922008-02-07 23:25:02 +00003276 QUERY_INFORMATION_REQ *pSMB;
3277 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003278 int rc = 0;
3279 int bytes_returned;
3280 int name_len;
3281
Joe Perchesb6b38f72010-04-21 03:50:45 +00003282 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003283QInfRetry:
3284 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003285 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003286 if (rc)
3287 return rc;
3288
3289 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3290 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003291 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3292 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003293 name_len++; /* trailing null */
3294 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003295 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003296 name_len = strnlen(searchName, PATH_MAX);
3297 name_len++; /* trailing null */
3298 strncpy(pSMB->FileName, searchName, name_len);
3299 }
3300 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003301 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003302 pSMB->hdr.smb_buf_length += (__u16) name_len;
3303 pSMB->ByteCount = cpu_to_le16(name_len);
3304
3305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003307 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003308 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003309 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003310 struct timespec ts;
3311 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003312
3313 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003314 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003315 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003316 ts.tv_nsec = 0;
3317 ts.tv_sec = time;
3318 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003319 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003320 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3321 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003322 pFinfo->AllocationSize =
3323 cpu_to_le64(le32_to_cpu(pSMBr->size));
3324 pFinfo->EndOfFile = pFinfo->AllocationSize;
3325 pFinfo->Attributes =
3326 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003327 } else
3328 rc = -EIO; /* bad buffer passed in */
3329
3330 cifs_buf_release(pSMB);
3331
3332 if (rc == -EAGAIN)
3333 goto QInfRetry;
3334
3335 return rc;
3336}
3337
Jeff Laytonbcd53572010-02-12 07:44:16 -05003338int
3339CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3340 u16 netfid, FILE_ALL_INFO *pFindData)
3341{
3342 struct smb_t2_qfi_req *pSMB = NULL;
3343 struct smb_t2_qfi_rsp *pSMBr = NULL;
3344 int rc = 0;
3345 int bytes_returned;
3346 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003347
Jeff Laytonbcd53572010-02-12 07:44:16 -05003348QFileInfoRetry:
3349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3350 (void **) &pSMBr);
3351 if (rc)
3352 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003353
Jeff Laytonbcd53572010-02-12 07:44:16 -05003354 params = 2 /* level */ + 2 /* fid */;
3355 pSMB->t2.TotalDataCount = 0;
3356 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3357 /* BB find exact max data count below from sess structure BB */
3358 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3359 pSMB->t2.MaxSetupCount = 0;
3360 pSMB->t2.Reserved = 0;
3361 pSMB->t2.Flags = 0;
3362 pSMB->t2.Timeout = 0;
3363 pSMB->t2.Reserved2 = 0;
3364 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3365 Fid) - 4);
3366 pSMB->t2.DataCount = 0;
3367 pSMB->t2.DataOffset = 0;
3368 pSMB->t2.SetupCount = 1;
3369 pSMB->t2.Reserved3 = 0;
3370 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3371 byte_count = params + 1 /* pad */ ;
3372 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3373 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3374 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3375 pSMB->Pad = 0;
3376 pSMB->Fid = netfid;
3377 pSMB->hdr.smb_buf_length += byte_count;
3378
3379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3380 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3381 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003382 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003383 } else { /* decode response */
3384 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3385
3386 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3387 rc = -EIO;
3388 else if (pSMBr->ByteCount < 40)
3389 rc = -EIO; /* bad smb */
3390 else if (pFindData) {
3391 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3392 memcpy((char *) pFindData,
3393 (char *) &pSMBr->hdr.Protocol +
3394 data_offset, sizeof(FILE_ALL_INFO));
3395 } else
3396 rc = -ENOMEM;
3397 }
3398 cifs_buf_release(pSMB);
3399 if (rc == -EAGAIN)
3400 goto QFileInfoRetry;
3401
3402 return rc;
3403}
Steve French6b8edfe2005-08-23 20:26:03 -07003404
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405int
3406CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3407 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003408 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003409 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003410 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411{
3412/* level 263 SMB_QUERY_FILE_ALL_INFO */
3413 TRANSACTION2_QPI_REQ *pSMB = NULL;
3414 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3415 int rc = 0;
3416 int bytes_returned;
3417 int name_len;
3418 __u16 params, byte_count;
3419
Joe Perchesb6b38f72010-04-21 03:50:45 +00003420/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421QPathInfoRetry:
3422 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3423 (void **) &pSMBr);
3424 if (rc)
3425 return rc;
3426
3427 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3428 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003429 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003430 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 name_len++; /* trailing null */
3432 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003433 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 name_len = strnlen(searchName, PATH_MAX);
3435 name_len++; /* trailing null */
3436 strncpy(pSMB->FileName, searchName, name_len);
3437 }
3438
Steve French50c2f752007-07-13 00:33:32 +00003439 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440 pSMB->TotalDataCount = 0;
3441 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003442 /* BB find exact max SMB PDU from sess structure BB */
3443 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 pSMB->MaxSetupCount = 0;
3445 pSMB->Reserved = 0;
3446 pSMB->Flags = 0;
3447 pSMB->Timeout = 0;
3448 pSMB->Reserved2 = 0;
3449 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003450 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451 pSMB->DataCount = 0;
3452 pSMB->DataOffset = 0;
3453 pSMB->SetupCount = 1;
3454 pSMB->Reserved3 = 0;
3455 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3456 byte_count = params + 1 /* pad */ ;
3457 pSMB->TotalParameterCount = cpu_to_le16(params);
3458 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003459 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003460 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3461 else
3462 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 pSMB->Reserved4 = 0;
3464 pSMB->hdr.smb_buf_length += byte_count;
3465 pSMB->ByteCount = cpu_to_le16(byte_count);
3466
3467 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3468 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3469 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003470 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 } else { /* decode response */
3472 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3473
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003474 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3475 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003476 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003478 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003479 rc = -EIO; /* 24 or 26 expected but we do not read
3480 last field */
3481 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003482 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003484
3485 /* On legacy responses we do not read the last field,
3486 EAsize, fortunately since it varies by subdialect and
3487 also note it differs on Set vs. Get, ie two bytes or 4
3488 bytes depending but we don't care here */
3489 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003490 size = sizeof(FILE_INFO_STANDARD);
3491 else
3492 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 memcpy((char *) pFindData,
3494 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003495 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 } else
3497 rc = -ENOMEM;
3498 }
3499 cifs_buf_release(pSMB);
3500 if (rc == -EAGAIN)
3501 goto QPathInfoRetry;
3502
3503 return rc;
3504}
3505
3506int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003507CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3508 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3509{
3510 struct smb_t2_qfi_req *pSMB = NULL;
3511 struct smb_t2_qfi_rsp *pSMBr = NULL;
3512 int rc = 0;
3513 int bytes_returned;
3514 __u16 params, byte_count;
3515
3516UnixQFileInfoRetry:
3517 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3518 (void **) &pSMBr);
3519 if (rc)
3520 return rc;
3521
3522 params = 2 /* level */ + 2 /* fid */;
3523 pSMB->t2.TotalDataCount = 0;
3524 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3525 /* BB find exact max data count below from sess structure BB */
3526 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3527 pSMB->t2.MaxSetupCount = 0;
3528 pSMB->t2.Reserved = 0;
3529 pSMB->t2.Flags = 0;
3530 pSMB->t2.Timeout = 0;
3531 pSMB->t2.Reserved2 = 0;
3532 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3533 Fid) - 4);
3534 pSMB->t2.DataCount = 0;
3535 pSMB->t2.DataOffset = 0;
3536 pSMB->t2.SetupCount = 1;
3537 pSMB->t2.Reserved3 = 0;
3538 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3539 byte_count = params + 1 /* pad */ ;
3540 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3541 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3542 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3543 pSMB->Pad = 0;
3544 pSMB->Fid = netfid;
3545 pSMB->hdr.smb_buf_length += byte_count;
3546
3547 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3548 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3549 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003550 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003551 } else { /* decode response */
3552 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3553
3554 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003555 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003556 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003557 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003558 rc = -EIO; /* bad smb */
3559 } else {
3560 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3561 memcpy((char *) pFindData,
3562 (char *) &pSMBr->hdr.Protocol +
3563 data_offset,
3564 sizeof(FILE_UNIX_BASIC_INFO));
3565 }
3566 }
3567
3568 cifs_buf_release(pSMB);
3569 if (rc == -EAGAIN)
3570 goto UnixQFileInfoRetry;
3571
3572 return rc;
3573}
3574
3575int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3577 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003578 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003579 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580{
3581/* SMB_QUERY_FILE_UNIX_BASIC */
3582 TRANSACTION2_QPI_REQ *pSMB = NULL;
3583 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3584 int rc = 0;
3585 int bytes_returned = 0;
3586 int name_len;
3587 __u16 params, byte_count;
3588
Joe Perchesb6b38f72010-04-21 03:50:45 +00003589 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590UnixQPathInfoRetry:
3591 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3592 (void **) &pSMBr);
3593 if (rc)
3594 return rc;
3595
3596 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3597 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003598 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003599 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 name_len++; /* trailing null */
3601 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003602 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 name_len = strnlen(searchName, PATH_MAX);
3604 name_len++; /* trailing null */
3605 strncpy(pSMB->FileName, searchName, name_len);
3606 }
3607
Steve French50c2f752007-07-13 00:33:32 +00003608 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 pSMB->TotalDataCount = 0;
3610 pSMB->MaxParameterCount = cpu_to_le16(2);
3611 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003612 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 pSMB->MaxSetupCount = 0;
3614 pSMB->Reserved = 0;
3615 pSMB->Flags = 0;
3616 pSMB->Timeout = 0;
3617 pSMB->Reserved2 = 0;
3618 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003619 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 pSMB->DataCount = 0;
3621 pSMB->DataOffset = 0;
3622 pSMB->SetupCount = 1;
3623 pSMB->Reserved3 = 0;
3624 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3625 byte_count = params + 1 /* pad */ ;
3626 pSMB->TotalParameterCount = cpu_to_le16(params);
3627 pSMB->ParameterCount = pSMB->TotalParameterCount;
3628 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3629 pSMB->Reserved4 = 0;
3630 pSMB->hdr.smb_buf_length += byte_count;
3631 pSMB->ByteCount = cpu_to_le16(byte_count);
3632
3633 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3634 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3635 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003636 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 } else { /* decode response */
3638 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3639
3640 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003641 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003642 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003643 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003644 rc = -EIO; /* bad smb */
3645 } else {
3646 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3647 memcpy((char *) pFindData,
3648 (char *) &pSMBr->hdr.Protocol +
3649 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003650 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 }
3652 }
3653 cifs_buf_release(pSMB);
3654 if (rc == -EAGAIN)
3655 goto UnixQPathInfoRetry;
3656
3657 return rc;
3658}
3659
Linus Torvalds1da177e2005-04-16 15:20:36 -07003660/* xid, tcon, searchName and codepage are input parms, rest are returned */
3661int
3662CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003663 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003665 __u16 *pnetfid,
3666 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667{
3668/* level 257 SMB_ */
3669 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3670 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003671 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672 int rc = 0;
3673 int bytes_returned = 0;
3674 int name_len;
3675 __u16 params, byte_count;
3676
Joe Perchesb6b38f72010-04-21 03:50:45 +00003677 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678
3679findFirstRetry:
3680 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3681 (void **) &pSMBr);
3682 if (rc)
3683 return rc;
3684
3685 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3686 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003687 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003688 PATH_MAX, nls_codepage, remap);
3689 /* We can not add the asterik earlier in case
3690 it got remapped to 0xF03A as if it were part of the
3691 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003693 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003694 pSMB->FileName[name_len+1] = 0;
3695 pSMB->FileName[name_len+2] = '*';
3696 pSMB->FileName[name_len+3] = 0;
3697 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3699 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003700 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 } else { /* BB add check for overrun of SMB buf BB */
3702 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003704 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 free buffer exit; BB */
3706 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003707 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003708 pSMB->FileName[name_len+1] = '*';
3709 pSMB->FileName[name_len+2] = 0;
3710 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 }
3712
3713 params = 12 + name_len /* includes null */ ;
3714 pSMB->TotalDataCount = 0; /* no EAs */
3715 pSMB->MaxParameterCount = cpu_to_le16(10);
3716 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3717 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3718 pSMB->MaxSetupCount = 0;
3719 pSMB->Reserved = 0;
3720 pSMB->Flags = 0;
3721 pSMB->Timeout = 0;
3722 pSMB->Reserved2 = 0;
3723 byte_count = params + 1 /* pad */ ;
3724 pSMB->TotalParameterCount = cpu_to_le16(params);
3725 pSMB->ParameterCount = pSMB->TotalParameterCount;
3726 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003727 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3728 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 pSMB->DataCount = 0;
3730 pSMB->DataOffset = 0;
3731 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3732 pSMB->Reserved3 = 0;
3733 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3734 pSMB->SearchAttributes =
3735 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3736 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003737 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3738 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 CIFS_SEARCH_RETURN_RESUME);
3740 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3741
3742 /* BB what should we set StorageType to? Does it matter? BB */
3743 pSMB->SearchStorageType = 0;
3744 pSMB->hdr.smb_buf_length += byte_count;
3745 pSMB->ByteCount = cpu_to_le16(byte_count);
3746
3747 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3748 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003749 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
Steve French88274812006-03-09 22:21:45 +00003751 if (rc) {/* BB add logic to retry regular search if Unix search
3752 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003754 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003755
Steve French88274812006-03-09 22:21:45 +00003756 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757
3758 /* BB eventually could optimize out free and realloc of buf */
3759 /* for this case */
3760 if (rc == -EAGAIN)
3761 goto findFirstRetry;
3762 } else { /* decode response */
3763 /* BB remember to free buffer if error BB */
3764 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003765 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003766 unsigned int lnoff;
3767
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003769 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 else
Steve French4b18f2a2008-04-29 00:06:05 +00003771 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
3773 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003774 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003775 psrch_inf->srch_entries_start =
3776 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3779 le16_to_cpu(pSMBr->t2.ParameterOffset));
3780
Steve French790fe572007-07-07 19:25:05 +00003781 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003782 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003783 else
Steve French4b18f2a2008-04-29 00:06:05 +00003784 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785
Steve French50c2f752007-07-13 00:33:32 +00003786 psrch_inf->entries_in_buffer =
3787 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003788 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003790 lnoff = le16_to_cpu(parms->LastNameOffset);
3791 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3792 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003793 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003794 psrch_inf->last_entry = NULL;
3795 return rc;
3796 }
3797
Steve French0752f152008-10-07 20:03:33 +00003798 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003799 lnoff;
3800
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 *pnetfid = parms->SearchHandle;
3802 } else {
3803 cifs_buf_release(pSMB);
3804 }
3805 }
3806
3807 return rc;
3808}
3809
3810int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003811 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812{
3813 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3814 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003815 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 char *response_data;
3817 int rc = 0;
3818 int bytes_returned, name_len;
3819 __u16 params, byte_count;
3820
Joe Perchesb6b38f72010-04-21 03:50:45 +00003821 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822
Steve French4b18f2a2008-04-29 00:06:05 +00003823 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 return -ENOENT;
3825
3826 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3827 (void **) &pSMBr);
3828 if (rc)
3829 return rc;
3830
Steve French50c2f752007-07-13 00:33:32 +00003831 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 byte_count = 0;
3833 pSMB->TotalDataCount = 0; /* no EAs */
3834 pSMB->MaxParameterCount = cpu_to_le16(8);
3835 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003836 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3837 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 pSMB->MaxSetupCount = 0;
3839 pSMB->Reserved = 0;
3840 pSMB->Flags = 0;
3841 pSMB->Timeout = 0;
3842 pSMB->Reserved2 = 0;
3843 pSMB->ParameterOffset = cpu_to_le16(
3844 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3845 pSMB->DataCount = 0;
3846 pSMB->DataOffset = 0;
3847 pSMB->SetupCount = 1;
3848 pSMB->Reserved3 = 0;
3849 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3850 pSMB->SearchHandle = searchHandle; /* always kept as le */
3851 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003852 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3854 pSMB->ResumeKey = psrch_inf->resume_key;
3855 pSMB->SearchFlags =
3856 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3857
3858 name_len = psrch_inf->resume_name_len;
3859 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003860 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3862 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003863 /* 14 byte parm len above enough for 2 byte null terminator */
3864 pSMB->ResumeFileName[name_len] = 0;
3865 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866 } else {
3867 rc = -EINVAL;
3868 goto FNext2_err_exit;
3869 }
3870 byte_count = params + 1 /* pad */ ;
3871 pSMB->TotalParameterCount = cpu_to_le16(params);
3872 pSMB->ParameterCount = pSMB->TotalParameterCount;
3873 pSMB->hdr.smb_buf_length += byte_count;
3874 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003875
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003878 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 if (rc) {
3880 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003881 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003882 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003883 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003885 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 } else { /* decode response */
3887 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003888
Steve French790fe572007-07-07 19:25:05 +00003889 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003890 unsigned int lnoff;
3891
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 /* BB fixme add lock for file (srch_info) struct here */
3893 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003894 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 else
Steve French4b18f2a2008-04-29 00:06:05 +00003896 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 response_data = (char *) &pSMBr->hdr.Protocol +
3898 le16_to_cpu(pSMBr->t2.ParameterOffset);
3899 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3900 response_data = (char *)&pSMBr->hdr.Protocol +
3901 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003902 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003903 cifs_small_buf_release(
3904 psrch_inf->ntwrk_buf_start);
3905 else
3906 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 psrch_inf->srch_entries_start = response_data;
3908 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003909 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003910 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003911 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 else
Steve French4b18f2a2008-04-29 00:06:05 +00003913 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003914 psrch_inf->entries_in_buffer =
3915 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 psrch_inf->index_of_last_entry +=
3917 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003918 lnoff = le16_to_cpu(parms->LastNameOffset);
3919 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3920 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003921 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003922 psrch_inf->last_entry = NULL;
3923 return rc;
3924 } else
3925 psrch_inf->last_entry =
3926 psrch_inf->srch_entries_start + lnoff;
3927
Joe Perchesb6b38f72010-04-21 03:50:45 +00003928/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3929 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930
3931 /* BB fixme add unlock here */
3932 }
3933
3934 }
3935
3936 /* BB On error, should we leave previous search buf (and count and
3937 last entry fields) intact or free the previous one? */
3938
3939 /* Note: On -EAGAIN error only caller can retry on handle based calls
3940 since file handle passed in no longer valid */
3941FNext2_err_exit:
3942 if (rc != 0)
3943 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 return rc;
3945}
3946
3947int
Steve French50c2f752007-07-13 00:33:32 +00003948CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3949 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950{
3951 int rc = 0;
3952 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953
Joe Perchesb6b38f72010-04-21 03:50:45 +00003954 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3956
3957 /* no sense returning error if session restarted
3958 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003959 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 return 0;
3961 if (rc)
3962 return rc;
3963
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 pSMB->FileID = searchHandle;
3965 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003966 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003967 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003968 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003969
Steve Frencha4544342005-08-24 13:59:35 -07003970 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971
3972 /* Since session is dead, search handle closed on server already */
3973 if (rc == -EAGAIN)
3974 rc = 0;
3975
3976 return rc;
3977}
3978
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979int
3980CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003981 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003982 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003983 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984{
3985 int rc = 0;
3986 TRANSACTION2_QPI_REQ *pSMB = NULL;
3987 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3988 int name_len, bytes_returned;
3989 __u16 params, byte_count;
3990
Joe Perchesb6b38f72010-04-21 03:50:45 +00003991 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003992 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003993 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994
3995GetInodeNumberRetry:
3996 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003997 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 if (rc)
3999 return rc;
4000
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4002 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004003 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004004 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 name_len++; /* trailing null */
4006 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004007 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 name_len = strnlen(searchName, PATH_MAX);
4009 name_len++; /* trailing null */
4010 strncpy(pSMB->FileName, searchName, name_len);
4011 }
4012
4013 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4014 pSMB->TotalDataCount = 0;
4015 pSMB->MaxParameterCount = cpu_to_le16(2);
4016 /* BB find exact max data count below from sess structure BB */
4017 pSMB->MaxDataCount = cpu_to_le16(4000);
4018 pSMB->MaxSetupCount = 0;
4019 pSMB->Reserved = 0;
4020 pSMB->Flags = 0;
4021 pSMB->Timeout = 0;
4022 pSMB->Reserved2 = 0;
4023 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004024 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 pSMB->DataCount = 0;
4026 pSMB->DataOffset = 0;
4027 pSMB->SetupCount = 1;
4028 pSMB->Reserved3 = 0;
4029 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4030 byte_count = params + 1 /* pad */ ;
4031 pSMB->TotalParameterCount = cpu_to_le16(params);
4032 pSMB->ParameterCount = pSMB->TotalParameterCount;
4033 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4034 pSMB->Reserved4 = 0;
4035 pSMB->hdr.smb_buf_length += byte_count;
4036 pSMB->ByteCount = cpu_to_le16(byte_count);
4037
4038 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4039 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4040 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004041 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 } else {
4043 /* decode response */
4044 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4045 if (rc || (pSMBr->ByteCount < 2))
4046 /* BB also check enough total bytes returned */
4047 /* If rc should we check for EOPNOSUPP and
4048 disable the srvino flag? or in caller? */
4049 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004050 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4052 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004053 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004055 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004056 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057 rc = -EIO;
4058 goto GetInodeNumOut;
4059 }
4060 pfinfo = (struct file_internal_info *)
4061 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004062 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 }
4064 }
4065GetInodeNumOut:
4066 cifs_buf_release(pSMB);
4067 if (rc == -EAGAIN)
4068 goto GetInodeNumberRetry;
4069 return rc;
4070}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071
Igor Mammedovfec45852008-05-16 13:06:30 +04004072/* parses DFS refferal V3 structure
4073 * caller is responsible for freeing target_nodes
4074 * returns:
4075 * on success - 0
4076 * on failure - errno
4077 */
4078static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004079parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004080 unsigned int *num_of_nodes,
4081 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004082 const struct nls_table *nls_codepage, int remap,
4083 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004084{
4085 int i, rc = 0;
4086 char *data_end;
4087 bool is_unicode;
4088 struct dfs_referral_level_3 *ref;
4089
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004090 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4091 is_unicode = true;
4092 else
4093 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004094 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4095
4096 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004097 cERROR(1, "num_referrals: must be at least > 0,"
4098 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004099 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004100 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004101 }
4102
4103 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004104 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004105 cERROR(1, "Referrals of V%d version are not supported,"
4106 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004107 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004108 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004109 }
4110
4111 /* get the upper boundary of the resp buffer */
4112 data_end = (char *)(&(pSMBr->PathConsumed)) +
4113 le16_to_cpu(pSMBr->t2.DataCount);
4114
Steve Frenchf19159d2010-04-21 04:12:10 +00004115 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004116 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004117 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004118
4119 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4120 *num_of_nodes, GFP_KERNEL);
4121 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004122 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004123 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004124 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004125 }
4126
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004127 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004128 for (i = 0; i < *num_of_nodes; i++) {
4129 char *temp;
4130 int max_len;
4131 struct dfs_info3_param *node = (*target_nodes)+i;
4132
Steve French0e0d2cf2009-05-01 05:27:32 +00004133 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004134 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004135 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4136 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004137 if (tmp == NULL) {
4138 rc = -ENOMEM;
4139 goto parse_DFS_referrals_exit;
4140 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004141 cifsConvertToUCS((__le16 *) tmp, searchName,
4142 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004143 node->path_consumed = cifs_ucs2_bytes(tmp,
4144 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004145 nls_codepage);
4146 kfree(tmp);
4147 } else
4148 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4149
Igor Mammedovfec45852008-05-16 13:06:30 +04004150 node->server_type = le16_to_cpu(ref->ServerType);
4151 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4152
4153 /* copy DfsPath */
4154 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4155 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004156 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4157 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004158 if (!node->path_name) {
4159 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004160 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004161 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004162
4163 /* copy link target UNC */
4164 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4165 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004166 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4167 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004168 if (!node->node_name)
4169 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004170 }
4171
Steve Frencha1fe78f2008-05-16 18:48:38 +00004172parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004173 if (rc) {
4174 free_dfs_info_array(*target_nodes, *num_of_nodes);
4175 *target_nodes = NULL;
4176 *num_of_nodes = 0;
4177 }
4178 return rc;
4179}
4180
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181int
4182CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4183 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004184 struct dfs_info3_param **target_nodes,
4185 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004186 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187{
4188/* TRANS2_GET_DFS_REFERRAL */
4189 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4190 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 int rc = 0;
4192 int bytes_returned;
4193 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004195 *num_of_nodes = 0;
4196 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197
Joe Perchesb6b38f72010-04-21 03:50:45 +00004198 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 if (ses == NULL)
4200 return -ENODEV;
4201getDFSRetry:
4202 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4203 (void **) &pSMBr);
4204 if (rc)
4205 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004206
4207 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004208 but should never be null here anyway */
4209 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210 pSMB->hdr.Tid = ses->ipc_tid;
4211 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004212 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004214 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216
4217 if (ses->capabilities & CAP_UNICODE) {
4218 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4219 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004220 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004221 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 name_len++; /* trailing null */
4223 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004224 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 name_len = strnlen(searchName, PATH_MAX);
4226 name_len++; /* trailing null */
4227 strncpy(pSMB->RequestFileName, searchName, name_len);
4228 }
4229
Steve French790fe572007-07-07 19:25:05 +00004230 if (ses->server) {
4231 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004232 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4233 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4234 }
4235
Steve French50c2f752007-07-13 00:33:32 +00004236 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004237
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 params = 2 /* level */ + name_len /*includes null */ ;
4239 pSMB->TotalDataCount = 0;
4240 pSMB->DataCount = 0;
4241 pSMB->DataOffset = 0;
4242 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004243 /* BB find exact max SMB PDU from sess structure BB */
4244 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 pSMB->MaxSetupCount = 0;
4246 pSMB->Reserved = 0;
4247 pSMB->Flags = 0;
4248 pSMB->Timeout = 0;
4249 pSMB->Reserved2 = 0;
4250 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004251 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 pSMB->SetupCount = 1;
4253 pSMB->Reserved3 = 0;
4254 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4255 byte_count = params + 3 /* pad */ ;
4256 pSMB->ParameterCount = cpu_to_le16(params);
4257 pSMB->TotalParameterCount = pSMB->ParameterCount;
4258 pSMB->MaxReferralLevel = cpu_to_le16(3);
4259 pSMB->hdr.smb_buf_length += byte_count;
4260 pSMB->ByteCount = cpu_to_le16(byte_count);
4261
4262 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4264 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004265 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004266 goto GetDFSRefExit;
4267 }
4268 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004270 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004271 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004272 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004273 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004275
Joe Perchesb6b38f72010-04-21 03:50:45 +00004276 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Igor Mammedovfec45852008-05-16 13:06:30 +04004277 pSMBr->ByteCount,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004278 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004279
4280 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004281 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004282 target_nodes, nls_codepage, remap,
4283 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004284
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004286 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
4288 if (rc == -EAGAIN)
4289 goto getDFSRetry;
4290
4291 return rc;
4292}
4293
Steve French20962432005-09-21 22:05:57 -07004294/* Query File System Info such as free space to old servers such as Win 9x */
4295int
4296SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4297{
4298/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4299 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4300 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4301 FILE_SYSTEM_ALLOC_INFO *response_data;
4302 int rc = 0;
4303 int bytes_returned = 0;
4304 __u16 params, byte_count;
4305
Joe Perchesb6b38f72010-04-21 03:50:45 +00004306 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004307oldQFSInfoRetry:
4308 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4309 (void **) &pSMBr);
4310 if (rc)
4311 return rc;
Steve French20962432005-09-21 22:05:57 -07004312
4313 params = 2; /* level */
4314 pSMB->TotalDataCount = 0;
4315 pSMB->MaxParameterCount = cpu_to_le16(2);
4316 pSMB->MaxDataCount = cpu_to_le16(1000);
4317 pSMB->MaxSetupCount = 0;
4318 pSMB->Reserved = 0;
4319 pSMB->Flags = 0;
4320 pSMB->Timeout = 0;
4321 pSMB->Reserved2 = 0;
4322 byte_count = params + 1 /* pad */ ;
4323 pSMB->TotalParameterCount = cpu_to_le16(params);
4324 pSMB->ParameterCount = pSMB->TotalParameterCount;
4325 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4326 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4327 pSMB->DataCount = 0;
4328 pSMB->DataOffset = 0;
4329 pSMB->SetupCount = 1;
4330 pSMB->Reserved3 = 0;
4331 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4332 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4333 pSMB->hdr.smb_buf_length += byte_count;
4334 pSMB->ByteCount = cpu_to_le16(byte_count);
4335
4336 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4337 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4338 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004339 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004340 } else { /* decode response */
4341 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4342
4343 if (rc || (pSMBr->ByteCount < 18))
4344 rc = -EIO; /* bad smb */
4345 else {
4346 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004347 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4348 pSMBr->ByteCount, data_offset);
Steve French20962432005-09-21 22:05:57 -07004349
Steve French50c2f752007-07-13 00:33:32 +00004350 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004351 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4352 FSData->f_bsize =
4353 le16_to_cpu(response_data->BytesPerSector) *
4354 le32_to_cpu(response_data->
4355 SectorsPerAllocationUnit);
4356 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004357 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004358 FSData->f_bfree = FSData->f_bavail =
4359 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004360 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4361 (unsigned long long)FSData->f_blocks,
4362 (unsigned long long)FSData->f_bfree,
4363 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004364 }
4365 }
4366 cifs_buf_release(pSMB);
4367
4368 if (rc == -EAGAIN)
4369 goto oldQFSInfoRetry;
4370
4371 return rc;
4372}
4373
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374int
Steve French737b7582005-04-28 22:41:06 -07004375CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376{
4377/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4378 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4379 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4380 FILE_SYSTEM_INFO *response_data;
4381 int rc = 0;
4382 int bytes_returned = 0;
4383 __u16 params, byte_count;
4384
Joe Perchesb6b38f72010-04-21 03:50:45 +00004385 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386QFSInfoRetry:
4387 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4388 (void **) &pSMBr);
4389 if (rc)
4390 return rc;
4391
4392 params = 2; /* level */
4393 pSMB->TotalDataCount = 0;
4394 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004395 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 pSMB->MaxSetupCount = 0;
4397 pSMB->Reserved = 0;
4398 pSMB->Flags = 0;
4399 pSMB->Timeout = 0;
4400 pSMB->Reserved2 = 0;
4401 byte_count = params + 1 /* pad */ ;
4402 pSMB->TotalParameterCount = cpu_to_le16(params);
4403 pSMB->ParameterCount = pSMB->TotalParameterCount;
4404 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004405 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 pSMB->DataCount = 0;
4407 pSMB->DataOffset = 0;
4408 pSMB->SetupCount = 1;
4409 pSMB->Reserved3 = 0;
4410 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4411 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4412 pSMB->hdr.smb_buf_length += byte_count;
4413 pSMB->ByteCount = cpu_to_le16(byte_count);
4414
4415 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4416 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4417 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004418 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004420 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421
Steve French20962432005-09-21 22:05:57 -07004422 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 rc = -EIO; /* bad smb */
4424 else {
4425 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426
4427 response_data =
4428 (FILE_SYSTEM_INFO
4429 *) (((char *) &pSMBr->hdr.Protocol) +
4430 data_offset);
4431 FSData->f_bsize =
4432 le32_to_cpu(response_data->BytesPerSector) *
4433 le32_to_cpu(response_data->
4434 SectorsPerAllocationUnit);
4435 FSData->f_blocks =
4436 le64_to_cpu(response_data->TotalAllocationUnits);
4437 FSData->f_bfree = FSData->f_bavail =
4438 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004439 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4440 (unsigned long long)FSData->f_blocks,
4441 (unsigned long long)FSData->f_bfree,
4442 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 }
4444 }
4445 cifs_buf_release(pSMB);
4446
4447 if (rc == -EAGAIN)
4448 goto QFSInfoRetry;
4449
4450 return rc;
4451}
4452
4453int
Steve French737b7582005-04-28 22:41:06 -07004454CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455{
4456/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4457 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4458 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4459 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4460 int rc = 0;
4461 int bytes_returned = 0;
4462 __u16 params, byte_count;
4463
Joe Perchesb6b38f72010-04-21 03:50:45 +00004464 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465QFSAttributeRetry:
4466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4467 (void **) &pSMBr);
4468 if (rc)
4469 return rc;
4470
4471 params = 2; /* level */
4472 pSMB->TotalDataCount = 0;
4473 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004474 /* BB find exact max SMB PDU from sess structure BB */
4475 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 pSMB->MaxSetupCount = 0;
4477 pSMB->Reserved = 0;
4478 pSMB->Flags = 0;
4479 pSMB->Timeout = 0;
4480 pSMB->Reserved2 = 0;
4481 byte_count = params + 1 /* pad */ ;
4482 pSMB->TotalParameterCount = cpu_to_le16(params);
4483 pSMB->ParameterCount = pSMB->TotalParameterCount;
4484 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004485 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 pSMB->DataCount = 0;
4487 pSMB->DataOffset = 0;
4488 pSMB->SetupCount = 1;
4489 pSMB->Reserved3 = 0;
4490 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4491 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4492 pSMB->hdr.smb_buf_length += byte_count;
4493 pSMB->ByteCount = cpu_to_le16(byte_count);
4494
4495 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4496 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4497 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004498 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 } else { /* decode response */
4500 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4501
Steve French50c2f752007-07-13 00:33:32 +00004502 if (rc || (pSMBr->ByteCount < 13)) {
4503 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 rc = -EIO; /* bad smb */
4505 } else {
4506 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4507 response_data =
4508 (FILE_SYSTEM_ATTRIBUTE_INFO
4509 *) (((char *) &pSMBr->hdr.Protocol) +
4510 data_offset);
4511 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004512 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513 }
4514 }
4515 cifs_buf_release(pSMB);
4516
4517 if (rc == -EAGAIN)
4518 goto QFSAttributeRetry;
4519
4520 return rc;
4521}
4522
4523int
Steve French737b7582005-04-28 22:41:06 -07004524CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525{
4526/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4527 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4528 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4529 FILE_SYSTEM_DEVICE_INFO *response_data;
4530 int rc = 0;
4531 int bytes_returned = 0;
4532 __u16 params, byte_count;
4533
Joe Perchesb6b38f72010-04-21 03:50:45 +00004534 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535QFSDeviceRetry:
4536 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4537 (void **) &pSMBr);
4538 if (rc)
4539 return rc;
4540
4541 params = 2; /* level */
4542 pSMB->TotalDataCount = 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(1000);
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->TotalParameterCount = cpu_to_le16(params);
4553 pSMB->ParameterCount = pSMB->TotalParameterCount;
4554 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004555 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
4557 pSMB->DataCount = 0;
4558 pSMB->DataOffset = 0;
4559 pSMB->SetupCount = 1;
4560 pSMB->Reserved3 = 0;
4561 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4562 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4563 pSMB->hdr.smb_buf_length += byte_count;
4564 pSMB->ByteCount = cpu_to_le16(byte_count);
4565
4566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4568 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004569 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 } else { /* decode response */
4571 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4572
Steve French630f3f0c2007-10-25 21:17:17 +00004573 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 rc = -EIO; /* bad smb */
4575 else {
4576 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4577 response_data =
Steve French737b7582005-04-28 22:41:06 -07004578 (FILE_SYSTEM_DEVICE_INFO *)
4579 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580 data_offset);
4581 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004582 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004583 }
4584 }
4585 cifs_buf_release(pSMB);
4586
4587 if (rc == -EAGAIN)
4588 goto QFSDeviceRetry;
4589
4590 return rc;
4591}
4592
4593int
Steve French737b7582005-04-28 22:41:06 -07004594CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595{
4596/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4597 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4598 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4599 FILE_SYSTEM_UNIX_INFO *response_data;
4600 int rc = 0;
4601 int bytes_returned = 0;
4602 __u16 params, byte_count;
4603
Joe Perchesb6b38f72010-04-21 03:50:45 +00004604 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004606 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4607 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 if (rc)
4609 return rc;
4610
4611 params = 2; /* level */
4612 pSMB->TotalDataCount = 0;
4613 pSMB->DataCount = 0;
4614 pSMB->DataOffset = 0;
4615 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004616 /* BB find exact max SMB PDU from sess structure BB */
4617 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 pSMB->MaxSetupCount = 0;
4619 pSMB->Reserved = 0;
4620 pSMB->Flags = 0;
4621 pSMB->Timeout = 0;
4622 pSMB->Reserved2 = 0;
4623 byte_count = params + 1 /* pad */ ;
4624 pSMB->ParameterCount = cpu_to_le16(params);
4625 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004626 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4627 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 pSMB->SetupCount = 1;
4629 pSMB->Reserved3 = 0;
4630 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4631 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4632 pSMB->hdr.smb_buf_length += byte_count;
4633 pSMB->ByteCount = cpu_to_le16(byte_count);
4634
4635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4637 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004638 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 } else { /* decode response */
4640 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4641
4642 if (rc || (pSMBr->ByteCount < 13)) {
4643 rc = -EIO; /* bad smb */
4644 } else {
4645 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4646 response_data =
4647 (FILE_SYSTEM_UNIX_INFO
4648 *) (((char *) &pSMBr->hdr.Protocol) +
4649 data_offset);
4650 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004651 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 }
4653 }
4654 cifs_buf_release(pSMB);
4655
4656 if (rc == -EAGAIN)
4657 goto QFSUnixRetry;
4658
4659
4660 return rc;
4661}
4662
Jeremy Allisonac670552005-06-22 17:26:35 -07004663int
Steve French45abc6e2005-06-23 13:42:03 -05004664CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004665{
4666/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4667 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4668 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4669 int rc = 0;
4670 int bytes_returned = 0;
4671 __u16 params, param_offset, offset, byte_count;
4672
Joe Perchesb6b38f72010-04-21 03:50:45 +00004673 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004674SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004675 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004676 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4677 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004678 if (rc)
4679 return rc;
4680
4681 params = 4; /* 2 bytes zero followed by info level. */
4682 pSMB->MaxSetupCount = 0;
4683 pSMB->Reserved = 0;
4684 pSMB->Flags = 0;
4685 pSMB->Timeout = 0;
4686 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004687 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4688 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004689 offset = param_offset + params;
4690
4691 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004692 /* BB find exact max SMB PDU from sess structure BB */
4693 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004694 pSMB->SetupCount = 1;
4695 pSMB->Reserved3 = 0;
4696 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4697 byte_count = 1 /* pad */ + params + 12;
4698
4699 pSMB->DataCount = cpu_to_le16(12);
4700 pSMB->ParameterCount = cpu_to_le16(params);
4701 pSMB->TotalDataCount = pSMB->DataCount;
4702 pSMB->TotalParameterCount = pSMB->ParameterCount;
4703 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4704 pSMB->DataOffset = cpu_to_le16(offset);
4705
4706 /* Params. */
4707 pSMB->FileNum = 0;
4708 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4709
4710 /* Data. */
4711 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4712 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4713 pSMB->ClientUnixCap = cpu_to_le64(cap);
4714
4715 pSMB->hdr.smb_buf_length += byte_count;
4716 pSMB->ByteCount = cpu_to_le16(byte_count);
4717
4718 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4719 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4720 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004721 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004722 } else { /* decode response */
4723 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004724 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004725 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004726 }
4727 cifs_buf_release(pSMB);
4728
4729 if (rc == -EAGAIN)
4730 goto SETFSUnixRetry;
4731
4732 return rc;
4733}
4734
4735
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736
4737int
4738CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004739 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740{
4741/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4742 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4743 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4744 FILE_SYSTEM_POSIX_INFO *response_data;
4745 int rc = 0;
4746 int bytes_returned = 0;
4747 __u16 params, byte_count;
4748
Joe Perchesb6b38f72010-04-21 03:50:45 +00004749 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750QFSPosixRetry:
4751 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4752 (void **) &pSMBr);
4753 if (rc)
4754 return rc;
4755
4756 params = 2; /* level */
4757 pSMB->TotalDataCount = 0;
4758 pSMB->DataCount = 0;
4759 pSMB->DataOffset = 0;
4760 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004761 /* BB find exact max SMB PDU from sess structure BB */
4762 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 pSMB->MaxSetupCount = 0;
4764 pSMB->Reserved = 0;
4765 pSMB->Flags = 0;
4766 pSMB->Timeout = 0;
4767 pSMB->Reserved2 = 0;
4768 byte_count = params + 1 /* pad */ ;
4769 pSMB->ParameterCount = cpu_to_le16(params);
4770 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004771 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4772 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 pSMB->SetupCount = 1;
4774 pSMB->Reserved3 = 0;
4775 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4776 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4777 pSMB->hdr.smb_buf_length += byte_count;
4778 pSMB->ByteCount = cpu_to_le16(byte_count);
4779
4780 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4781 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4782 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004783 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 } else { /* decode response */
4785 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4786
4787 if (rc || (pSMBr->ByteCount < 13)) {
4788 rc = -EIO; /* bad smb */
4789 } else {
4790 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4791 response_data =
4792 (FILE_SYSTEM_POSIX_INFO
4793 *) (((char *) &pSMBr->hdr.Protocol) +
4794 data_offset);
4795 FSData->f_bsize =
4796 le32_to_cpu(response_data->BlockSize);
4797 FSData->f_blocks =
4798 le64_to_cpu(response_data->TotalBlocks);
4799 FSData->f_bfree =
4800 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004801 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 FSData->f_bavail = FSData->f_bfree;
4803 } else {
4804 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004805 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 }
Steve French790fe572007-07-07 19:25:05 +00004807 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004809 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004810 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004812 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 }
4814 }
4815 cifs_buf_release(pSMB);
4816
4817 if (rc == -EAGAIN)
4818 goto QFSPosixRetry;
4819
4820 return rc;
4821}
4822
4823
Steve French50c2f752007-07-13 00:33:32 +00004824/* We can not use write of zero bytes trick to
4825 set file size due to need for large file support. Also note that
4826 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 routine which is only needed to work around a sharing violation bug
4828 in Samba which this routine can run into */
4829
4830int
4831CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004832 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004833 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834{
4835 struct smb_com_transaction2_spi_req *pSMB = NULL;
4836 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4837 struct file_end_of_file_info *parm_data;
4838 int name_len;
4839 int rc = 0;
4840 int bytes_returned = 0;
4841 __u16 params, byte_count, data_count, param_offset, offset;
4842
Joe Perchesb6b38f72010-04-21 03:50:45 +00004843 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844SetEOFRetry:
4845 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4846 (void **) &pSMBr);
4847 if (rc)
4848 return rc;
4849
4850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4851 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004852 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004853 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004854 name_len++; /* trailing null */
4855 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004856 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 name_len = strnlen(fileName, PATH_MAX);
4858 name_len++; /* trailing null */
4859 strncpy(pSMB->FileName, fileName, name_len);
4860 }
4861 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004862 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004864 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 pSMB->MaxSetupCount = 0;
4866 pSMB->Reserved = 0;
4867 pSMB->Flags = 0;
4868 pSMB->Timeout = 0;
4869 pSMB->Reserved2 = 0;
4870 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004871 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004873 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004874 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4875 pSMB->InformationLevel =
4876 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4877 else
4878 pSMB->InformationLevel =
4879 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4880 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4882 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004883 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 else
4885 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004886 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 }
4888
4889 parm_data =
4890 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4891 offset);
4892 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4893 pSMB->DataOffset = cpu_to_le16(offset);
4894 pSMB->SetupCount = 1;
4895 pSMB->Reserved3 = 0;
4896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4897 byte_count = 3 /* pad */ + params + data_count;
4898 pSMB->DataCount = cpu_to_le16(data_count);
4899 pSMB->TotalDataCount = pSMB->DataCount;
4900 pSMB->ParameterCount = cpu_to_le16(params);
4901 pSMB->TotalParameterCount = pSMB->ParameterCount;
4902 pSMB->Reserved4 = 0;
4903 pSMB->hdr.smb_buf_length += byte_count;
4904 parm_data->FileSize = cpu_to_le64(size);
4905 pSMB->ByteCount = cpu_to_le16(byte_count);
4906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004908 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004909 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910
4911 cifs_buf_release(pSMB);
4912
4913 if (rc == -EAGAIN)
4914 goto SetEOFRetry;
4915
4916 return rc;
4917}
4918
4919int
Steve French50c2f752007-07-13 00:33:32 +00004920CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004921 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922{
4923 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 struct file_end_of_file_info *parm_data;
4925 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004926 __u16 params, param_offset, offset, byte_count, count;
4927
Joe Perchesb6b38f72010-04-21 03:50:45 +00004928 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4929 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004930 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4931
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 if (rc)
4933 return rc;
4934
4935 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4936 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004937
Linus Torvalds1da177e2005-04-16 15:20:36 -07004938 params = 6;
4939 pSMB->MaxSetupCount = 0;
4940 pSMB->Reserved = 0;
4941 pSMB->Flags = 0;
4942 pSMB->Timeout = 0;
4943 pSMB->Reserved2 = 0;
4944 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4945 offset = param_offset + params;
4946
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 count = sizeof(struct file_end_of_file_info);
4948 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004949 /* BB find exact max SMB PDU from sess structure BB */
4950 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 pSMB->SetupCount = 1;
4952 pSMB->Reserved3 = 0;
4953 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4954 byte_count = 3 /* pad */ + params + count;
4955 pSMB->DataCount = cpu_to_le16(count);
4956 pSMB->ParameterCount = cpu_to_le16(params);
4957 pSMB->TotalDataCount = pSMB->DataCount;
4958 pSMB->TotalParameterCount = pSMB->ParameterCount;
4959 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4960 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004961 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4962 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004963 pSMB->DataOffset = cpu_to_le16(offset);
4964 parm_data->FileSize = cpu_to_le64(size);
4965 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004966 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004967 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4968 pSMB->InformationLevel =
4969 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4970 else
4971 pSMB->InformationLevel =
4972 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004973 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004974 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4975 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004976 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977 else
4978 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004979 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980 }
4981 pSMB->Reserved4 = 0;
4982 pSMB->hdr.smb_buf_length += byte_count;
4983 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004984 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004986 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 }
4988
Steve French50c2f752007-07-13 00:33:32 +00004989 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 since file handle passed in no longer valid */
4991
4992 return rc;
4993}
4994
Steve French50c2f752007-07-13 00:33:32 +00004995/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 an open handle, rather than by pathname - this is awkward due to
4997 potential access conflicts on the open, but it is unavoidable for these
4998 old servers since the only other choice is to go from 100 nanosecond DCE
4999 time and resort to the original setpathinfo level which takes the ancient
5000 DOS time format with 2 second granularity */
5001int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005002CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5003 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004{
5005 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 char *data_offset;
5007 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 __u16 params, param_offset, offset, byte_count, count;
5009
Joe Perchesb6b38f72010-04-21 03:50:45 +00005010 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005011 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5012
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 if (rc)
5014 return rc;
5015
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005016 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5017 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005018
Linus Torvalds1da177e2005-04-16 15:20:36 -07005019 params = 6;
5020 pSMB->MaxSetupCount = 0;
5021 pSMB->Reserved = 0;
5022 pSMB->Flags = 0;
5023 pSMB->Timeout = 0;
5024 pSMB->Reserved2 = 0;
5025 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5026 offset = param_offset + params;
5027
Steve French50c2f752007-07-13 00:33:32 +00005028 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
Steve French26f57362007-08-30 22:09:15 +00005030 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005032 /* BB find max SMB PDU from sess */
5033 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005034 pSMB->SetupCount = 1;
5035 pSMB->Reserved3 = 0;
5036 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5037 byte_count = 3 /* pad */ + params + count;
5038 pSMB->DataCount = cpu_to_le16(count);
5039 pSMB->ParameterCount = cpu_to_le16(params);
5040 pSMB->TotalDataCount = pSMB->DataCount;
5041 pSMB->TotalParameterCount = pSMB->ParameterCount;
5042 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5043 pSMB->DataOffset = cpu_to_le16(offset);
5044 pSMB->Fid = fid;
5045 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5046 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5047 else
5048 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5049 pSMB->Reserved4 = 0;
5050 pSMB->hdr.smb_buf_length += byte_count;
5051 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005052 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005053 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005054 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005055 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056
Steve French50c2f752007-07-13 00:33:32 +00005057 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 since file handle passed in no longer valid */
5059
5060 return rc;
5061}
5062
Jeff Layton6d22f092008-09-23 11:48:35 -04005063int
5064CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5065 bool delete_file, __u16 fid, __u32 pid_of_opener)
5066{
5067 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5068 char *data_offset;
5069 int rc = 0;
5070 __u16 params, param_offset, offset, byte_count, count;
5071
Joe Perchesb6b38f72010-04-21 03:50:45 +00005072 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005073 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5074
5075 if (rc)
5076 return rc;
5077
5078 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5079 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5080
5081 params = 6;
5082 pSMB->MaxSetupCount = 0;
5083 pSMB->Reserved = 0;
5084 pSMB->Flags = 0;
5085 pSMB->Timeout = 0;
5086 pSMB->Reserved2 = 0;
5087 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5088 offset = param_offset + params;
5089
5090 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5091
5092 count = 1;
5093 pSMB->MaxParameterCount = cpu_to_le16(2);
5094 /* BB find max SMB PDU from sess */
5095 pSMB->MaxDataCount = cpu_to_le16(1000);
5096 pSMB->SetupCount = 1;
5097 pSMB->Reserved3 = 0;
5098 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5099 byte_count = 3 /* pad */ + params + count;
5100 pSMB->DataCount = cpu_to_le16(count);
5101 pSMB->ParameterCount = cpu_to_le16(params);
5102 pSMB->TotalDataCount = pSMB->DataCount;
5103 pSMB->TotalParameterCount = pSMB->ParameterCount;
5104 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5105 pSMB->DataOffset = cpu_to_le16(offset);
5106 pSMB->Fid = fid;
5107 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5108 pSMB->Reserved4 = 0;
5109 pSMB->hdr.smb_buf_length += byte_count;
5110 pSMB->ByteCount = cpu_to_le16(byte_count);
5111 *data_offset = delete_file ? 1 : 0;
5112 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5113 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005114 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005115
5116 return rc;
5117}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005118
5119int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005120CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5121 const char *fileName, const FILE_BASIC_INFO *data,
5122 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123{
5124 TRANSACTION2_SPI_REQ *pSMB = NULL;
5125 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5126 int name_len;
5127 int rc = 0;
5128 int bytes_returned = 0;
5129 char *data_offset;
5130 __u16 params, param_offset, offset, byte_count, count;
5131
Joe Perchesb6b38f72010-04-21 03:50:45 +00005132 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133
5134SetTimesRetry:
5135 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5136 (void **) &pSMBr);
5137 if (rc)
5138 return rc;
5139
5140 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5141 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005142 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005143 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 name_len++; /* trailing null */
5145 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005146 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 name_len = strnlen(fileName, PATH_MAX);
5148 name_len++; /* trailing null */
5149 strncpy(pSMB->FileName, fileName, name_len);
5150 }
5151
5152 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005153 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005155 /* BB find max SMB PDU from sess structure BB */
5156 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 pSMB->MaxSetupCount = 0;
5158 pSMB->Reserved = 0;
5159 pSMB->Flags = 0;
5160 pSMB->Timeout = 0;
5161 pSMB->Reserved2 = 0;
5162 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005163 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 offset = param_offset + params;
5165 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5166 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5167 pSMB->DataOffset = cpu_to_le16(offset);
5168 pSMB->SetupCount = 1;
5169 pSMB->Reserved3 = 0;
5170 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5171 byte_count = 3 /* pad */ + params + count;
5172
5173 pSMB->DataCount = cpu_to_le16(count);
5174 pSMB->ParameterCount = cpu_to_le16(params);
5175 pSMB->TotalDataCount = pSMB->DataCount;
5176 pSMB->TotalParameterCount = pSMB->ParameterCount;
5177 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5178 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5179 else
5180 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5181 pSMB->Reserved4 = 0;
5182 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005183 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 pSMB->ByteCount = cpu_to_le16(byte_count);
5185 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5186 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005187 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005188 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189
5190 cifs_buf_release(pSMB);
5191
5192 if (rc == -EAGAIN)
5193 goto SetTimesRetry;
5194
5195 return rc;
5196}
5197
5198/* Can not be used to set time stamps yet (due to old DOS time format) */
5199/* Can be used to set attributes */
5200#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5201 handling it anyway and NT4 was what we thought it would be needed for
5202 Do not delete it until we prove whether needed for Win9x though */
5203int
5204CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5205 __u16 dos_attrs, const struct nls_table *nls_codepage)
5206{
5207 SETATTR_REQ *pSMB = NULL;
5208 SETATTR_RSP *pSMBr = NULL;
5209 int rc = 0;
5210 int bytes_returned;
5211 int name_len;
5212
Joe Perchesb6b38f72010-04-21 03:50:45 +00005213 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214
5215SetAttrLgcyRetry:
5216 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5217 (void **) &pSMBr);
5218 if (rc)
5219 return rc;
5220
5221 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5222 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005223 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 PATH_MAX, nls_codepage);
5225 name_len++; /* trailing null */
5226 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005227 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 name_len = strnlen(fileName, PATH_MAX);
5229 name_len++; /* trailing null */
5230 strncpy(pSMB->fileName, fileName, name_len);
5231 }
5232 pSMB->attr = cpu_to_le16(dos_attrs);
5233 pSMB->BufferFormat = 0x04;
5234 pSMB->hdr.smb_buf_length += name_len + 1;
5235 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5237 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005238 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005239 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240
5241 cifs_buf_release(pSMB);
5242
5243 if (rc == -EAGAIN)
5244 goto SetAttrLgcyRetry;
5245
5246 return rc;
5247}
5248#endif /* temporarily unneeded SetAttr legacy function */
5249
Jeff Layton654cf142009-07-09 20:02:49 -04005250static void
5251cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5252 const struct cifs_unix_set_info_args *args)
5253{
5254 u64 mode = args->mode;
5255
5256 /*
5257 * Samba server ignores set of file size to zero due to bugs in some
5258 * older clients, but we should be precise - we use SetFileSize to
5259 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005260 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005261 * zero instead of -1 here
5262 */
5263 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5264 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5265 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5266 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5267 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5268 data_offset->Uid = cpu_to_le64(args->uid);
5269 data_offset->Gid = cpu_to_le64(args->gid);
5270 /* better to leave device as zero when it is */
5271 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5272 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5273 data_offset->Permissions = cpu_to_le64(mode);
5274
5275 if (S_ISREG(mode))
5276 data_offset->Type = cpu_to_le32(UNIX_FILE);
5277 else if (S_ISDIR(mode))
5278 data_offset->Type = cpu_to_le32(UNIX_DIR);
5279 else if (S_ISLNK(mode))
5280 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5281 else if (S_ISCHR(mode))
5282 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5283 else if (S_ISBLK(mode))
5284 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5285 else if (S_ISFIFO(mode))
5286 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5287 else if (S_ISSOCK(mode))
5288 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5289}
5290
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005292CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5293 const struct cifs_unix_set_info_args *args,
5294 u16 fid, u32 pid_of_opener)
5295{
5296 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5297 FILE_UNIX_BASIC_INFO *data_offset;
5298 int rc = 0;
5299 u16 params, param_offset, offset, byte_count, count;
5300
Joe Perchesb6b38f72010-04-21 03:50:45 +00005301 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005302 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5303
5304 if (rc)
5305 return rc;
5306
5307 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5308 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5309
5310 params = 6;
5311 pSMB->MaxSetupCount = 0;
5312 pSMB->Reserved = 0;
5313 pSMB->Flags = 0;
5314 pSMB->Timeout = 0;
5315 pSMB->Reserved2 = 0;
5316 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5317 offset = param_offset + params;
5318
5319 data_offset = (FILE_UNIX_BASIC_INFO *)
5320 ((char *)(&pSMB->hdr.Protocol) + offset);
5321 count = sizeof(FILE_UNIX_BASIC_INFO);
5322
5323 pSMB->MaxParameterCount = cpu_to_le16(2);
5324 /* BB find max SMB PDU from sess */
5325 pSMB->MaxDataCount = cpu_to_le16(1000);
5326 pSMB->SetupCount = 1;
5327 pSMB->Reserved3 = 0;
5328 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5329 byte_count = 3 /* pad */ + params + count;
5330 pSMB->DataCount = cpu_to_le16(count);
5331 pSMB->ParameterCount = cpu_to_le16(params);
5332 pSMB->TotalDataCount = pSMB->DataCount;
5333 pSMB->TotalParameterCount = pSMB->ParameterCount;
5334 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5335 pSMB->DataOffset = cpu_to_le16(offset);
5336 pSMB->Fid = fid;
5337 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5338 pSMB->Reserved4 = 0;
5339 pSMB->hdr.smb_buf_length += byte_count;
5340 pSMB->ByteCount = cpu_to_le16(byte_count);
5341
5342 cifs_fill_unix_set_info(data_offset, args);
5343
5344 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5345 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005346 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005347
5348 /* Note: On -EAGAIN error only caller can retry on handle based calls
5349 since file handle passed in no longer valid */
5350
5351 return rc;
5352}
5353
5354int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005355CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5356 const struct cifs_unix_set_info_args *args,
5357 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358{
5359 TRANSACTION2_SPI_REQ *pSMB = NULL;
5360 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5361 int name_len;
5362 int rc = 0;
5363 int bytes_returned = 0;
5364 FILE_UNIX_BASIC_INFO *data_offset;
5365 __u16 params, param_offset, offset, count, byte_count;
5366
Joe Perchesb6b38f72010-04-21 03:50:45 +00005367 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005368setPermsRetry:
5369 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5370 (void **) &pSMBr);
5371 if (rc)
5372 return rc;
5373
5374 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5375 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005376 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005377 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005378 name_len++; /* trailing null */
5379 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005380 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381 name_len = strnlen(fileName, PATH_MAX);
5382 name_len++; /* trailing null */
5383 strncpy(pSMB->FileName, fileName, name_len);
5384 }
5385
5386 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005387 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005389 /* BB find max SMB PDU from sess structure BB */
5390 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 pSMB->MaxSetupCount = 0;
5392 pSMB->Reserved = 0;
5393 pSMB->Flags = 0;
5394 pSMB->Timeout = 0;
5395 pSMB->Reserved2 = 0;
5396 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005397 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 offset = param_offset + params;
5399 data_offset =
5400 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5401 offset);
5402 memset(data_offset, 0, count);
5403 pSMB->DataOffset = cpu_to_le16(offset);
5404 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5405 pSMB->SetupCount = 1;
5406 pSMB->Reserved3 = 0;
5407 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5408 byte_count = 3 /* pad */ + params + count;
5409 pSMB->ParameterCount = cpu_to_le16(params);
5410 pSMB->DataCount = cpu_to_le16(count);
5411 pSMB->TotalParameterCount = pSMB->ParameterCount;
5412 pSMB->TotalDataCount = pSMB->DataCount;
5413 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5414 pSMB->Reserved4 = 0;
5415 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005416
Jeff Layton654cf142009-07-09 20:02:49 -04005417 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005418
5419 pSMB->ByteCount = cpu_to_le16(byte_count);
5420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005422 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005423 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
Steve French0d817bc2008-05-22 02:02:03 +00005425 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 if (rc == -EAGAIN)
5427 goto setPermsRetry;
5428 return rc;
5429}
5430
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005432/*
5433 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5434 * function used by listxattr and getxattr type calls. When ea_name is set,
5435 * it looks for that attribute name and stuffs that value into the EAData
5436 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5437 * buffer. In both cases, the return value is either the length of the
5438 * resulting data or a negative error code. If EAData is a NULL pointer then
5439 * the data isn't copied to it, but the length is returned.
5440 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441ssize_t
5442CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005443 const unsigned char *searchName, const unsigned char *ea_name,
5444 char *EAData, size_t buf_size,
5445 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446{
5447 /* BB assumes one setup word */
5448 TRANSACTION2_QPI_REQ *pSMB = NULL;
5449 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5450 int rc = 0;
5451 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005452 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005453 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005454 struct fea *temp_fea;
5455 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005456 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005457 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458
Joe Perchesb6b38f72010-04-21 03:50:45 +00005459 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460QAllEAsRetry:
5461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5462 (void **) &pSMBr);
5463 if (rc)
5464 return rc;
5465
5466 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005467 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005468 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005469 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005470 list_len++; /* trailing null */
5471 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005473 list_len = strnlen(searchName, PATH_MAX);
5474 list_len++; /* trailing null */
5475 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 }
5477
Jeff Layton6e462b92010-02-10 16:18:26 -05005478 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 pSMB->TotalDataCount = 0;
5480 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005481 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005482 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 pSMB->MaxSetupCount = 0;
5484 pSMB->Reserved = 0;
5485 pSMB->Flags = 0;
5486 pSMB->Timeout = 0;
5487 pSMB->Reserved2 = 0;
5488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005489 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 pSMB->DataCount = 0;
5491 pSMB->DataOffset = 0;
5492 pSMB->SetupCount = 1;
5493 pSMB->Reserved3 = 0;
5494 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5495 byte_count = params + 1 /* pad */ ;
5496 pSMB->TotalParameterCount = cpu_to_le16(params);
5497 pSMB->ParameterCount = pSMB->TotalParameterCount;
5498 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5499 pSMB->Reserved4 = 0;
5500 pSMB->hdr.smb_buf_length += byte_count;
5501 pSMB->ByteCount = cpu_to_le16(byte_count);
5502
5503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5505 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005506 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005507 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005509
5510
5511 /* BB also check enough total bytes returned */
5512 /* BB we need to improve the validity checking
5513 of these trans2 responses */
5514
5515 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5516 if (rc || (pSMBr->ByteCount < 4)) {
5517 rc = -EIO; /* bad smb */
5518 goto QAllEAsOut;
5519 }
5520
5521 /* check that length of list is not more than bcc */
5522 /* check that each entry does not go beyond length
5523 of list */
5524 /* check that each element of each entry does not
5525 go beyond end of list */
5526 /* validate_trans2_offsets() */
5527 /* BB check if start of smb + data_offset > &bcc+ bcc */
5528
5529 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5530 ea_response_data = (struct fealist *)
5531 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5532
Jeff Layton6e462b92010-02-10 16:18:26 -05005533 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005534 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005535 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005536 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005537 goto QAllEAsOut;
5538 }
5539
Jeff Layton0cd126b2010-02-10 16:18:26 -05005540 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005541 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005542 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005543 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005544 rc = -EIO;
5545 goto QAllEAsOut;
5546 }
5547
Jeff Laytonf0d38682010-02-10 16:18:26 -05005548 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005549 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005550 temp_fea = ea_response_data->list;
5551 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005552 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005553 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005554 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005555
Jeff Layton6e462b92010-02-10 16:18:26 -05005556 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005557 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005558 /* make sure we can read name_len and value_len */
5559 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005560 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005561 rc = -EIO;
5562 goto QAllEAsOut;
5563 }
5564
5565 name_len = temp_fea->name_len;
5566 value_len = le16_to_cpu(temp_fea->value_len);
5567 list_len -= name_len + 1 + value_len;
5568 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005569 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005570 rc = -EIO;
5571 goto QAllEAsOut;
5572 }
5573
Jeff Layton31c05192010-02-10 16:18:26 -05005574 if (ea_name) {
5575 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5576 temp_ptr += name_len + 1;
5577 rc = value_len;
5578 if (buf_size == 0)
5579 goto QAllEAsOut;
5580 if ((size_t)value_len > buf_size) {
5581 rc = -ERANGE;
5582 goto QAllEAsOut;
5583 }
5584 memcpy(EAData, temp_ptr, value_len);
5585 goto QAllEAsOut;
5586 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005587 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005588 /* account for prefix user. and trailing null */
5589 rc += (5 + 1 + name_len);
5590 if (rc < (int) buf_size) {
5591 memcpy(EAData, "user.", 5);
5592 EAData += 5;
5593 memcpy(EAData, temp_ptr, name_len);
5594 EAData += name_len;
5595 /* null terminate name */
5596 *EAData = 0;
5597 ++EAData;
5598 } else if (buf_size == 0) {
5599 /* skip copy - calc size only */
5600 } else {
5601 /* stop before overrun buffer */
5602 rc = -ERANGE;
5603 break;
5604 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005605 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005606 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005607 temp_fea = (struct fea *)temp_ptr;
5608 }
5609
Jeff Layton31c05192010-02-10 16:18:26 -05005610 /* didn't find the named attribute */
5611 if (ea_name)
5612 rc = -ENODATA;
5613
Jeff Laytonf0d38682010-02-10 16:18:26 -05005614QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005615 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 if (rc == -EAGAIN)
5617 goto QAllEAsRetry;
5618
5619 return (ssize_t)rc;
5620}
5621
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622int
5623CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005624 const char *ea_name, const void *ea_value,
5625 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5626 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627{
5628 struct smb_com_transaction2_spi_req *pSMB = NULL;
5629 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5630 struct fealist *parm_data;
5631 int name_len;
5632 int rc = 0;
5633 int bytes_returned = 0;
5634 __u16 params, param_offset, byte_count, offset, count;
5635
Joe Perchesb6b38f72010-04-21 03:50:45 +00005636 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637SetEARetry:
5638 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5639 (void **) &pSMBr);
5640 if (rc)
5641 return rc;
5642
5643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5644 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005645 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005646 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 name_len++; /* trailing null */
5648 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005649 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 name_len = strnlen(fileName, PATH_MAX);
5651 name_len++; /* trailing null */
5652 strncpy(pSMB->FileName, fileName, name_len);
5653 }
5654
5655 params = 6 + name_len;
5656
5657 /* done calculating parms using name_len of file name,
5658 now use name_len to calculate length of ea name
5659 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005660 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 name_len = 0;
5662 else
Steve French50c2f752007-07-13 00:33:32 +00005663 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005665 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005667 /* BB find max SMB PDU from sess */
5668 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 pSMB->MaxSetupCount = 0;
5670 pSMB->Reserved = 0;
5671 pSMB->Flags = 0;
5672 pSMB->Timeout = 0;
5673 pSMB->Reserved2 = 0;
5674 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005675 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 offset = param_offset + params;
5677 pSMB->InformationLevel =
5678 cpu_to_le16(SMB_SET_FILE_EA);
5679
5680 parm_data =
5681 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5682 offset);
5683 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5684 pSMB->DataOffset = cpu_to_le16(offset);
5685 pSMB->SetupCount = 1;
5686 pSMB->Reserved3 = 0;
5687 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5688 byte_count = 3 /* pad */ + params + count;
5689 pSMB->DataCount = cpu_to_le16(count);
5690 parm_data->list_len = cpu_to_le32(count);
5691 parm_data->list[0].EA_flags = 0;
5692 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005693 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005695 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005696 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697 parm_data->list[0].name[name_len] = 0;
5698 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5699 /* caller ensures that ea_value_len is less than 64K but
5700 we need to ensure that it fits within the smb */
5701
Steve French50c2f752007-07-13 00:33:32 +00005702 /*BB add length check to see if it would fit in
5703 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005704 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5705 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005706 memcpy(parm_data->list[0].name+name_len+1,
5707 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708
5709 pSMB->TotalDataCount = pSMB->DataCount;
5710 pSMB->ParameterCount = cpu_to_le16(params);
5711 pSMB->TotalParameterCount = pSMB->ParameterCount;
5712 pSMB->Reserved4 = 0;
5713 pSMB->hdr.smb_buf_length += byte_count;
5714 pSMB->ByteCount = cpu_to_le16(byte_count);
5715 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5716 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005717 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005718 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719
5720 cifs_buf_release(pSMB);
5721
5722 if (rc == -EAGAIN)
5723 goto SetEARetry;
5724
5725 return rc;
5726}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727#endif
Steve French0eff0e22011-02-24 05:39:23 +00005728
5729#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5730/*
5731 * Years ago the kernel added a "dnotify" function for Samba server,
5732 * to allow network clients (such as Windows) to display updated
5733 * lists of files in directory listings automatically when
5734 * files are added by one user when another user has the
5735 * same directory open on their desktop. The Linux cifs kernel
5736 * client hooked into the kernel side of this interface for
5737 * the same reason, but ironically when the VFS moved from
5738 * "dnotify" to "inotify" it became harder to plug in Linux
5739 * network file system clients (the most obvious use case
5740 * for notify interfaces is when multiple users can update
5741 * the contents of the same directory - exactly what network
5742 * file systems can do) although the server (Samba) could
5743 * still use it. For the short term we leave the worker
5744 * function ifdeffed out (below) until inotify is fixed
5745 * in the VFS to make it easier to plug in network file
5746 * system clients. If inotify turns out to be permanently
5747 * incompatible for network fs clients, we could instead simply
5748 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
5749 */
5750int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5751 const int notify_subdirs, const __u16 netfid,
5752 __u32 filter, struct file *pfile, int multishot,
5753 const struct nls_table *nls_codepage)
5754{
5755 int rc = 0;
5756 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5757 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
5758 struct dir_notify_req *dnotify_req;
5759 int bytes_returned;
5760
5761 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
5762 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5763 (void **) &pSMBr);
5764 if (rc)
5765 return rc;
5766
5767 pSMB->TotalParameterCount = 0 ;
5768 pSMB->TotalDataCount = 0;
5769 pSMB->MaxParameterCount = cpu_to_le32(2);
5770 /* BB find exact data count max from sess structure BB */
5771 pSMB->MaxDataCount = 0; /* same in little endian or be */
5772/* BB VERIFY verify which is correct for above BB */
5773 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5774 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5775
5776 pSMB->MaxSetupCount = 4;
5777 pSMB->Reserved = 0;
5778 pSMB->ParameterOffset = 0;
5779 pSMB->DataCount = 0;
5780 pSMB->DataOffset = 0;
5781 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5782 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5783 pSMB->ParameterCount = pSMB->TotalParameterCount;
5784 if (notify_subdirs)
5785 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5786 pSMB->Reserved2 = 0;
5787 pSMB->CompletionFilter = cpu_to_le32(filter);
5788 pSMB->Fid = netfid; /* file handle always le */
5789 pSMB->ByteCount = 0;
5790
5791 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5792 (struct smb_hdr *)pSMBr, &bytes_returned,
5793 CIFS_ASYNC_OP);
5794 if (rc) {
5795 cFYI(1, "Error in Notify = %d", rc);
5796 } else {
5797 /* Add file to outstanding requests */
5798 /* BB change to kmem cache alloc */
5799 dnotify_req = kmalloc(
5800 sizeof(struct dir_notify_req),
5801 GFP_KERNEL);
5802 if (dnotify_req) {
5803 dnotify_req->Pid = pSMB->hdr.Pid;
5804 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5805 dnotify_req->Mid = pSMB->hdr.Mid;
5806 dnotify_req->Tid = pSMB->hdr.Tid;
5807 dnotify_req->Uid = pSMB->hdr.Uid;
5808 dnotify_req->netfid = netfid;
5809 dnotify_req->pfile = pfile;
5810 dnotify_req->filter = filter;
5811 dnotify_req->multishot = multishot;
5812 spin_lock(&GlobalMid_Lock);
5813 list_add_tail(&dnotify_req->lhead,
5814 &GlobalDnotifyReqList);
5815 spin_unlock(&GlobalMid_Lock);
5816 } else
5817 rc = -ENOMEM;
5818 }
5819 cifs_buf_release(pSMB);
5820 return rc;
5821}
5822#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */