blob: a80f7bd97b90d541e9305d7e225c708f3f0cd3d1 [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>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include "cifspdu.h"
38#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000039#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "cifsproto.h"
41#include "cifs_unicode.h"
42#include "cifs_debug.h"
43
44#ifdef CONFIG_CIFS_POSIX
45static struct {
46 int index;
47 char *name;
48} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000049#ifdef CONFIG_CIFS_WEAK_PW_HASH
50 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000051 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000052#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000053 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000054 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 {BAD_PROT, "\2"}
56};
57#else
58static struct {
59 int index;
60 char *name;
61} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000062#ifdef CONFIG_CIFS_WEAK_PW_HASH
63 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000064 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000065#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000066 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 {BAD_PROT, "\2"}
68};
69#endif
70
Steve French39798772006-05-31 22:40:51 +000071/* define the number of elements in the cifs dialect array */
72#ifdef CONFIG_CIFS_POSIX
73#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000074#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000075#else
76#define CIFS_NUM_PROT 2
77#endif /* CIFS_WEAK_PW_HASH */
78#else /* not posix */
79#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000080#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000081#else
82#define CIFS_NUM_PROT 1
83#endif /* CONFIG_CIFS_WEAK_PW_HASH */
84#endif /* CIFS_POSIX */
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086/* Mark as invalid, all open files on tree connections since they
87 were closed when session to server was lost */
Steve French96daf2b2011-05-27 04:34:02 +000088static void mark_open_files_invalid(struct cifs_tcon *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
90 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000091 struct list_head *tmp;
92 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -040095 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000097 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000098 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040099 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 }
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
Jeff Layton9162ab22009-09-03 12:07:17 -0400106/* reconnect the socket, tcon, and smb session if needed */
107static int
Steve French96daf2b2011-05-27 04:34:02 +0000108cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400109{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400110 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000111 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400112 struct TCP_Server_Info *server;
113 struct nls_table *nls_codepage;
114
115 /*
116 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
117 * tcp and smb session status done differently for those three - in the
118 * calling routine
119 */
120 if (!tcon)
121 return 0;
122
123 ses = tcon->ses;
124 server = ses->server;
125
126 /*
127 * only tree disconnect, open, and write, (and ulogoff which does not
128 * have tcon) are allowed as we start force umount
129 */
130 if (tcon->tidStatus == CifsExiting) {
131 if (smb_command != SMB_COM_WRITE_ANDX &&
132 smb_command != SMB_COM_OPEN_ANDX &&
133 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000134 cFYI(1, "can not send cmd %d while umounting",
135 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400136 return -ENODEV;
137 }
138 }
139
Jeff Layton9162ab22009-09-03 12:07:17 -0400140 /*
141 * Give demultiplex thread up to 10 seconds to reconnect, should be
142 * greater than cifs socket timeout which is 7 seconds
143 */
144 while (server->tcpStatus == CifsNeedReconnect) {
145 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000146 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400147
Steve Frenchfd88ce92011-04-12 01:01:14 +0000148 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400149 if (server->tcpStatus != CifsNeedReconnect)
150 break;
151
152 /*
153 * on "soft" mounts we wait once. Hard mounts keep
154 * retrying until process is killed or server comes
155 * back on-line
156 */
Jeff Laytond4025392011-02-07 08:54:35 -0500157 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000158 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400159 return -EHOSTDOWN;
160 }
161 }
162
163 if (!ses->need_reconnect && !tcon->need_reconnect)
164 return 0;
165
166 nls_codepage = load_nls_default();
167
168 /*
169 * need to prevent multiple threads trying to simultaneously
170 * reconnect the same SMB session
171 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000172 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400173 rc = cifs_negotiate_protocol(0, ses);
174 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400175 rc = cifs_setup_session(0, ses, nls_codepage);
176
177 /* do we need to reconnect tcon? */
178 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000179 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400180 goto out;
181 }
182
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000185 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000186 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400187
188 if (rc)
189 goto out;
190
191 /*
192 * FIXME: check if wsize needs updated due to negotiated smb buffer
193 * size shrinking
194 */
195 atomic_inc(&tconInfoReconnectCount);
196
197 /* tell server Unix caps we support */
198 if (ses->capabilities & CAP_UNIX)
199 reset_cifs_unix_caps(0, tcon, NULL, NULL);
200
201 /*
202 * Removed call to reopen open files here. It is safer (and faster) to
203 * reopen files one at a time as needed in read and write.
204 *
205 * FIXME: what about file locks? don't we need to reclaim them ASAP?
206 */
207
208out:
209 /*
210 * Check if handle based operation so we know whether we can continue
211 * or not without returning to caller to reset file handle
212 */
213 switch (smb_command) {
214 case SMB_COM_READ_ANDX:
215 case SMB_COM_WRITE_ANDX:
216 case SMB_COM_CLOSE:
217 case SMB_COM_FIND_CLOSE2:
218 case SMB_COM_LOCKING_ANDX:
219 rc = -EAGAIN;
220 }
221
222 unload_nls(nls_codepage);
223 return rc;
224}
225
Steve Frenchad7a2922008-02-07 23:25:02 +0000226/* Allocate and return pointer to an SMB request buffer, and set basic
227 SMB information in the SMB header. If the return code is zero, this
228 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229static int
Steve French96daf2b2011-05-27 04:34:02 +0000230small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000231 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
Jeff Laytonf5695992010-09-29 15:27:08 -0400233 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Jeff Layton9162ab22009-09-03 12:07:17 -0400235 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000236 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return rc;
238
239 *request_buf = cifs_small_buf_get();
240 if (*request_buf == NULL) {
241 /* BB should we add a retry in here if not a writepage? */
242 return -ENOMEM;
243 }
244
Steve French63135e02007-07-17 17:34:02 +0000245 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000246 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Steve French790fe572007-07-07 19:25:05 +0000248 if (tcon != NULL)
249 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700250
Jeff Laytonf5695992010-09-29 15:27:08 -0400251 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000252}
253
Steve French12b3b8f2006-02-09 21:12:47 +0000254int
Steve French50c2f752007-07-13 00:33:32 +0000255small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000256 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000257{
258 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000259 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000260
Steve French5815449d2006-02-14 01:36:20 +0000261 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000262 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000263 return rc;
264
Steve French04fdabe2006-02-10 05:52:50 +0000265 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000266 buffer->Mid = GetNextMid(ses->server);
267 if (ses->capabilities & CAP_UNICODE)
268 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000269 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000270 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
271
272 /* uid, tid can stay at zero as set in header assemble */
273
Steve French50c2f752007-07-13 00:33:32 +0000274 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000275 this function is used after 1st of session setup requests */
276
277 return rc;
278}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280/* If the return code is zero, this function must fill in request_buf pointer */
281static int
Steve French96daf2b2011-05-27 04:34:02 +0000282__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400283 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 *request_buf = cifs_buf_get();
286 if (*request_buf == NULL) {
287 /* BB should we add a retry in here if not a writepage? */
288 return -ENOMEM;
289 }
290 /* Although the original thought was we needed the response buf for */
291 /* potential retries of smb operations it turns out we can determine */
292 /* from the mid flags when the request buffer can be resent without */
293 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000294 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000295 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000298 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Steve French790fe572007-07-07 19:25:05 +0000300 if (tcon != NULL)
301 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700302
Jeff Laytonf5695992010-09-29 15:27:08 -0400303 return 0;
304}
305
306/* If the return code is zero, this function must fill in request_buf pointer */
307static int
Steve French96daf2b2011-05-27 04:34:02 +0000308smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400309 void **request_buf, void **response_buf)
310{
311 int rc;
312
313 rc = cifs_reconnect_tcon(tcon, smb_command);
314 if (rc)
315 return rc;
316
317 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
318}
319
320static int
Steve French96daf2b2011-05-27 04:34:02 +0000321smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400322 void **request_buf, void **response_buf)
323{
324 if (tcon->ses->need_reconnect || tcon->need_reconnect)
325 return -EHOSTDOWN;
326
327 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328}
329
Steve French50c2f752007-07-13 00:33:32 +0000330static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
Jeff Layton12df83c2011-01-20 13:36:51 -0500332 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jeff Layton12df83c2011-01-20 13:36:51 -0500334 /* check for plausible wct */
335 if (pSMB->hdr.WordCount < 10)
336 goto vt2_err;
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500339 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
340 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
341 goto vt2_err;
342
Jeff Layton12df83c2011-01-20 13:36:51 -0500343 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
344 if (total_size >= 512)
345 goto vt2_err;
346
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400347 /* check that bcc is at least as big as parms + data, and that it is
348 * less than negotiated smb buffer
349 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500350 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
351 if (total_size > get_bcc(&pSMB->hdr) ||
352 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
353 goto vt2_err;
354
355 return 0;
356vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000357 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500359 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
Jeff Layton690c5222011-01-20 13:36:51 -0500361
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000362static inline void inc_rfc1001_len(void *pSMB, int count)
363{
364 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
365
366 be32_add_cpu(&hdr->smb_buf_length, count);
367}
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369int
Steve French96daf2b2011-05-27 04:34:02 +0000370CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372 NEGOTIATE_REQ *pSMB;
373 NEGOTIATE_RSP *pSMBr;
374 int rc = 0;
375 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000376 int i;
Steve French50c2f752007-07-13 00:33:32 +0000377 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000379 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Steve French790fe572007-07-07 19:25:05 +0000381 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 server = ses->server;
383 else {
384 rc = -EIO;
385 return rc;
386 }
387 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
388 (void **) &pSMB, (void **) &pSMBr);
389 if (rc)
390 return rc;
Steve French750d1152006-06-27 06:28:30 +0000391
392 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000393 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000394 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000395 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400396 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000397
Joe Perchesb6b38f72010-04-21 03:50:45 +0000398 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000399
Steve French1982c342005-08-17 12:38:22 -0700400 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000401 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000402
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000403 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000404 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000405 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000406 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000407 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500408 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000409 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
410 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000411 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000412 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
413 }
Steve French50c2f752007-07-13 00:33:32 +0000414
Steve French39798772006-05-31 22:40:51 +0000415 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000416 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000417 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
418 count += strlen(protocols[i].name) + 1;
419 /* null at end of source and target buffers anyway */
420 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000421 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 pSMB->ByteCount = cpu_to_le16(count);
423
424 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000426 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000427 goto neg_err_exit;
428
Jeff Layton9bf67e52010-04-24 07:57:46 -0400429 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
430 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000431 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400432 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000433 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000434 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000435 could not negotiate a common dialect */
436 rc = -EOPNOTSUPP;
437 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000438#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000439 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400440 && ((server->dialect == LANMAN_PROT)
441 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000442 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000443 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000444
Steve French790fe572007-07-07 19:25:05 +0000445 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000446 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000447 server->secType = LANMAN;
448 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000449 cERROR(1, "mount failed weak security disabled"
450 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000453 }
Steve French96daf2b2011-05-27 04:34:02 +0000454 server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
Steve French254e55e2006-06-04 05:53:15 +0000455 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
456 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000457 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000458 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000459 /* even though we do not use raw we might as well set this
460 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000461 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000462 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000463 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
464 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE;
467 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000468 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000469 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000470 /* OS/2 often does not set timezone therefore
471 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000472 * Could deviate slightly from the right zone.
473 * Smallest defined timezone difference is 15 minutes
474 * (i.e. Nepal). Rounding up/down is done to match
475 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000476 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000477 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000478 struct timespec ts, utc;
479 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400480 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
481 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000482 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000483 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000484 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000485 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000486 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000487 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000488 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000489 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000490 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000491 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000492 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000493 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000494 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000495 server->timeAdj = (int)tmp;
496 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000497 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000498 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000499
Steve French39798772006-05-31 22:40:51 +0000500
Steve French254e55e2006-06-04 05:53:15 +0000501 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000502 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000503
Steve French50c2f752007-07-13 00:33:32 +0000504 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500506 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000507 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000508 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000509 rc = -EIO; /* need cryptkey unless plain text */
510 goto neg_err_exit;
511 }
Steve French39798772006-05-31 22:40:51 +0000512
Steve Frenchf19159d2010-04-21 04:12:10 +0000513 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000514 /* we will not end up setting signing flags - as no signing
515 was in LANMAN and server did not return the flags on */
516 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000517#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000518 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000519 cERROR(1, "mount failed, cifs module not built "
520 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300521 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000522#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000523 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000524 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000525 /* unknown wct */
526 rc = -EOPNOTSUPP;
527 goto neg_err_exit;
528 }
529 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000530 server->sec_mode = pSMBr->SecurityMode;
531 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000532 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000533
Steve French96daf2b2011-05-27 04:34:02 +0000534 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000535#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000536 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000537#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000538 cERROR(1, "Server requests plain text password"
539 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000540
Steve French790fe572007-07-07 19:25:05 +0000541 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000542 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000543 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000544 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000545 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000546 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000547 else if (secFlags & CIFSSEC_MAY_KRB5)
548 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000549 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000550 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000551 else if (secFlags & CIFSSEC_MAY_LANMAN)
552 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000553 else {
554 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000555 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000556 goto neg_err_exit;
557 }
558 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000559
Steve French254e55e2006-06-04 05:53:15 +0000560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
562 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
563 /* probably no need to store and check maxvcs */
564 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000566 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000567 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000568 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000569 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
570 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000571 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500572 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000573 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000574 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
575 server->capabilities & CAP_EXTENDED_SECURITY) &&
576 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000577 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400578 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000579 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000581 goto neg_err_exit;
582 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530583 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500584 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530585 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000586 if (memcmp(server->server_GUID,
587 pSMBr->u.extended_response.
588 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000589 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000590 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000591 pSMBr->u.extended_response.GUID,
592 16);
593 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500594 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530595 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000596 memcpy(server->server_GUID,
597 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 }
Jeff Laytone187e442007-10-16 17:10:44 +0000599
600 if (count == 16) {
601 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000602 } else {
603 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400604 SecurityBlob, count - 16,
605 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000606 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000607 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000608 else
Steve French254e55e2006-06-04 05:53:15 +0000609 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500610 if (server->secType == Kerberos) {
611 if (!server->sec_kerberos &&
612 !server->sec_mskerberos)
613 rc = -EOPNOTSUPP;
614 } else if (server->secType == RawNTLMSSP) {
615 if (!server->sec_ntlmssp)
616 rc = -EOPNOTSUPP;
617 } else
618 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
Steve French96daf2b2011-05-27 04:34:02 +0000620 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000621 rc = -EIO; /* no crypt key only if plain text pwd */
622 goto neg_err_exit;
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 French96daf2b2011-05-27 04:34:02 +0000633 if (server->sec_mode & 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 French96daf2b2011-05-27 04:34:02 +0000639 server->sec_mode &=
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 French96daf2b2011-05-27 04:34:02 +0000644 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000645 (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
Steve French96daf2b2011-05-27 04:34:02 +0000649 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000650 } else {
651 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000652 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
653 server->sec_mode &=
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
Steve French96daf2b2011-05-27 04:34:02 +0000665CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
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;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400724 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725
726 cFYI(1, "In echo request");
727
728 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
729 if (rc)
730 return rc;
731
732 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000733 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500734 smb->hdr.WordCount = 1;
735 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400736 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000738 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400739 iov.iov_base = smb;
740 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741
Jeff Layton59ffd842011-05-19 16:22:55 -0400742 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500743 if (rc)
744 cFYI(1, "Echo request failed: %d", rc);
745
746 cifs_small_buf_release(smb);
747
748 return rc;
749}
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751int
Steve French96daf2b2011-05-27 04:34:02 +0000752CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 LOGOFF_ANDX_REQ *pSMB;
755 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Joe Perchesb6b38f72010-04-21 03:50:45 +0000757 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500758
759 /*
760 * BB: do we need to check validity of ses and server? They should
761 * always be valid since we have an active reference. If not, that
762 * should probably be a BUG()
763 */
764 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return -EIO;
766
Steve Frenchd7b619c2010-02-25 05:36:46 +0000767 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000768 if (ses->need_reconnect)
769 goto session_already_dead; /* no need to send SMBlogoff if uid
770 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
772 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000773 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return rc;
775 }
776
Steve French3b795212008-11-13 19:45:32 +0000777 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700778
Steve French96daf2b2011-05-27 04:34:02 +0000779 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
781 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 pSMB->hdr.Uid = ses->Suid;
784
785 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000786 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000787session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000788 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000791 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 error */
793 if (rc == -EAGAIN)
794 rc = 0;
795 return rc;
796}
797
798int
Steve French96daf2b2011-05-27 04:34:02 +0000799CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000800 __u16 type, const struct nls_table *nls_codepage, int remap)
801{
802 TRANSACTION2_SPI_REQ *pSMB = NULL;
803 TRANSACTION2_SPI_RSP *pSMBr = NULL;
804 struct unlink_psx_rq *pRqD;
805 int name_len;
806 int rc = 0;
807 int bytes_returned = 0;
808 __u16 params, param_offset, offset, byte_count;
809
Joe Perchesb6b38f72010-04-21 03:50:45 +0000810 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000811PsxDelete:
812 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
813 (void **) &pSMBr);
814 if (rc)
815 return rc;
816
817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
818 name_len =
819 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
820 PATH_MAX, nls_codepage, remap);
821 name_len++; /* trailing null */
822 name_len *= 2;
823 } else { /* BB add path length overrun check */
824 name_len = strnlen(fileName, PATH_MAX);
825 name_len++; /* trailing null */
826 strncpy(pSMB->FileName, fileName, name_len);
827 }
828
829 params = 6 + name_len;
830 pSMB->MaxParameterCount = cpu_to_le16(2);
831 pSMB->MaxDataCount = 0; /* BB double check this with jra */
832 pSMB->MaxSetupCount = 0;
833 pSMB->Reserved = 0;
834 pSMB->Flags = 0;
835 pSMB->Timeout = 0;
836 pSMB->Reserved2 = 0;
837 param_offset = offsetof(struct smb_com_transaction2_spi_req,
838 InformationLevel) - 4;
839 offset = param_offset + params;
840
841 /* Setup pointer to Request Data (inode type) */
842 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
843 pRqD->type = cpu_to_le16(type);
844 pSMB->ParameterOffset = cpu_to_le16(param_offset);
845 pSMB->DataOffset = cpu_to_le16(offset);
846 pSMB->SetupCount = 1;
847 pSMB->Reserved3 = 0;
848 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
849 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
850
851 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
852 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
853 pSMB->ParameterCount = cpu_to_le16(params);
854 pSMB->TotalParameterCount = pSMB->ParameterCount;
855 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
856 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000857 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000858 pSMB->ByteCount = cpu_to_le16(byte_count);
859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000861 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000862 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000863 cifs_buf_release(pSMB);
864
865 cifs_stats_inc(&tcon->num_deletes);
866
867 if (rc == -EAGAIN)
868 goto PsxDelete;
869
870 return rc;
871}
872
873int
Steve French96daf2b2011-05-27 04:34:02 +0000874CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700875 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
877 DELETE_FILE_REQ *pSMB = NULL;
878 DELETE_FILE_RSP *pSMBr = NULL;
879 int rc = 0;
880 int bytes_returned;
881 int name_len;
882
883DelFileRetry:
884 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
888
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
890 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000891 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 name_len++; /* trailing null */
894 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700895 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 name_len = strnlen(fileName, PATH_MAX);
897 name_len++; /* trailing null */
898 strncpy(pSMB->fileName, fileName, name_len);
899 }
900 pSMB->SearchAttributes =
901 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
902 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000903 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 pSMB->ByteCount = cpu_to_le16(name_len + 1);
905 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
906 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700907 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000908 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000909 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 cifs_buf_release(pSMB);
912 if (rc == -EAGAIN)
913 goto DelFileRetry;
914
915 return rc;
916}
917
918int
Steve French96daf2b2011-05-27 04:34:02 +0000919CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700920 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
922 DELETE_DIRECTORY_REQ *pSMB = NULL;
923 DELETE_DIRECTORY_RSP *pSMBr = NULL;
924 int rc = 0;
925 int bytes_returned;
926 int name_len;
927
Joe Perchesb6b38f72010-04-21 03:50:45 +0000928 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929RmDirRetry:
930 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
931 (void **) &pSMBr);
932 if (rc)
933 return rc;
934
935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700936 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
937 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 name_len++; /* trailing null */
939 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700940 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 name_len = strnlen(dirName, PATH_MAX);
942 name_len++; /* trailing null */
943 strncpy(pSMB->DirName, dirName, name_len);
944 }
945
946 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000947 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 pSMB->ByteCount = cpu_to_le16(name_len + 1);
949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
950 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700951 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000952 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000953 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 cifs_buf_release(pSMB);
956 if (rc == -EAGAIN)
957 goto RmDirRetry;
958 return rc;
959}
960
961int
Steve French96daf2b2011-05-27 04:34:02 +0000962CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700963 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
965 int rc = 0;
966 CREATE_DIRECTORY_REQ *pSMB = NULL;
967 CREATE_DIRECTORY_RSP *pSMBr = NULL;
968 int bytes_returned;
969 int name_len;
970
Joe Perchesb6b38f72010-04-21 03:50:45 +0000971 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972MkDirRetry:
973 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
974 (void **) &pSMBr);
975 if (rc)
976 return rc;
977
978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000979 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700980 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 name_len++; /* trailing null */
982 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700983 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 name_len = strnlen(name, PATH_MAX);
985 name_len++; /* trailing null */
986 strncpy(pSMB->DirName, name, name_len);
987 }
988
989 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000990 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 pSMB->ByteCount = cpu_to_le16(name_len + 1);
992 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
993 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700994 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000995 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000996 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700997
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 cifs_buf_release(pSMB);
999 if (rc == -EAGAIN)
1000 goto MkDirRetry;
1001 return rc;
1002}
1003
Steve French2dd29d32007-04-23 22:07:35 +00001004int
Steve French96daf2b2011-05-27 04:34:02 +00001005CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001006 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001007 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001008 const struct nls_table *nls_codepage, int remap)
1009{
1010 TRANSACTION2_SPI_REQ *pSMB = NULL;
1011 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1012 int name_len;
1013 int rc = 0;
1014 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001015 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001016 OPEN_PSX_REQ *pdata;
1017 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001018
Joe Perchesb6b38f72010-04-21 03:50:45 +00001019 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001020PsxCreat:
1021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1022 (void **) &pSMBr);
1023 if (rc)
1024 return rc;
1025
1026 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1027 name_len =
1028 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1029 PATH_MAX, nls_codepage, remap);
1030 name_len++; /* trailing null */
1031 name_len *= 2;
1032 } else { /* BB improve the check for buffer overruns BB */
1033 name_len = strnlen(name, PATH_MAX);
1034 name_len++; /* trailing null */
1035 strncpy(pSMB->FileName, name, name_len);
1036 }
1037
1038 params = 6 + name_len;
1039 count = sizeof(OPEN_PSX_REQ);
1040 pSMB->MaxParameterCount = cpu_to_le16(2);
1041 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1042 pSMB->MaxSetupCount = 0;
1043 pSMB->Reserved = 0;
1044 pSMB->Flags = 0;
1045 pSMB->Timeout = 0;
1046 pSMB->Reserved2 = 0;
1047 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001048 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001049 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001050 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001051 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001052 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001053 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001054 pdata->OpenFlags = cpu_to_le32(*pOplock);
1055 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1056 pSMB->DataOffset = cpu_to_le16(offset);
1057 pSMB->SetupCount = 1;
1058 pSMB->Reserved3 = 0;
1059 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1060 byte_count = 3 /* pad */ + params + count;
1061
1062 pSMB->DataCount = cpu_to_le16(count);
1063 pSMB->ParameterCount = cpu_to_le16(params);
1064 pSMB->TotalDataCount = pSMB->DataCount;
1065 pSMB->TotalParameterCount = pSMB->ParameterCount;
1066 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1067 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001068 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001069 pSMB->ByteCount = cpu_to_le16(byte_count);
1070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1072 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001073 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001074 goto psx_create_err;
1075 }
1076
Joe Perchesb6b38f72010-04-21 03:50:45 +00001077 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001078 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1079
Jeff Layton820a8032011-05-04 08:05:26 -04001080 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001081 rc = -EIO; /* bad smb */
1082 goto psx_create_err;
1083 }
1084
1085 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001086 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001087 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001088
Steve French2dd29d32007-04-23 22:07:35 +00001089 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001090 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001091 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1092 /* Let caller know file was created so we can set the mode. */
1093 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001094 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001095 *pOplock |= CIFS_CREATE_ACTION;
1096 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001097 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1098 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001099 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001100 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001101 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001102 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001103 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001104 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001105 goto psx_create_err;
1106 }
Steve French50c2f752007-07-13 00:33:32 +00001107 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001108 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001109 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001110 }
Steve French2dd29d32007-04-23 22:07:35 +00001111
1112psx_create_err:
1113 cifs_buf_release(pSMB);
1114
Steve French65bc98b2009-07-10 15:27:25 +00001115 if (posix_flags & SMB_O_DIRECTORY)
1116 cifs_stats_inc(&tcon->num_posixmkdirs);
1117 else
1118 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001119
1120 if (rc == -EAGAIN)
1121 goto PsxCreat;
1122
Steve French50c2f752007-07-13 00:33:32 +00001123 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001124}
1125
Steve Frencha9d02ad2005-08-24 23:06:05 -07001126static __u16 convert_disposition(int disposition)
1127{
1128 __u16 ofun = 0;
1129
1130 switch (disposition) {
1131 case FILE_SUPERSEDE:
1132 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1133 break;
1134 case FILE_OPEN:
1135 ofun = SMBOPEN_OAPPEND;
1136 break;
1137 case FILE_CREATE:
1138 ofun = SMBOPEN_OCREATE;
1139 break;
1140 case FILE_OPEN_IF:
1141 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1142 break;
1143 case FILE_OVERWRITE:
1144 ofun = SMBOPEN_OTRUNC;
1145 break;
1146 case FILE_OVERWRITE_IF:
1147 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1148 break;
1149 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001150 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001151 ofun = SMBOPEN_OAPPEND; /* regular open */
1152 }
1153 return ofun;
1154}
1155
Jeff Layton35fc37d2008-05-14 10:22:03 -07001156static int
1157access_flags_to_smbopen_mode(const int access_flags)
1158{
1159 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1160
1161 if (masked_flags == GENERIC_READ)
1162 return SMBOPEN_READ;
1163 else if (masked_flags == GENERIC_WRITE)
1164 return SMBOPEN_WRITE;
1165
1166 /* just go for read/write */
1167 return SMBOPEN_READWRITE;
1168}
1169
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170int
Steve French96daf2b2011-05-27 04:34:02 +00001171SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001172 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001173 const int access_flags, const int create_options, __u16 *netfid,
1174 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175 const struct nls_table *nls_codepage, int remap)
1176{
1177 int rc = -EACCES;
1178 OPENX_REQ *pSMB = NULL;
1179 OPENX_RSP *pSMBr = NULL;
1180 int bytes_returned;
1181 int name_len;
1182 __u16 count;
1183
1184OldOpenRetry:
1185 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1186 (void **) &pSMBr);
1187 if (rc)
1188 return rc;
1189
1190 pSMB->AndXCommand = 0xFF; /* none */
1191
1192 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1193 count = 1; /* account for one byte pad to word boundary */
1194 name_len =
1195 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1196 fileName, PATH_MAX, nls_codepage, remap);
1197 name_len++; /* trailing null */
1198 name_len *= 2;
1199 } else { /* BB improve check for buffer overruns BB */
1200 count = 0; /* no pad */
1201 name_len = strnlen(fileName, PATH_MAX);
1202 name_len++; /* trailing null */
1203 strncpy(pSMB->fileName, fileName, name_len);
1204 }
1205 if (*pOplock & REQ_OPLOCK)
1206 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001207 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001209
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001211 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1213 /* set file as system file if special file such
1214 as fifo and server expecting SFU style and
1215 no Unix extensions */
1216
Steve French790fe572007-07-07 19:25:05 +00001217 if (create_options & CREATE_OPTION_SPECIAL)
1218 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001219 else /* BB FIXME BB */
1220 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221
Jeff Layton67750fb2008-05-09 22:28:02 +00001222 if (create_options & CREATE_OPTION_READONLY)
1223 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001224
1225 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001226/* pSMB->CreateOptions = cpu_to_le32(create_options &
1227 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001229
1230 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001231 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001233 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
1235 pSMB->ByteCount = cpu_to_le16(count);
1236 /* long_op set to 1 to allow for oplock break timeouts */
1237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001238 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 cifs_stats_inc(&tcon->num_opens);
1240 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001241 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 } else {
1243 /* BB verify if wct == 15 */
1244
Steve French582d21e2008-05-13 04:54:12 +00001245/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246
1247 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1248 /* Let caller know file was created so we can set the mode. */
1249 /* Do we care about the CreateAction in any other cases? */
1250 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001251/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 *pOplock |= CIFS_CREATE_ACTION; */
1253 /* BB FIXME END */
1254
Steve French790fe572007-07-07 19:25:05 +00001255 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1257 pfile_info->LastAccessTime = 0; /* BB fixme */
1258 pfile_info->LastWriteTime = 0; /* BB fixme */
1259 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001260 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001261 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001263 pfile_info->AllocationSize =
1264 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1265 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001267 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 }
1269 }
1270
1271 cifs_buf_release(pSMB);
1272 if (rc == -EAGAIN)
1273 goto OldOpenRetry;
1274 return rc;
1275}
1276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277int
Steve French96daf2b2011-05-27 04:34:02 +00001278CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001280 const int access_flags, const int create_options, __u16 *netfid,
1281 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001282 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283{
1284 int rc = -EACCES;
1285 OPEN_REQ *pSMB = NULL;
1286 OPEN_RSP *pSMBr = NULL;
1287 int bytes_returned;
1288 int name_len;
1289 __u16 count;
1290
1291openRetry:
1292 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1293 (void **) &pSMBr);
1294 if (rc)
1295 return rc;
1296
1297 pSMB->AndXCommand = 0xFF; /* none */
1298
1299 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1300 count = 1; /* account for one byte pad to word boundary */
1301 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001302 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001303 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 name_len++; /* trailing null */
1305 name_len *= 2;
1306 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001307 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 count = 0; /* no pad */
1309 name_len = strnlen(fileName, PATH_MAX);
1310 name_len++; /* trailing null */
1311 pSMB->NameLength = cpu_to_le16(name_len);
1312 strncpy(pSMB->fileName, fileName, name_len);
1313 }
1314 if (*pOplock & REQ_OPLOCK)
1315 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001316 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1319 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001320 /* set file as system file if special file such
1321 as fifo and server expecting SFU style and
1322 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001323 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001324 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1325 else
1326 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 /* XP does not handle ATTR_POSIX_SEMANTICS */
1329 /* but it helps speed up case sensitive checks for other
1330 servers such as Samba */
1331 if (tcon->ses->capabilities & CAP_UNIX)
1332 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1333
Jeff Layton67750fb2008-05-09 22:28:02 +00001334 if (create_options & CREATE_OPTION_READONLY)
1335 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1338 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001339 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001340 /* BB Expirement with various impersonation levels and verify */
1341 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 pSMB->SecurityFlags =
1343 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1344
1345 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001346 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 pSMB->ByteCount = cpu_to_le16(count);
1349 /* long_op set to 1 to allow for oplock break timeouts */
1350 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001351 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001352 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001354 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 } else {
Steve French09d1db52005-04-28 22:41:08 -07001356 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1358 /* Let caller know file was created so we can set the mode. */
1359 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001360 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001361 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001362 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001363 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1364 36 /* CreationTime to Attributes */);
1365 /* the file_info buf is endian converted by caller */
1366 pfile_info->AllocationSize = pSMBr->AllocationSize;
1367 pfile_info->EndOfFile = pSMBr->EndOfFile;
1368 pfile_info->NumberOfLinks = cpu_to_le32(1);
1369 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 cifs_buf_release(pSMB);
1374 if (rc == -EAGAIN)
1375 goto openRetry;
1376 return rc;
1377}
1378
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001380CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001381 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382{
1383 int rc = -EACCES;
1384 READ_REQ *pSMB = NULL;
1385 READ_RSP *pSMBr = NULL;
1386 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001387 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001388 int resp_buf_type = 0;
1389 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001390 __u32 pid = io_parms->pid;
1391 __u16 netfid = io_parms->netfid;
1392 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001393 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001394 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Joe Perchesb6b38f72010-04-21 03:50:45 +00001396 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001397 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001398 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001399 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001400 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001401 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001402 /* can not handle this big offset for old */
1403 return -EIO;
1404 }
1405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
1407 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001408 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 if (rc)
1410 return rc;
1411
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001412 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1413 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1414
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 /* tcon and ses pointer are checked in smb_init */
1416 if (tcon->ses->server == NULL)
1417 return -ECONNABORTED;
1418
Steve Frenchec637e32005-12-12 20:53:18 -08001419 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001421 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001422 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001423 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 pSMB->Remaining = 0;
1426 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1427 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001428 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001429 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1430 else {
1431 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001432 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001434 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001435 }
Steve Frenchec637e32005-12-12 20:53:18 -08001436
1437 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001438 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001439 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001440 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001441 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001442 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001444 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 } else {
1446 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1447 data_length = data_length << 16;
1448 data_length += le16_to_cpu(pSMBr->DataLength);
1449 *nbytes = data_length;
1450
1451 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001452 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001454 cFYI(1, "bad length %d for count %d",
1455 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 rc = -EIO;
1457 *nbytes = 0;
1458 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001459 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001460 le16_to_cpu(pSMBr->DataOffset);
1461/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001462 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001463 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001464 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001465 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001466 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 }
1468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
Steve French4b8f9302006-02-26 16:41:18 +00001470/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001471 if (*buf) {
1472 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001473 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001474 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001475 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001476 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001477 /* return buffer to caller to free */
1478 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001479 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001480 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001481 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001482 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001483 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001484
1485 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 since file handle passed in no longer valid */
1487 return rc;
1488}
1489
Steve Frenchec637e32005-12-12 20:53:18 -08001490
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001492CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1493 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001494 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
1496 int rc = -EACCES;
1497 WRITE_REQ *pSMB = NULL;
1498 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001499 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 __u32 bytes_sent;
1501 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001502 __u32 pid = io_parms->pid;
1503 __u16 netfid = io_parms->netfid;
1504 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001505 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001506 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
Steve Frencha24e2d72010-04-03 17:20:21 +00001508 *nbytes = 0;
1509
Joe Perchesb6b38f72010-04-21 03:50:45 +00001510 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001511 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001512 return -ECONNABORTED;
1513
Steve French790fe572007-07-07 19:25:05 +00001514 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001515 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001516 else {
Steve French1c955182005-08-30 20:58:07 -07001517 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001518 if ((offset >> 32) > 0) {
1519 /* can not handle big offset for old srv */
1520 return -EIO;
1521 }
1522 }
Steve French1c955182005-08-30 20:58:07 -07001523
1524 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 (void **) &pSMBr);
1526 if (rc)
1527 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001528
1529 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1530 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1531
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 /* tcon and ses pointer are checked in smb_init */
1533 if (tcon->ses->server == NULL)
1534 return -ECONNABORTED;
1535
1536 pSMB->AndXCommand = 0xFF; /* none */
1537 pSMB->Fid = netfid;
1538 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001539 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001540 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 pSMB->Reserved = 0xFFFFFFFF;
1543 pSMB->WriteMode = 0;
1544 pSMB->Remaining = 0;
1545
Steve French50c2f752007-07-13 00:33:32 +00001546 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 can send more if LARGE_WRITE_X capability returned by the server and if
1548 our buffer is big enough or if we convert to iovecs on socket writes
1549 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001550 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1552 } else {
1553 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1554 & ~0xFF;
1555 }
1556
1557 if (bytes_sent > count)
1558 bytes_sent = count;
1559 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001560 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001561 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001562 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001563 else if (ubuf) {
1564 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 cifs_buf_release(pSMB);
1566 return -EFAULT;
1567 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001568 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 /* No buffer */
1570 cifs_buf_release(pSMB);
1571 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001572 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001573 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001574 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001575 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001576 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1579 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001580 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001581
Steve French790fe572007-07-07 19:25:05 +00001582 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001583 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001584 else { /* old style write has byte count 4 bytes earlier
1585 so 4 bytes pad */
1586 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001587 (struct smb_com_writex_req *)pSMB;
1588 pSMBW->ByteCount = cpu_to_le16(byte_count);
1589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1592 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001593 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001595 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 } else {
1597 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1598 *nbytes = (*nbytes) << 16;
1599 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301600
1601 /*
1602 * Mask off high 16 bits when bytes written as returned by the
1603 * server is greater than bytes requested by the client. Some
1604 * OS/2 servers are known to set incorrect CountHigh values.
1605 */
1606 if (*nbytes > count)
1607 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
1609
1610 cifs_buf_release(pSMB);
1611
Steve French50c2f752007-07-13 00:33:32 +00001612 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 since file handle passed in no longer valid */
1614
1615 return rc;
1616}
1617
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001618void
1619cifs_writedata_release(struct kref *refcount)
1620{
1621 struct cifs_writedata *wdata = container_of(refcount,
1622 struct cifs_writedata, refcount);
1623
1624 if (wdata->cfile)
1625 cifsFileInfo_put(wdata->cfile);
1626
1627 kfree(wdata);
1628}
1629
1630/*
1631 * Write failed with a retryable error. Resend the write request. It's also
1632 * possible that the page was redirtied so re-clean the page.
1633 */
1634static void
1635cifs_writev_requeue(struct cifs_writedata *wdata)
1636{
1637 int i, rc;
1638 struct inode *inode = wdata->cfile->dentry->d_inode;
1639
1640 for (i = 0; i < wdata->nr_pages; i++) {
1641 lock_page(wdata->pages[i]);
1642 clear_page_dirty_for_io(wdata->pages[i]);
1643 }
1644
1645 do {
1646 rc = cifs_async_writev(wdata);
1647 } while (rc == -EAGAIN);
1648
1649 for (i = 0; i < wdata->nr_pages; i++) {
1650 if (rc != 0)
1651 SetPageError(wdata->pages[i]);
1652 unlock_page(wdata->pages[i]);
1653 }
1654
1655 mapping_set_error(inode->i_mapping, rc);
1656 kref_put(&wdata->refcount, cifs_writedata_release);
1657}
1658
1659static void
1660cifs_writev_complete(struct work_struct *work)
1661{
1662 struct cifs_writedata *wdata = container_of(work,
1663 struct cifs_writedata, work);
1664 struct inode *inode = wdata->cfile->dentry->d_inode;
1665 int i = 0;
1666
1667 if (wdata->result == 0) {
1668 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1669 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1670 wdata->bytes);
1671 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1672 return cifs_writev_requeue(wdata);
1673
1674 for (i = 0; i < wdata->nr_pages; i++) {
1675 struct page *page = wdata->pages[i];
1676 if (wdata->result == -EAGAIN)
1677 __set_page_dirty_nobuffers(page);
1678 else if (wdata->result < 0)
1679 SetPageError(page);
1680 end_page_writeback(page);
1681 page_cache_release(page);
1682 }
1683 if (wdata->result != -EAGAIN)
1684 mapping_set_error(inode->i_mapping, wdata->result);
1685 kref_put(&wdata->refcount, cifs_writedata_release);
1686}
1687
1688struct cifs_writedata *
1689cifs_writedata_alloc(unsigned int nr_pages)
1690{
1691 struct cifs_writedata *wdata;
1692
1693 /* this would overflow */
1694 if (nr_pages == 0) {
1695 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1696 return NULL;
1697 }
1698
1699 /* writedata + number of page pointers */
1700 wdata = kzalloc(sizeof(*wdata) +
1701 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1702 if (wdata != NULL) {
1703 INIT_WORK(&wdata->work, cifs_writev_complete);
1704 kref_init(&wdata->refcount);
1705 }
1706 return wdata;
1707}
1708
1709/*
1710 * Check the midState and signature on received buffer (if any), and queue the
1711 * workqueue completion task.
1712 */
1713static void
1714cifs_writev_callback(struct mid_q_entry *mid)
1715{
1716 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001717 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001718 unsigned int written;
1719 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1720
1721 switch (mid->midState) {
1722 case MID_RESPONSE_RECEIVED:
1723 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1724 if (wdata->result != 0)
1725 break;
1726
1727 written = le16_to_cpu(smb->CountHigh);
1728 written <<= 16;
1729 written += le16_to_cpu(smb->Count);
1730 /*
1731 * Mask off high 16 bits when bytes written as returned
1732 * by the server is greater than bytes requested by the
1733 * client. OS/2 servers are known to set incorrect
1734 * CountHigh values.
1735 */
1736 if (written > wdata->bytes)
1737 written &= 0xFFFF;
1738
1739 if (written < wdata->bytes)
1740 wdata->result = -ENOSPC;
1741 else
1742 wdata->bytes = written;
1743 break;
1744 case MID_REQUEST_SUBMITTED:
1745 case MID_RETRY_NEEDED:
1746 wdata->result = -EAGAIN;
1747 break;
1748 default:
1749 wdata->result = -EIO;
1750 break;
1751 }
1752
1753 queue_work(system_nrt_wq, &wdata->work);
1754 DeleteMidQEntry(mid);
1755 atomic_dec(&tcon->ses->server->inFlight);
1756 wake_up(&tcon->ses->server->request_q);
1757}
1758
1759/* cifs_async_writev - send an async write, and set up mid to handle result */
1760int
1761cifs_async_writev(struct cifs_writedata *wdata)
1762{
1763 int i, rc = -EACCES;
1764 WRITE_REQ *smb = NULL;
1765 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00001766 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001767 struct inode *inode = wdata->cfile->dentry->d_inode;
1768 struct kvec *iov = NULL;
1769
1770 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1771 wct = 14;
1772 } else {
1773 wct = 12;
1774 if (wdata->offset >> 32 > 0) {
1775 /* can not handle big offset for old srv */
1776 return -EIO;
1777 }
1778 }
1779
1780 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
1781 if (rc)
1782 goto async_writev_out;
1783
1784 /* 1 iov per page + 1 for header */
1785 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
1786 if (iov == NULL) {
1787 rc = -ENOMEM;
1788 goto async_writev_out;
1789 }
1790
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001791 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
1792 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
1793
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001794 smb->AndXCommand = 0xFF; /* none */
1795 smb->Fid = wdata->cfile->netfid;
1796 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
1797 if (wct == 14)
1798 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
1799 smb->Reserved = 0xFFFFFFFF;
1800 smb->WriteMode = 0;
1801 smb->Remaining = 0;
1802
1803 smb->DataOffset =
1804 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1805
1806 /* 4 for RFC1001 length + 1 for BCC */
1807 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
1808 iov[0].iov_base = smb;
1809
1810 /* marshal up the pages into iov array */
1811 wdata->bytes = 0;
1812 for (i = 0; i < wdata->nr_pages; i++) {
1813 iov[i + 1].iov_len = min(inode->i_size -
1814 page_offset(wdata->pages[i]),
1815 (loff_t)PAGE_CACHE_SIZE);
1816 iov[i + 1].iov_base = kmap(wdata->pages[i]);
1817 wdata->bytes += iov[i + 1].iov_len;
1818 }
1819
1820 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
1821
1822 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
1823 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
1824
1825 if (wct == 14) {
1826 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
1827 put_bcc(wdata->bytes + 1, &smb->hdr);
1828 } else {
1829 /* wct == 12 */
1830 struct smb_com_writex_req *smbw =
1831 (struct smb_com_writex_req *)smb;
1832 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
1833 put_bcc(wdata->bytes + 5, &smbw->hdr);
1834 iov[0].iov_len += 4; /* pad bigger by four bytes */
1835 }
1836
1837 kref_get(&wdata->refcount);
1838 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
1839 cifs_writev_callback, wdata, false);
1840
1841 if (rc == 0)
1842 cifs_stats_inc(&tcon->num_writes);
1843 else
1844 kref_put(&wdata->refcount, cifs_writedata_release);
1845
1846 /* send is done, unmap pages */
1847 for (i = 0; i < wdata->nr_pages; i++)
1848 kunmap(wdata->pages[i]);
1849
1850async_writev_out:
1851 cifs_small_buf_release(smb);
1852 kfree(iov);
1853 return rc;
1854}
1855
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001856int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001857CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
1858 unsigned int *nbytes, struct kvec *iov, int n_vec,
1859 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860{
1861 int rc = -EACCES;
1862 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001863 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001864 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001865 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001866 __u32 pid = io_parms->pid;
1867 __u16 netfid = io_parms->netfid;
1868 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001869 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001870 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001872 *nbytes = 0;
1873
Joe Perchesb6b38f72010-04-21 03:50:45 +00001874 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001875
Steve French4c3130e2008-12-09 00:28:16 +00001876 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001877 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001878 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001879 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001880 if ((offset >> 32) > 0) {
1881 /* can not handle big offset for old srv */
1882 return -EIO;
1883 }
1884 }
Steve French8cc64c62005-10-03 13:49:43 -07001885 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 if (rc)
1887 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001888
1889 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1890 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1891
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 /* tcon and ses pointer are checked in smb_init */
1893 if (tcon->ses->server == NULL)
1894 return -ECONNABORTED;
1895
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001896 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 pSMB->Fid = netfid;
1898 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001899 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001900 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 pSMB->Reserved = 0xFFFFFFFF;
1902 pSMB->WriteMode = 0;
1903 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001904
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001906 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
Steve French3e844692005-10-03 13:37:24 -07001908 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1909 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001910 /* header + 1 byte pad */
1911 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001912 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001913 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001914 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001915 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001916 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001917 pSMB->ByteCount = cpu_to_le16(count + 1);
1918 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001919 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001920 (struct smb_com_writex_req *)pSMB;
1921 pSMBW->ByteCount = cpu_to_le16(count + 5);
1922 }
Steve French3e844692005-10-03 13:37:24 -07001923 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001924 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001925 iov[0].iov_len = smb_hdr_len + 4;
1926 else /* wct == 12 pad bigger by four bytes */
1927 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001928
Steve French3e844692005-10-03 13:37:24 -07001929
Steve Frenchec637e32005-12-12 20:53:18 -08001930 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001931 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001932 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001934 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001935 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001936 /* presumably this can not happen, but best to be safe */
1937 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001938 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001939 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001940 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1941 *nbytes = (*nbytes) << 16;
1942 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301943
1944 /*
1945 * Mask off high 16 bits when bytes written as returned by the
1946 * server is greater than bytes requested by the client. OS/2
1947 * servers are known to set incorrect CountHigh values.
1948 */
1949 if (*nbytes > count)
1950 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Steve French4b8f9302006-02-26 16:41:18 +00001953/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001954 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001955 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001956 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001957 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
Steve French50c2f752007-07-13 00:33:32 +00001959 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 since file handle passed in no longer valid */
1961
1962 return rc;
1963}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001964
1965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966int
Steve French96daf2b2011-05-27 04:34:02 +00001967CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 const __u16 smb_file_id, const __u64 len,
1969 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001970 const __u32 numLock, const __u8 lockType,
1971 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972{
1973 int rc = 0;
1974 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001975/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 int bytes_returned;
1977 int timeout = 0;
1978 __u16 count;
1979
Joe Perchesb6b38f72010-04-21 03:50:45 +00001980 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001981 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1982
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 if (rc)
1984 return rc;
1985
Steve French790fe572007-07-07 19:25:05 +00001986 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001987 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001989 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001990 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1992 } else {
1993 pSMB->Timeout = 0;
1994 }
1995
1996 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1997 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1998 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001999 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 pSMB->AndXCommand = 0xFF; /* none */
2001 pSMB->Fid = smb_file_id; /* netfid stays le */
2002
Steve French790fe572007-07-07 19:25:05 +00002003 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
2005 /* BB where to store pid high? */
2006 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2007 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2008 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2009 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2010 count = sizeof(LOCKING_ANDX_RANGE);
2011 } else {
2012 /* oplock break */
2013 count = 0;
2014 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002015 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 pSMB->ByteCount = cpu_to_le16(count);
2017
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002018 if (waitFlag) {
2019 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002020 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002021 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002022 } else {
Steve French133672e2007-11-13 22:41:37 +00002023 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2024 timeout);
2025 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002026 }
Steve Frencha4544342005-08-24 13:59:35 -07002027 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002028 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002029 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Steve French50c2f752007-07-13 00:33:32 +00002031 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 since file handle passed in no longer valid */
2033 return rc;
2034}
2035
2036int
Steve French96daf2b2011-05-27 04:34:02 +00002037CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Steve French08547b02006-02-28 22:39:25 +00002038 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00002039 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00002040 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002041{
2042 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2043 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002044 struct cifs_posix_lock *parm_data;
2045 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002046 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002047 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002048 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002049 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002050 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002051
Joe Perchesb6b38f72010-04-21 03:50:45 +00002052 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002053
Steve French790fe572007-07-07 19:25:05 +00002054 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002055 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002056
Steve French08547b02006-02-28 22:39:25 +00002057 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2058
2059 if (rc)
2060 return rc;
2061
2062 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2063
Steve French50c2f752007-07-13 00:33:32 +00002064 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002065 pSMB->MaxSetupCount = 0;
2066 pSMB->Reserved = 0;
2067 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002068 pSMB->Reserved2 = 0;
2069 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2070 offset = param_offset + params;
2071
Steve French08547b02006-02-28 22:39:25 +00002072 count = sizeof(struct cifs_posix_lock);
2073 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002074 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002075 pSMB->SetupCount = 1;
2076 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002077 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002078 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2079 else
2080 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2081 byte_count = 3 /* pad */ + params + count;
2082 pSMB->DataCount = cpu_to_le16(count);
2083 pSMB->ParameterCount = cpu_to_le16(params);
2084 pSMB->TotalDataCount = pSMB->DataCount;
2085 pSMB->TotalParameterCount = pSMB->ParameterCount;
2086 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002087 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002088 (((char *) &pSMB->hdr.Protocol) + offset);
2089
2090 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002091 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002092 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002093 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002094 pSMB->Timeout = cpu_to_le32(-1);
2095 } else
2096 pSMB->Timeout = 0;
2097
Steve French08547b02006-02-28 22:39:25 +00002098 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002099 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002100 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002101
2102 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002103 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002104 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2105 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002106 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002107 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002108 if (waitFlag) {
2109 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2110 (struct smb_hdr *) pSMBr, &bytes_returned);
2111 } else {
Steve French133672e2007-11-13 22:41:37 +00002112 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002113 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002114 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2115 &resp_buf_type, timeout);
2116 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2117 not try to free it twice below on exit */
2118 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002119 }
2120
Steve French08547b02006-02-28 22:39:25 +00002121 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002122 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002123 } else if (get_flag) {
2124 /* lock structure can be returned on get */
2125 __u16 data_offset;
2126 __u16 data_count;
2127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002128
Jeff Layton820a8032011-05-04 08:05:26 -04002129 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002130 rc = -EIO; /* bad smb */
2131 goto plk_err_exit;
2132 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002133 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2134 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002135 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002136 rc = -EIO;
2137 goto plk_err_exit;
2138 }
2139 parm_data = (struct cifs_posix_lock *)
2140 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002141 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002142 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002143 else {
2144 if (parm_data->lock_type ==
2145 __constant_cpu_to_le16(CIFS_RDLCK))
2146 pLockData->fl_type = F_RDLCK;
2147 else if (parm_data->lock_type ==
2148 __constant_cpu_to_le16(CIFS_WRLCK))
2149 pLockData->fl_type = F_WRLCK;
2150
Steve French5443d132011-03-13 05:08:25 +00002151 pLockData->fl_start = le64_to_cpu(parm_data->start);
2152 pLockData->fl_end = pLockData->fl_start +
2153 le64_to_cpu(parm_data->length) - 1;
2154 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002155 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002156 }
Steve French50c2f752007-07-13 00:33:32 +00002157
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002158plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002159 if (pSMB)
2160 cifs_small_buf_release(pSMB);
2161
Steve French133672e2007-11-13 22:41:37 +00002162 if (resp_buf_type == CIFS_SMALL_BUFFER)
2163 cifs_small_buf_release(iov[0].iov_base);
2164 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2165 cifs_buf_release(iov[0].iov_base);
2166
Steve French08547b02006-02-28 22:39:25 +00002167 /* Note: On -EAGAIN error only caller can retry on handle based calls
2168 since file handle passed in no longer valid */
2169
2170 return rc;
2171}
2172
2173
2174int
Steve French96daf2b2011-05-27 04:34:02 +00002175CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176{
2177 int rc = 0;
2178 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002179 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180
2181/* do not retry on dead session on close */
2182 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002183 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 return 0;
2185 if (rc)
2186 return rc;
2187
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002189 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002191 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002192 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002194 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002196 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 }
2198 }
2199
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002201 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 rc = 0;
2203
2204 return rc;
2205}
2206
2207int
Steve French96daf2b2011-05-27 04:34:02 +00002208CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002209{
2210 int rc = 0;
2211 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002212 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002213
2214 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2215 if (rc)
2216 return rc;
2217
2218 pSMB->FileID = (__u16) smb_file_id;
2219 pSMB->ByteCount = 0;
2220 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2221 cifs_stats_inc(&tcon->num_flushes);
2222 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002223 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002224
2225 return rc;
2226}
2227
2228int
Steve French96daf2b2011-05-27 04:34:02 +00002229CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002231 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232{
2233 int rc = 0;
2234 RENAME_REQ *pSMB = NULL;
2235 RENAME_RSP *pSMBr = NULL;
2236 int bytes_returned;
2237 int name_len, name_len2;
2238 __u16 count;
2239
Joe Perchesb6b38f72010-04-21 03:50:45 +00002240 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241renameRetry:
2242 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2243 (void **) &pSMBr);
2244 if (rc)
2245 return rc;
2246
2247 pSMB->BufferFormat = 0x04;
2248 pSMB->SearchAttributes =
2249 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2250 ATTR_DIRECTORY);
2251
2252 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2253 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002254 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002255 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 name_len++; /* trailing null */
2257 name_len *= 2;
2258 pSMB->OldFileName[name_len] = 0x04; /* pad */
2259 /* protocol requires ASCII signature byte on Unicode string */
2260 pSMB->OldFileName[name_len + 1] = 0x00;
2261 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002262 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002263 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2265 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002266 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 name_len = strnlen(fromName, PATH_MAX);
2268 name_len++; /* trailing null */
2269 strncpy(pSMB->OldFileName, fromName, name_len);
2270 name_len2 = strnlen(toName, PATH_MAX);
2271 name_len2++; /* trailing null */
2272 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2273 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2274 name_len2++; /* trailing null */
2275 name_len2++; /* signature byte */
2276 }
2277
2278 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002279 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 pSMB->ByteCount = cpu_to_le16(count);
2281
2282 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2283 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002284 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002285 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002286 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 cifs_buf_release(pSMB);
2289
2290 if (rc == -EAGAIN)
2291 goto renameRetry;
2292
2293 return rc;
2294}
2295
Steve French96daf2b2011-05-27 04:34:02 +00002296int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002297 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002298 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2301 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002302 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 char *data_offset;
2304 char dummy_string[30];
2305 int rc = 0;
2306 int bytes_returned = 0;
2307 int len_of_str;
2308 __u16 params, param_offset, offset, count, byte_count;
2309
Joe Perchesb6b38f72010-04-21 03:50:45 +00002310 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2312 (void **) &pSMBr);
2313 if (rc)
2314 return rc;
2315
2316 params = 6;
2317 pSMB->MaxSetupCount = 0;
2318 pSMB->Reserved = 0;
2319 pSMB->Flags = 0;
2320 pSMB->Timeout = 0;
2321 pSMB->Reserved2 = 0;
2322 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2323 offset = param_offset + params;
2324
2325 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2326 rename_info = (struct set_file_rename *) data_offset;
2327 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002328 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 pSMB->SetupCount = 1;
2330 pSMB->Reserved3 = 0;
2331 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2332 byte_count = 3 /* pad */ + params;
2333 pSMB->ParameterCount = cpu_to_le16(params);
2334 pSMB->TotalParameterCount = pSMB->ParameterCount;
2335 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2336 pSMB->DataOffset = cpu_to_le16(offset);
2337 /* construct random name ".cifs_tmp<inodenum><mid>" */
2338 rename_info->overwrite = cpu_to_le32(1);
2339 rename_info->root_fid = 0;
2340 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002341 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002342 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2343 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002344 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002346 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002347 target_name, PATH_MAX, nls_codepage,
2348 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 }
2350 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002351 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 byte_count += count;
2353 pSMB->DataCount = cpu_to_le16(count);
2354 pSMB->TotalDataCount = pSMB->DataCount;
2355 pSMB->Fid = netfid;
2356 pSMB->InformationLevel =
2357 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2358 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002359 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 pSMB->ByteCount = cpu_to_le16(byte_count);
2361 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002362 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002363 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002364 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002365 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002366
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 cifs_buf_release(pSMB);
2368
2369 /* Note: On -EAGAIN error only caller can retry on handle based calls
2370 since file handle passed in no longer valid */
2371
2372 return rc;
2373}
2374
2375int
Steve French96daf2b2011-05-27 04:34:02 +00002376CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002377 const __u16 target_tid, const char *toName, const int flags,
2378 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379{
2380 int rc = 0;
2381 COPY_REQ *pSMB = NULL;
2382 COPY_RSP *pSMBr = NULL;
2383 int bytes_returned;
2384 int name_len, name_len2;
2385 __u16 count;
2386
Joe Perchesb6b38f72010-04-21 03:50:45 +00002387 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388copyRetry:
2389 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2390 (void **) &pSMBr);
2391 if (rc)
2392 return rc;
2393
2394 pSMB->BufferFormat = 0x04;
2395 pSMB->Tid2 = target_tid;
2396
2397 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2398
2399 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002400 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002401 fromName, PATH_MAX, nls_codepage,
2402 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 name_len++; /* trailing null */
2404 name_len *= 2;
2405 pSMB->OldFileName[name_len] = 0x04; /* pad */
2406 /* protocol requires ASCII signature byte on Unicode string */
2407 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002408 name_len2 =
2409 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002410 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2412 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002413 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 name_len = strnlen(fromName, PATH_MAX);
2415 name_len++; /* trailing null */
2416 strncpy(pSMB->OldFileName, fromName, name_len);
2417 name_len2 = strnlen(toName, PATH_MAX);
2418 name_len2++; /* trailing null */
2419 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2420 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2421 name_len2++; /* trailing null */
2422 name_len2++; /* signature byte */
2423 }
2424
2425 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002426 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 pSMB->ByteCount = cpu_to_le16(count);
2428
2429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2431 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002432 cFYI(1, "Send error in copy = %d with %d files copied",
2433 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
Steve French0d817bc2008-05-22 02:02:03 +00002435 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
2437 if (rc == -EAGAIN)
2438 goto copyRetry;
2439
2440 return rc;
2441}
2442
2443int
Steve French96daf2b2011-05-27 04:34:02 +00002444CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 const char *fromName, const char *toName,
2446 const struct nls_table *nls_codepage)
2447{
2448 TRANSACTION2_SPI_REQ *pSMB = NULL;
2449 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2450 char *data_offset;
2451 int name_len;
2452 int name_len_target;
2453 int rc = 0;
2454 int bytes_returned = 0;
2455 __u16 params, param_offset, offset, byte_count;
2456
Joe Perchesb6b38f72010-04-21 03:50:45 +00002457 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458createSymLinkRetry:
2459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2460 (void **) &pSMBr);
2461 if (rc)
2462 return rc;
2463
2464 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2465 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002466 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 /* find define for this maxpathcomponent */
2468 , nls_codepage);
2469 name_len++; /* trailing null */
2470 name_len *= 2;
2471
Steve French50c2f752007-07-13 00:33:32 +00002472 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 name_len = strnlen(fromName, PATH_MAX);
2474 name_len++; /* trailing null */
2475 strncpy(pSMB->FileName, fromName, name_len);
2476 }
2477 params = 6 + name_len;
2478 pSMB->MaxSetupCount = 0;
2479 pSMB->Reserved = 0;
2480 pSMB->Flags = 0;
2481 pSMB->Timeout = 0;
2482 pSMB->Reserved2 = 0;
2483 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002484 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 offset = param_offset + params;
2486
2487 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2488 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2489 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002490 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 /* find define for this maxpathcomponent */
2492 , nls_codepage);
2493 name_len_target++; /* trailing null */
2494 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002495 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 name_len_target = strnlen(toName, PATH_MAX);
2497 name_len_target++; /* trailing null */
2498 strncpy(data_offset, toName, name_len_target);
2499 }
2500
2501 pSMB->MaxParameterCount = cpu_to_le16(2);
2502 /* BB find exact max on data count below from sess */
2503 pSMB->MaxDataCount = cpu_to_le16(1000);
2504 pSMB->SetupCount = 1;
2505 pSMB->Reserved3 = 0;
2506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2507 byte_count = 3 /* pad */ + params + name_len_target;
2508 pSMB->DataCount = cpu_to_le16(name_len_target);
2509 pSMB->ParameterCount = cpu_to_le16(params);
2510 pSMB->TotalDataCount = pSMB->DataCount;
2511 pSMB->TotalParameterCount = pSMB->ParameterCount;
2512 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2513 pSMB->DataOffset = cpu_to_le16(offset);
2514 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2515 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002516 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 pSMB->ByteCount = cpu_to_le16(byte_count);
2518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2519 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002520 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002521 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002522 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
Steve French0d817bc2008-05-22 02:02:03 +00002524 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
2526 if (rc == -EAGAIN)
2527 goto createSymLinkRetry;
2528
2529 return rc;
2530}
2531
2532int
Steve French96daf2b2011-05-27 04:34:02 +00002533CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002535 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
2537 TRANSACTION2_SPI_REQ *pSMB = NULL;
2538 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2539 char *data_offset;
2540 int name_len;
2541 int name_len_target;
2542 int rc = 0;
2543 int bytes_returned = 0;
2544 __u16 params, param_offset, offset, byte_count;
2545
Joe Perchesb6b38f72010-04-21 03:50:45 +00002546 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547createHardLinkRetry:
2548 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2549 (void **) &pSMBr);
2550 if (rc)
2551 return rc;
2552
2553 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002554 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002555 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 name_len++; /* trailing null */
2557 name_len *= 2;
2558
Steve French50c2f752007-07-13 00:33:32 +00002559 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 name_len = strnlen(toName, PATH_MAX);
2561 name_len++; /* trailing null */
2562 strncpy(pSMB->FileName, toName, name_len);
2563 }
2564 params = 6 + name_len;
2565 pSMB->MaxSetupCount = 0;
2566 pSMB->Reserved = 0;
2567 pSMB->Flags = 0;
2568 pSMB->Timeout = 0;
2569 pSMB->Reserved2 = 0;
2570 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002571 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 offset = param_offset + params;
2573
2574 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2575 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2576 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002577 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002578 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 name_len_target++; /* trailing null */
2580 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002581 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 name_len_target = strnlen(fromName, PATH_MAX);
2583 name_len_target++; /* trailing null */
2584 strncpy(data_offset, fromName, name_len_target);
2585 }
2586
2587 pSMB->MaxParameterCount = cpu_to_le16(2);
2588 /* BB find exact max on data count below from sess*/
2589 pSMB->MaxDataCount = cpu_to_le16(1000);
2590 pSMB->SetupCount = 1;
2591 pSMB->Reserved3 = 0;
2592 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2593 byte_count = 3 /* pad */ + params + name_len_target;
2594 pSMB->ParameterCount = cpu_to_le16(params);
2595 pSMB->TotalParameterCount = pSMB->ParameterCount;
2596 pSMB->DataCount = cpu_to_le16(name_len_target);
2597 pSMB->TotalDataCount = pSMB->DataCount;
2598 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2599 pSMB->DataOffset = cpu_to_le16(offset);
2600 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2601 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002602 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 pSMB->ByteCount = cpu_to_le16(byte_count);
2604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002606 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002607 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002608 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
2610 cifs_buf_release(pSMB);
2611 if (rc == -EAGAIN)
2612 goto createHardLinkRetry;
2613
2614 return rc;
2615}
2616
2617int
Steve French96daf2b2011-05-27 04:34:02 +00002618CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002620 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621{
2622 int rc = 0;
2623 NT_RENAME_REQ *pSMB = NULL;
2624 RENAME_RSP *pSMBr = NULL;
2625 int bytes_returned;
2626 int name_len, name_len2;
2627 __u16 count;
2628
Joe Perchesb6b38f72010-04-21 03:50:45 +00002629 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630winCreateHardLinkRetry:
2631
2632 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2633 (void **) &pSMBr);
2634 if (rc)
2635 return rc;
2636
2637 pSMB->SearchAttributes =
2638 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2639 ATTR_DIRECTORY);
2640 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2641 pSMB->ClusterCount = 0;
2642
2643 pSMB->BufferFormat = 0x04;
2644
2645 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2646 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002647 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002648 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 name_len++; /* trailing null */
2650 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002651
2652 /* protocol specifies ASCII buffer format (0x04) for unicode */
2653 pSMB->OldFileName[name_len] = 0x04;
2654 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002656 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002657 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2659 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002660 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 name_len = strnlen(fromName, PATH_MAX);
2662 name_len++; /* trailing null */
2663 strncpy(pSMB->OldFileName, fromName, name_len);
2664 name_len2 = strnlen(toName, PATH_MAX);
2665 name_len2++; /* trailing null */
2666 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2667 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2668 name_len2++; /* trailing null */
2669 name_len2++; /* signature byte */
2670 }
2671
2672 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002673 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 pSMB->ByteCount = cpu_to_le16(count);
2675
2676 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002678 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002679 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002680 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 cifs_buf_release(pSMB);
2683 if (rc == -EAGAIN)
2684 goto winCreateHardLinkRetry;
2685
2686 return rc;
2687}
2688
2689int
Steve French96daf2b2011-05-27 04:34:02 +00002690CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002691 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 const struct nls_table *nls_codepage)
2693{
2694/* SMB_QUERY_FILE_UNIX_LINK */
2695 TRANSACTION2_QPI_REQ *pSMB = NULL;
2696 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2697 int rc = 0;
2698 int bytes_returned;
2699 int name_len;
2700 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002701 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Joe Perchesb6b38f72010-04-21 03:50:45 +00002703 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705querySymLinkRetry:
2706 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2707 (void **) &pSMBr);
2708 if (rc)
2709 return rc;
2710
2711 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2712 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002713 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2714 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 name_len++; /* trailing null */
2716 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002717 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 name_len = strnlen(searchName, PATH_MAX);
2719 name_len++; /* trailing null */
2720 strncpy(pSMB->FileName, searchName, name_len);
2721 }
2722
2723 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2724 pSMB->TotalDataCount = 0;
2725 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002726 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 pSMB->MaxSetupCount = 0;
2728 pSMB->Reserved = 0;
2729 pSMB->Flags = 0;
2730 pSMB->Timeout = 0;
2731 pSMB->Reserved2 = 0;
2732 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002733 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 pSMB->DataCount = 0;
2735 pSMB->DataOffset = 0;
2736 pSMB->SetupCount = 1;
2737 pSMB->Reserved3 = 0;
2738 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2739 byte_count = params + 1 /* pad */ ;
2740 pSMB->TotalParameterCount = cpu_to_le16(params);
2741 pSMB->ParameterCount = pSMB->TotalParameterCount;
2742 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2743 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002744 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 pSMB->ByteCount = cpu_to_le16(byte_count);
2746
2747 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2748 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2749 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002750 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 } else {
2752 /* decode response */
2753
2754 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002756 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002757 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002759 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002760 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761
Jeff Layton460b9692009-04-30 07:17:56 -04002762 data_start = ((char *) &pSMBr->hdr.Protocol) +
2763 le16_to_cpu(pSMBr->t2.DataOffset);
2764
Steve French0e0d2cf2009-05-01 05:27:32 +00002765 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2766 is_unicode = true;
2767 else
2768 is_unicode = false;
2769
Steve French737b7582005-04-28 22:41:06 -07002770 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002771 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002772 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002773 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002774 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 }
2776 }
2777 cifs_buf_release(pSMB);
2778 if (rc == -EAGAIN)
2779 goto querySymLinkRetry;
2780 return rc;
2781}
2782
Steve Frenchc52a9552011-02-24 06:16:22 +00002783#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2784/*
2785 * Recent Windows versions now create symlinks more frequently
2786 * and they use the "reparse point" mechanism below. We can of course
2787 * do symlinks nicely to Samba and other servers which support the
2788 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2789 * "MF" symlinks optionally, but for recent Windows we really need to
2790 * reenable the code below and fix the cifs_symlink callers to handle this.
2791 * In the interim this code has been moved to its own config option so
2792 * it is not compiled in by default until callers fixed up and more tested.
2793 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794int
Steve French96daf2b2011-05-27 04:34:02 +00002795CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002797 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 const struct nls_table *nls_codepage)
2799{
2800 int rc = 0;
2801 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002802 struct smb_com_transaction_ioctl_req *pSMB;
2803 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Joe Perchesb6b38f72010-04-21 03:50:45 +00002805 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2807 (void **) &pSMBr);
2808 if (rc)
2809 return rc;
2810
2811 pSMB->TotalParameterCount = 0 ;
2812 pSMB->TotalDataCount = 0;
2813 pSMB->MaxParameterCount = cpu_to_le32(2);
2814 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002815 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2816 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 pSMB->MaxSetupCount = 4;
2818 pSMB->Reserved = 0;
2819 pSMB->ParameterOffset = 0;
2820 pSMB->DataCount = 0;
2821 pSMB->DataOffset = 0;
2822 pSMB->SetupCount = 4;
2823 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2824 pSMB->ParameterCount = pSMB->TotalParameterCount;
2825 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2826 pSMB->IsFsctl = 1; /* FSCTL */
2827 pSMB->IsRootFlag = 0;
2828 pSMB->Fid = fid; /* file handle always le */
2829 pSMB->ByteCount = 0;
2830
2831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2833 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002834 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 } else { /* decode response */
2836 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2837 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002838 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2839 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002841 goto qreparse_out;
2842 }
2843 if (data_count && (data_count < 2048)) {
2844 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002845 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846
Steve Frenchafe48c32009-05-02 05:25:46 +00002847 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002848 (struct reparse_data *)
2849 ((char *)&pSMBr->hdr.Protocol
2850 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002851 if ((char *)reparse_buf >= end_of_smb) {
2852 rc = -EIO;
2853 goto qreparse_out;
2854 }
2855 if ((reparse_buf->LinkNamesBuf +
2856 reparse_buf->TargetNameOffset +
2857 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002858 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002859 rc = -EIO;
2860 goto qreparse_out;
2861 }
Steve French50c2f752007-07-13 00:33:32 +00002862
Steve Frenchafe48c32009-05-02 05:25:46 +00002863 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2864 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002865 (reparse_buf->LinkNamesBuf +
2866 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002867 buflen,
2868 reparse_buf->TargetNameLen,
2869 nls_codepage, 0);
2870 } else { /* ASCII names */
2871 strncpy(symlinkinfo,
2872 reparse_buf->LinkNamesBuf +
2873 reparse_buf->TargetNameOffset,
2874 min_t(const int, buflen,
2875 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002877 } else {
2878 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002879 cFYI(1, "Invalid return data count on "
2880 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002882 symlinkinfo[buflen] = 0; /* just in case so the caller
2883 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002884 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 }
Steve French989c7e52009-05-02 05:32:20 +00002886
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002888 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
2890 /* Note: On -EAGAIN error only caller can retry on handle based calls
2891 since file handle passed in no longer valid */
2892
2893 return rc;
2894}
Steve Frenchc52a9552011-02-24 06:16:22 +00002895#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897#ifdef CONFIG_CIFS_POSIX
2898
2899/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002900static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2901 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902{
2903 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002904 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2905 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2906 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002907 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909 return;
2910}
2911
2912/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002913static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2914 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916 int size = 0;
2917 int i;
2918 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002919 struct cifs_posix_ace *pACE;
2920 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2921 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
2923 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2924 return -EOPNOTSUPP;
2925
Steve French790fe572007-07-07 19:25:05 +00002926 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 count = le16_to_cpu(cifs_acl->access_entry_count);
2928 pACE = &cifs_acl->ace_array[0];
2929 size = sizeof(struct cifs_posix_acl);
2930 size += sizeof(struct cifs_posix_ace) * count;
2931 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002932 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002933 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2934 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 return -EINVAL;
2936 }
Steve French790fe572007-07-07 19:25:05 +00002937 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 count = le16_to_cpu(cifs_acl->access_entry_count);
2939 size = sizeof(struct cifs_posix_acl);
2940 size += sizeof(struct cifs_posix_ace) * count;
2941/* skip past access ACEs to get to default ACEs */
2942 pACE = &cifs_acl->ace_array[count];
2943 count = le16_to_cpu(cifs_acl->default_entry_count);
2944 size += sizeof(struct cifs_posix_ace) * count;
2945 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002946 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 return -EINVAL;
2948 } else {
2949 /* illegal type */
2950 return -EINVAL;
2951 }
2952
2953 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002954 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002955 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002956 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 return -ERANGE;
2958 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002959 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002960 for (i = 0; i < count ; i++) {
2961 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2962 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 }
2964 }
2965 return size;
2966}
2967
Steve French50c2f752007-07-13 00:33:32 +00002968static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2969 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970{
2971 __u16 rc = 0; /* 0 = ACL converted ok */
2972
Steve Frenchff7feac2005-11-15 16:45:16 -08002973 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2974 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002976 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 /* Probably no need to le convert -1 on any arch but can not hurt */
2978 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002979 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002980 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002981 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 return rc;
2983}
2984
2985/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002986static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2987 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988{
2989 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002990 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2991 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 int count;
2993 int i;
2994
Steve French790fe572007-07-07 19:25:05 +00002995 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 return 0;
2997
2998 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002999 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003000 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003001 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003002 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003003 cFYI(1, "unknown POSIX ACL version %d",
3004 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 return 0;
3006 }
3007 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003008 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003009 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003010 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003011 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003013 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 return 0;
3015 }
Steve French50c2f752007-07-13 00:33:32 +00003016 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3018 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003019 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 /* ACE not converted */
3021 break;
3022 }
3023 }
Steve French790fe572007-07-07 19:25:05 +00003024 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3026 rc += sizeof(struct cifs_posix_acl);
3027 /* BB add check to make sure ACL does not overflow SMB */
3028 }
3029 return rc;
3030}
3031
3032int
Steve French96daf2b2011-05-27 04:34:02 +00003033CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003034 const unsigned char *searchName,
3035 char *acl_inf, const int buflen, const int acl_type,
3036 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037{
3038/* SMB_QUERY_POSIX_ACL */
3039 TRANSACTION2_QPI_REQ *pSMB = NULL;
3040 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3041 int rc = 0;
3042 int bytes_returned;
3043 int name_len;
3044 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003045
Joe Perchesb6b38f72010-04-21 03:50:45 +00003046 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047
3048queryAclRetry:
3049 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3050 (void **) &pSMBr);
3051 if (rc)
3052 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003053
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3055 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003056 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003057 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 name_len++; /* trailing null */
3059 name_len *= 2;
3060 pSMB->FileName[name_len] = 0;
3061 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003062 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 name_len = strnlen(searchName, PATH_MAX);
3064 name_len++; /* trailing null */
3065 strncpy(pSMB->FileName, searchName, name_len);
3066 }
3067
3068 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3069 pSMB->TotalDataCount = 0;
3070 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003071 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 pSMB->MaxDataCount = cpu_to_le16(4000);
3073 pSMB->MaxSetupCount = 0;
3074 pSMB->Reserved = 0;
3075 pSMB->Flags = 0;
3076 pSMB->Timeout = 0;
3077 pSMB->Reserved2 = 0;
3078 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003079 offsetof(struct smb_com_transaction2_qpi_req,
3080 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 pSMB->DataCount = 0;
3082 pSMB->DataOffset = 0;
3083 pSMB->SetupCount = 1;
3084 pSMB->Reserved3 = 0;
3085 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3086 byte_count = params + 1 /* pad */ ;
3087 pSMB->TotalParameterCount = cpu_to_le16(params);
3088 pSMB->ParameterCount = pSMB->TotalParameterCount;
3089 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3090 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003091 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 pSMB->ByteCount = cpu_to_le16(byte_count);
3093
3094 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3095 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003096 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003098 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 } else {
3100 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003101
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003104 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 rc = -EIO; /* bad smb */
3106 else {
3107 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3108 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3109 rc = cifs_copy_posix_acl(acl_inf,
3110 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003111 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 }
3113 }
3114 cifs_buf_release(pSMB);
3115 if (rc == -EAGAIN)
3116 goto queryAclRetry;
3117 return rc;
3118}
3119
3120int
Steve French96daf2b2011-05-27 04:34:02 +00003121CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003122 const unsigned char *fileName,
3123 const char *local_acl, const int buflen,
3124 const int acl_type,
3125 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126{
3127 struct smb_com_transaction2_spi_req *pSMB = NULL;
3128 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3129 char *parm_data;
3130 int name_len;
3131 int rc = 0;
3132 int bytes_returned = 0;
3133 __u16 params, byte_count, data_count, param_offset, offset;
3134
Joe Perchesb6b38f72010-04-21 03:50:45 +00003135 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136setAclRetry:
3137 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003138 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 if (rc)
3140 return rc;
3141 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3142 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003143 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003144 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 name_len++; /* trailing null */
3146 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003147 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 name_len = strnlen(fileName, PATH_MAX);
3149 name_len++; /* trailing null */
3150 strncpy(pSMB->FileName, fileName, name_len);
3151 }
3152 params = 6 + name_len;
3153 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003154 /* BB find max SMB size from sess */
3155 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 pSMB->MaxSetupCount = 0;
3157 pSMB->Reserved = 0;
3158 pSMB->Flags = 0;
3159 pSMB->Timeout = 0;
3160 pSMB->Reserved2 = 0;
3161 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003162 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 offset = param_offset + params;
3164 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3165 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3166
3167 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003168 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
Steve French790fe572007-07-07 19:25:05 +00003170 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 rc = -EOPNOTSUPP;
3172 goto setACLerrorExit;
3173 }
3174 pSMB->DataOffset = cpu_to_le16(offset);
3175 pSMB->SetupCount = 1;
3176 pSMB->Reserved3 = 0;
3177 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3178 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3179 byte_count = 3 /* pad */ + params + data_count;
3180 pSMB->DataCount = cpu_to_le16(data_count);
3181 pSMB->TotalDataCount = pSMB->DataCount;
3182 pSMB->ParameterCount = cpu_to_le16(params);
3183 pSMB->TotalParameterCount = pSMB->ParameterCount;
3184 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003185 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 pSMB->ByteCount = cpu_to_le16(byte_count);
3187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003189 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003190 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
3192setACLerrorExit:
3193 cifs_buf_release(pSMB);
3194 if (rc == -EAGAIN)
3195 goto setAclRetry;
3196 return rc;
3197}
3198
Steve Frenchf654bac2005-04-28 22:41:04 -07003199/* BB fix tabs in this function FIXME BB */
3200int
Steve French96daf2b2011-05-27 04:34:02 +00003201CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003202 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003203{
Steve French50c2f752007-07-13 00:33:32 +00003204 int rc = 0;
3205 struct smb_t2_qfi_req *pSMB = NULL;
3206 struct smb_t2_qfi_rsp *pSMBr = NULL;
3207 int bytes_returned;
3208 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003209
Joe Perchesb6b38f72010-04-21 03:50:45 +00003210 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003211 if (tcon == NULL)
3212 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003213
3214GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003215 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3216 (void **) &pSMBr);
3217 if (rc)
3218 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003219
Steve Frenchad7a2922008-02-07 23:25:02 +00003220 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003221 pSMB->t2.TotalDataCount = 0;
3222 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3223 /* BB find exact max data count below from sess structure BB */
3224 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3225 pSMB->t2.MaxSetupCount = 0;
3226 pSMB->t2.Reserved = 0;
3227 pSMB->t2.Flags = 0;
3228 pSMB->t2.Timeout = 0;
3229 pSMB->t2.Reserved2 = 0;
3230 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3231 Fid) - 4);
3232 pSMB->t2.DataCount = 0;
3233 pSMB->t2.DataOffset = 0;
3234 pSMB->t2.SetupCount = 1;
3235 pSMB->t2.Reserved3 = 0;
3236 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3237 byte_count = params + 1 /* pad */ ;
3238 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3239 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3240 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3241 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003242 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003243 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003244 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003245
Steve French790fe572007-07-07 19:25:05 +00003246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3248 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003249 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003250 } else {
3251 /* decode response */
3252 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003253 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003254 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003255 /* If rc should we check for EOPNOSUPP and
3256 disable the srvino flag? or in caller? */
3257 rc = -EIO; /* bad smb */
3258 else {
3259 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3260 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3261 struct file_chattr_info *pfinfo;
3262 /* BB Do we need a cast or hash here ? */
3263 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003264 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003265 rc = -EIO;
3266 goto GetExtAttrOut;
3267 }
3268 pfinfo = (struct file_chattr_info *)
3269 (data_offset + (char *) &pSMBr->hdr.Protocol);
3270 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003271 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003272 }
3273 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003274GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003275 cifs_buf_release(pSMB);
3276 if (rc == -EAGAIN)
3277 goto GetExtAttrRetry;
3278 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003279}
3280
Steve Frenchf654bac2005-04-28 22:41:04 -07003281#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
Jeff Layton79df1ba2010-12-06 12:52:08 -05003283#ifdef CONFIG_CIFS_ACL
3284/*
3285 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3286 * all NT TRANSACTS that we init here have total parm and data under about 400
3287 * bytes (to fit in small cifs buffer size), which is the case so far, it
3288 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3289 * returned setup area) and MaxParameterCount (returned parms size) must be set
3290 * by caller
3291 */
3292static int
3293smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003294 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003295 void **ret_buf)
3296{
3297 int rc;
3298 __u32 temp_offset;
3299 struct smb_com_ntransact_req *pSMB;
3300
3301 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3302 (void **)&pSMB);
3303 if (rc)
3304 return rc;
3305 *ret_buf = (void *)pSMB;
3306 pSMB->Reserved = 0;
3307 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3308 pSMB->TotalDataCount = 0;
3309 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3310 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3311 pSMB->ParameterCount = pSMB->TotalParameterCount;
3312 pSMB->DataCount = pSMB->TotalDataCount;
3313 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3314 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3315 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3316 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3317 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3318 pSMB->SubCommand = cpu_to_le16(sub_command);
3319 return 0;
3320}
3321
3322static int
3323validate_ntransact(char *buf, char **ppparm, char **ppdata,
3324 __u32 *pparmlen, __u32 *pdatalen)
3325{
3326 char *end_of_smb;
3327 __u32 data_count, data_offset, parm_count, parm_offset;
3328 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003329 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003330
3331 *pdatalen = 0;
3332 *pparmlen = 0;
3333
3334 if (buf == NULL)
3335 return -EINVAL;
3336
3337 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3338
Jeff Layton820a8032011-05-04 08:05:26 -04003339 bcc = get_bcc(&pSMBr->hdr);
3340 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003341 (char *)&pSMBr->ByteCount;
3342
3343 data_offset = le32_to_cpu(pSMBr->DataOffset);
3344 data_count = le32_to_cpu(pSMBr->DataCount);
3345 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3346 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3347
3348 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3349 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3350
3351 /* should we also check that parm and data areas do not overlap? */
3352 if (*ppparm > end_of_smb) {
3353 cFYI(1, "parms start after end of smb");
3354 return -EINVAL;
3355 } else if (parm_count + *ppparm > end_of_smb) {
3356 cFYI(1, "parm end after end of smb");
3357 return -EINVAL;
3358 } else if (*ppdata > end_of_smb) {
3359 cFYI(1, "data starts after end of smb");
3360 return -EINVAL;
3361 } else if (data_count + *ppdata > end_of_smb) {
3362 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3363 *ppdata, data_count, (data_count + *ppdata),
3364 end_of_smb, pSMBr);
3365 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003366 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003367 cFYI(1, "parm count and data count larger than SMB");
3368 return -EINVAL;
3369 }
3370 *pdatalen = data_count;
3371 *pparmlen = parm_count;
3372 return 0;
3373}
3374
Steve French0a4b92c2006-01-12 15:44:21 -08003375/* Get Security Descriptor (by handle) from remote server for a file or dir */
3376int
Steve French96daf2b2011-05-27 04:34:02 +00003377CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003378 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003379{
3380 int rc = 0;
3381 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003382 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003383 struct kvec iov[1];
3384
Joe Perchesb6b38f72010-04-21 03:50:45 +00003385 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003386
Steve French630f3f02007-10-25 21:17:17 +00003387 *pbuflen = 0;
3388 *acl_inf = NULL;
3389
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003390 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003391 8 /* parm len */, tcon, (void **) &pSMB);
3392 if (rc)
3393 return rc;
3394
3395 pSMB->MaxParameterCount = cpu_to_le32(4);
3396 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3397 pSMB->MaxSetupCount = 0;
3398 pSMB->Fid = fid; /* file handle always le */
3399 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3400 CIFS_ACL_DACL);
3401 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003402 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003403 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003404 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003405
Steve Frencha761ac52007-10-18 21:45:27 +00003406 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003407 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003408 cifs_stats_inc(&tcon->num_acl_get);
3409 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003410 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003411 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003412 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003413 __u32 parm_len;
3414 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003415 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003416 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003417
3418/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003419 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003420 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003421 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003422 goto qsec_out;
3423 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3424
Joe Perchesb6b38f72010-04-21 03:50:45 +00003425 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003426
3427 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3428 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003429 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003430 goto qsec_out;
3431 }
3432
3433/* BB check that data area is minimum length and as big as acl_len */
3434
Steve Frenchaf6f4612007-10-16 18:40:37 +00003435 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003436 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003437 cERROR(1, "acl length %d does not match %d",
3438 acl_len, *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003439 if (*pbuflen > acl_len)
3440 *pbuflen = acl_len;
3441 }
Steve French0a4b92c2006-01-12 15:44:21 -08003442
Steve French630f3f02007-10-25 21:17:17 +00003443 /* check if buffer is big enough for the acl
3444 header followed by the smallest SID */
3445 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3446 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003447 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003448 rc = -EINVAL;
3449 *pbuflen = 0;
3450 } else {
3451 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3452 if (*acl_inf == NULL) {
3453 *pbuflen = 0;
3454 rc = -ENOMEM;
3455 }
3456 memcpy(*acl_inf, pdata, *pbuflen);
3457 }
Steve French0a4b92c2006-01-12 15:44:21 -08003458 }
3459qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003460 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003461 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003462 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003463 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003464/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003465 return rc;
3466}
Steve French97837582007-12-31 07:47:21 +00003467
3468int
Steve French96daf2b2011-05-27 04:34:02 +00003469CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French97837582007-12-31 07:47:21 +00003470 struct cifs_ntsd *pntsd, __u32 acllen)
3471{
3472 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3473 int rc = 0;
3474 int bytes_returned = 0;
3475 SET_SEC_DESC_REQ *pSMB = NULL;
3476 NTRANSACT_RSP *pSMBr = NULL;
3477
3478setCifsAclRetry:
3479 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3480 (void **) &pSMBr);
3481 if (rc)
3482 return (rc);
3483
3484 pSMB->MaxSetupCount = 0;
3485 pSMB->Reserved = 0;
3486
3487 param_count = 8;
3488 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3489 data_count = acllen;
3490 data_offset = param_offset + param_count;
3491 byte_count = 3 /* pad */ + param_count;
3492
3493 pSMB->DataCount = cpu_to_le32(data_count);
3494 pSMB->TotalDataCount = pSMB->DataCount;
3495 pSMB->MaxParameterCount = cpu_to_le32(4);
3496 pSMB->MaxDataCount = cpu_to_le32(16384);
3497 pSMB->ParameterCount = cpu_to_le32(param_count);
3498 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3499 pSMB->TotalParameterCount = pSMB->ParameterCount;
3500 pSMB->DataOffset = cpu_to_le32(data_offset);
3501 pSMB->SetupCount = 0;
3502 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3503 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3504
3505 pSMB->Fid = fid; /* file handle always le */
3506 pSMB->Reserved2 = 0;
3507 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3508
3509 if (pntsd && acllen) {
3510 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3511 (char *) pntsd,
3512 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003513 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003514 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003515 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003516
3517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3518 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3519
Joe Perchesb6b38f72010-04-21 03:50:45 +00003520 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003521 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003522 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003523 cifs_buf_release(pSMB);
3524
3525 if (rc == -EAGAIN)
3526 goto setCifsAclRetry;
3527
3528 return (rc);
3529}
3530
Jeff Layton79df1ba2010-12-06 12:52:08 -05003531#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003532
Steve French6b8edfe2005-08-23 20:26:03 -07003533/* Legacy Query Path Information call for lookup to old servers such
3534 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003535int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003536 const unsigned char *searchName,
3537 FILE_ALL_INFO *pFinfo,
3538 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003539{
Steve Frenchad7a2922008-02-07 23:25:02 +00003540 QUERY_INFORMATION_REQ *pSMB;
3541 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003542 int rc = 0;
3543 int bytes_returned;
3544 int name_len;
3545
Joe Perchesb6b38f72010-04-21 03:50:45 +00003546 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003547QInfRetry:
3548 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003549 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003550 if (rc)
3551 return rc;
3552
3553 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3554 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003555 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3556 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003557 name_len++; /* trailing null */
3558 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003559 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003560 name_len = strnlen(searchName, PATH_MAX);
3561 name_len++; /* trailing null */
3562 strncpy(pSMB->FileName, searchName, name_len);
3563 }
3564 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003565 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003566 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003567 pSMB->ByteCount = cpu_to_le16(name_len);
3568
3569 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003570 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003571 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003572 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003573 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003574 struct timespec ts;
3575 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003576
3577 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003578 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003579 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003580 ts.tv_nsec = 0;
3581 ts.tv_sec = time;
3582 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003583 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003584 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3585 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003586 pFinfo->AllocationSize =
3587 cpu_to_le64(le32_to_cpu(pSMBr->size));
3588 pFinfo->EndOfFile = pFinfo->AllocationSize;
3589 pFinfo->Attributes =
3590 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003591 } else
3592 rc = -EIO; /* bad buffer passed in */
3593
3594 cifs_buf_release(pSMB);
3595
3596 if (rc == -EAGAIN)
3597 goto QInfRetry;
3598
3599 return rc;
3600}
3601
Jeff Laytonbcd53572010-02-12 07:44:16 -05003602int
Steve French96daf2b2011-05-27 04:34:02 +00003603CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003604 u16 netfid, FILE_ALL_INFO *pFindData)
3605{
3606 struct smb_t2_qfi_req *pSMB = NULL;
3607 struct smb_t2_qfi_rsp *pSMBr = NULL;
3608 int rc = 0;
3609 int bytes_returned;
3610 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003611
Jeff Laytonbcd53572010-02-12 07:44:16 -05003612QFileInfoRetry:
3613 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3614 (void **) &pSMBr);
3615 if (rc)
3616 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003617
Jeff Laytonbcd53572010-02-12 07:44:16 -05003618 params = 2 /* level */ + 2 /* fid */;
3619 pSMB->t2.TotalDataCount = 0;
3620 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3621 /* BB find exact max data count below from sess structure BB */
3622 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3623 pSMB->t2.MaxSetupCount = 0;
3624 pSMB->t2.Reserved = 0;
3625 pSMB->t2.Flags = 0;
3626 pSMB->t2.Timeout = 0;
3627 pSMB->t2.Reserved2 = 0;
3628 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3629 Fid) - 4);
3630 pSMB->t2.DataCount = 0;
3631 pSMB->t2.DataOffset = 0;
3632 pSMB->t2.SetupCount = 1;
3633 pSMB->t2.Reserved3 = 0;
3634 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3635 byte_count = params + 1 /* pad */ ;
3636 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3637 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3638 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3639 pSMB->Pad = 0;
3640 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003641 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003642
3643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3645 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003646 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003647 } else { /* decode response */
3648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3649
3650 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3651 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003652 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003653 rc = -EIO; /* bad smb */
3654 else if (pFindData) {
3655 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3656 memcpy((char *) pFindData,
3657 (char *) &pSMBr->hdr.Protocol +
3658 data_offset, sizeof(FILE_ALL_INFO));
3659 } else
3660 rc = -ENOMEM;
3661 }
3662 cifs_buf_release(pSMB);
3663 if (rc == -EAGAIN)
3664 goto QFileInfoRetry;
3665
3666 return rc;
3667}
Steve French6b8edfe2005-08-23 20:26:03 -07003668
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669int
Steve French96daf2b2011-05-27 04:34:02 +00003670CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003672 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003673 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003674 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675{
3676/* level 263 SMB_QUERY_FILE_ALL_INFO */
3677 TRANSACTION2_QPI_REQ *pSMB = NULL;
3678 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3679 int rc = 0;
3680 int bytes_returned;
3681 int name_len;
3682 __u16 params, byte_count;
3683
Joe Perchesb6b38f72010-04-21 03:50:45 +00003684/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685QPathInfoRetry:
3686 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3687 (void **) &pSMBr);
3688 if (rc)
3689 return rc;
3690
3691 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3692 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003693 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003694 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 name_len++; /* trailing null */
3696 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003697 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 name_len = strnlen(searchName, PATH_MAX);
3699 name_len++; /* trailing null */
3700 strncpy(pSMB->FileName, searchName, name_len);
3701 }
3702
Steve French50c2f752007-07-13 00:33:32 +00003703 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 pSMB->TotalDataCount = 0;
3705 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003706 /* BB find exact max SMB PDU from sess structure BB */
3707 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 pSMB->MaxSetupCount = 0;
3709 pSMB->Reserved = 0;
3710 pSMB->Flags = 0;
3711 pSMB->Timeout = 0;
3712 pSMB->Reserved2 = 0;
3713 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003714 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 pSMB->DataCount = 0;
3716 pSMB->DataOffset = 0;
3717 pSMB->SetupCount = 1;
3718 pSMB->Reserved3 = 0;
3719 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3720 byte_count = params + 1 /* pad */ ;
3721 pSMB->TotalParameterCount = cpu_to_le16(params);
3722 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003723 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003724 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3725 else
3726 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003728 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 pSMB->ByteCount = cpu_to_le16(byte_count);
3730
3731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3733 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003734 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 } else { /* decode response */
3736 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3737
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003738 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3739 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003740 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003742 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003743 rc = -EIO; /* 24 or 26 expected but we do not read
3744 last field */
3745 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003746 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003748
3749 /* On legacy responses we do not read the last field,
3750 EAsize, fortunately since it varies by subdialect and
3751 also note it differs on Set vs. Get, ie two bytes or 4
3752 bytes depending but we don't care here */
3753 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003754 size = sizeof(FILE_INFO_STANDARD);
3755 else
3756 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 memcpy((char *) pFindData,
3758 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003759 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 } else
3761 rc = -ENOMEM;
3762 }
3763 cifs_buf_release(pSMB);
3764 if (rc == -EAGAIN)
3765 goto QPathInfoRetry;
3766
3767 return rc;
3768}
3769
3770int
Steve French96daf2b2011-05-27 04:34:02 +00003771CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003772 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3773{
3774 struct smb_t2_qfi_req *pSMB = NULL;
3775 struct smb_t2_qfi_rsp *pSMBr = NULL;
3776 int rc = 0;
3777 int bytes_returned;
3778 __u16 params, byte_count;
3779
3780UnixQFileInfoRetry:
3781 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3782 (void **) &pSMBr);
3783 if (rc)
3784 return rc;
3785
3786 params = 2 /* level */ + 2 /* fid */;
3787 pSMB->t2.TotalDataCount = 0;
3788 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3789 /* BB find exact max data count below from sess structure BB */
3790 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3791 pSMB->t2.MaxSetupCount = 0;
3792 pSMB->t2.Reserved = 0;
3793 pSMB->t2.Flags = 0;
3794 pSMB->t2.Timeout = 0;
3795 pSMB->t2.Reserved2 = 0;
3796 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3797 Fid) - 4);
3798 pSMB->t2.DataCount = 0;
3799 pSMB->t2.DataOffset = 0;
3800 pSMB->t2.SetupCount = 1;
3801 pSMB->t2.Reserved3 = 0;
3802 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3803 byte_count = params + 1 /* pad */ ;
3804 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3805 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3806 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3807 pSMB->Pad = 0;
3808 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003809 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003810
3811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3813 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003814 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003815 } else { /* decode response */
3816 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3817
Jeff Layton820a8032011-05-04 08:05:26 -04003818 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003819 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003820 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003821 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003822 rc = -EIO; /* bad smb */
3823 } else {
3824 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3825 memcpy((char *) pFindData,
3826 (char *) &pSMBr->hdr.Protocol +
3827 data_offset,
3828 sizeof(FILE_UNIX_BASIC_INFO));
3829 }
3830 }
3831
3832 cifs_buf_release(pSMB);
3833 if (rc == -EAGAIN)
3834 goto UnixQFileInfoRetry;
3835
3836 return rc;
3837}
3838
3839int
Steve French96daf2b2011-05-27 04:34:02 +00003840CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003842 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003843 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844{
3845/* SMB_QUERY_FILE_UNIX_BASIC */
3846 TRANSACTION2_QPI_REQ *pSMB = NULL;
3847 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3848 int rc = 0;
3849 int bytes_returned = 0;
3850 int name_len;
3851 __u16 params, byte_count;
3852
Joe Perchesb6b38f72010-04-21 03:50:45 +00003853 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854UnixQPathInfoRetry:
3855 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3856 (void **) &pSMBr);
3857 if (rc)
3858 return rc;
3859
3860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3861 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003862 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003863 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 name_len++; /* trailing null */
3865 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003866 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 name_len = strnlen(searchName, PATH_MAX);
3868 name_len++; /* trailing null */
3869 strncpy(pSMB->FileName, searchName, name_len);
3870 }
3871
Steve French50c2f752007-07-13 00:33:32 +00003872 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 pSMB->TotalDataCount = 0;
3874 pSMB->MaxParameterCount = cpu_to_le16(2);
3875 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003876 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 pSMB->MaxSetupCount = 0;
3878 pSMB->Reserved = 0;
3879 pSMB->Flags = 0;
3880 pSMB->Timeout = 0;
3881 pSMB->Reserved2 = 0;
3882 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003883 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 pSMB->DataCount = 0;
3885 pSMB->DataOffset = 0;
3886 pSMB->SetupCount = 1;
3887 pSMB->Reserved3 = 0;
3888 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3889 byte_count = params + 1 /* pad */ ;
3890 pSMB->TotalParameterCount = cpu_to_le16(params);
3891 pSMB->ParameterCount = pSMB->TotalParameterCount;
3892 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3893 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003894 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 pSMB->ByteCount = cpu_to_le16(byte_count);
3896
3897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3899 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003900 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 } else { /* decode response */
3902 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3903
Jeff Layton820a8032011-05-04 08:05:26 -04003904 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003905 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003906 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003907 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 rc = -EIO; /* bad smb */
3909 } else {
3910 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3911 memcpy((char *) pFindData,
3912 (char *) &pSMBr->hdr.Protocol +
3913 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003914 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 }
3916 }
3917 cifs_buf_release(pSMB);
3918 if (rc == -EAGAIN)
3919 goto UnixQPathInfoRetry;
3920
3921 return rc;
3922}
3923
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924/* xid, tcon, searchName and codepage are input parms, rest are returned */
3925int
Steve French96daf2b2011-05-27 04:34:02 +00003926CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003927 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003929 __u16 *pnetfid,
3930 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931{
3932/* level 257 SMB_ */
3933 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3934 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003935 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 int rc = 0;
3937 int bytes_returned = 0;
3938 int name_len;
3939 __u16 params, byte_count;
3940
Joe Perchesb6b38f72010-04-21 03:50:45 +00003941 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942
3943findFirstRetry:
3944 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3945 (void **) &pSMBr);
3946 if (rc)
3947 return rc;
3948
3949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3950 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003951 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003952 PATH_MAX, nls_codepage, remap);
3953 /* We can not add the asterik earlier in case
3954 it got remapped to 0xF03A as if it were part of the
3955 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003957 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003958 pSMB->FileName[name_len+1] = 0;
3959 pSMB->FileName[name_len+2] = '*';
3960 pSMB->FileName[name_len+3] = 0;
3961 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3963 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003964 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 } else { /* BB add check for overrun of SMB buf BB */
3966 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003968 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 free buffer exit; BB */
3970 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003971 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003972 pSMB->FileName[name_len+1] = '*';
3973 pSMB->FileName[name_len+2] = 0;
3974 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 }
3976
3977 params = 12 + name_len /* includes null */ ;
3978 pSMB->TotalDataCount = 0; /* no EAs */
3979 pSMB->MaxParameterCount = cpu_to_le16(10);
3980 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3981 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3982 pSMB->MaxSetupCount = 0;
3983 pSMB->Reserved = 0;
3984 pSMB->Flags = 0;
3985 pSMB->Timeout = 0;
3986 pSMB->Reserved2 = 0;
3987 byte_count = params + 1 /* pad */ ;
3988 pSMB->TotalParameterCount = cpu_to_le16(params);
3989 pSMB->ParameterCount = pSMB->TotalParameterCount;
3990 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003991 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3992 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 pSMB->DataCount = 0;
3994 pSMB->DataOffset = 0;
3995 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3996 pSMB->Reserved3 = 0;
3997 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3998 pSMB->SearchAttributes =
3999 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4000 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004001 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4002 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 CIFS_SEARCH_RETURN_RESUME);
4004 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4005
4006 /* BB what should we set StorageType to? Does it matter? BB */
4007 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004008 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 pSMB->ByteCount = cpu_to_le16(byte_count);
4010
4011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004013 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
Steve French88274812006-03-09 22:21:45 +00004015 if (rc) {/* BB add logic to retry regular search if Unix search
4016 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004018 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004019
Steve French88274812006-03-09 22:21:45 +00004020 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
4022 /* BB eventually could optimize out free and realloc of buf */
4023 /* for this case */
4024 if (rc == -EAGAIN)
4025 goto findFirstRetry;
4026 } else { /* decode response */
4027 /* BB remember to free buffer if error BB */
4028 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004029 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004030 unsigned int lnoff;
4031
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004033 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 else
Steve French4b18f2a2008-04-29 00:06:05 +00004035 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036
4037 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004038 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004039 psrch_inf->srch_entries_start =
4040 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4043 le16_to_cpu(pSMBr->t2.ParameterOffset));
4044
Steve French790fe572007-07-07 19:25:05 +00004045 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004046 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 else
Steve French4b18f2a2008-04-29 00:06:05 +00004048 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049
Steve French50c2f752007-07-13 00:33:32 +00004050 psrch_inf->entries_in_buffer =
4051 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004052 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004054 lnoff = le16_to_cpu(parms->LastNameOffset);
4055 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4056 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004057 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004058 psrch_inf->last_entry = NULL;
4059 return rc;
4060 }
4061
Steve French0752f152008-10-07 20:03:33 +00004062 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004063 lnoff;
4064
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 *pnetfid = parms->SearchHandle;
4066 } else {
4067 cifs_buf_release(pSMB);
4068 }
4069 }
4070
4071 return rc;
4072}
4073
Steve French96daf2b2011-05-27 04:34:02 +00004074int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004075 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076{
4077 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4078 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004079 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 char *response_data;
4081 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004082 int bytes_returned;
4083 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 __u16 params, byte_count;
4085
Joe Perchesb6b38f72010-04-21 03:50:45 +00004086 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087
Steve French4b18f2a2008-04-29 00:06:05 +00004088 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089 return -ENOENT;
4090
4091 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4092 (void **) &pSMBr);
4093 if (rc)
4094 return rc;
4095
Steve French50c2f752007-07-13 00:33:32 +00004096 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097 byte_count = 0;
4098 pSMB->TotalDataCount = 0; /* no EAs */
4099 pSMB->MaxParameterCount = cpu_to_le16(8);
4100 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00004101 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
4102 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004103 pSMB->MaxSetupCount = 0;
4104 pSMB->Reserved = 0;
4105 pSMB->Flags = 0;
4106 pSMB->Timeout = 0;
4107 pSMB->Reserved2 = 0;
4108 pSMB->ParameterOffset = cpu_to_le16(
4109 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4110 pSMB->DataCount = 0;
4111 pSMB->DataOffset = 0;
4112 pSMB->SetupCount = 1;
4113 pSMB->Reserved3 = 0;
4114 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4115 pSMB->SearchHandle = searchHandle; /* always kept as le */
4116 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00004117 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4119 pSMB->ResumeKey = psrch_inf->resume_key;
4120 pSMB->SearchFlags =
4121 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4122
4123 name_len = psrch_inf->resume_name_len;
4124 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004125 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4127 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004128 /* 14 byte parm len above enough for 2 byte null terminator */
4129 pSMB->ResumeFileName[name_len] = 0;
4130 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 } else {
4132 rc = -EINVAL;
4133 goto FNext2_err_exit;
4134 }
4135 byte_count = params + 1 /* pad */ ;
4136 pSMB->TotalParameterCount = cpu_to_le16(params);
4137 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004138 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004140
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004143 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 if (rc) {
4145 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004146 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004147 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004148 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004150 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 } else { /* decode response */
4152 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004153
Steve French790fe572007-07-07 19:25:05 +00004154 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004155 unsigned int lnoff;
4156
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 /* BB fixme add lock for file (srch_info) struct here */
4158 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004159 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 else
Steve French4b18f2a2008-04-29 00:06:05 +00004161 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 response_data = (char *) &pSMBr->hdr.Protocol +
4163 le16_to_cpu(pSMBr->t2.ParameterOffset);
4164 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4165 response_data = (char *)&pSMBr->hdr.Protocol +
4166 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004167 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004168 cifs_small_buf_release(
4169 psrch_inf->ntwrk_buf_start);
4170 else
4171 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 psrch_inf->srch_entries_start = response_data;
4173 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004174 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004175 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004176 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 else
Steve French4b18f2a2008-04-29 00:06:05 +00004178 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004179 psrch_inf->entries_in_buffer =
4180 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 psrch_inf->index_of_last_entry +=
4182 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004183 lnoff = le16_to_cpu(parms->LastNameOffset);
4184 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4185 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004186 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004187 psrch_inf->last_entry = NULL;
4188 return rc;
4189 } else
4190 psrch_inf->last_entry =
4191 psrch_inf->srch_entries_start + lnoff;
4192
Joe Perchesb6b38f72010-04-21 03:50:45 +00004193/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4194 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195
4196 /* BB fixme add unlock here */
4197 }
4198
4199 }
4200
4201 /* BB On error, should we leave previous search buf (and count and
4202 last entry fields) intact or free the previous one? */
4203
4204 /* Note: On -EAGAIN error only caller can retry on handle based calls
4205 since file handle passed in no longer valid */
4206FNext2_err_exit:
4207 if (rc != 0)
4208 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 return rc;
4210}
4211
4212int
Steve French96daf2b2011-05-27 04:34:02 +00004213CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004214 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215{
4216 int rc = 0;
4217 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218
Joe Perchesb6b38f72010-04-21 03:50:45 +00004219 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4221
4222 /* no sense returning error if session restarted
4223 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004224 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 return 0;
4226 if (rc)
4227 return rc;
4228
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 pSMB->FileID = searchHandle;
4230 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004231 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004232 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004233 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004234
Steve Frencha4544342005-08-24 13:59:35 -07004235 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
4237 /* Since session is dead, search handle closed on server already */
4238 if (rc == -EAGAIN)
4239 rc = 0;
4240
4241 return rc;
4242}
4243
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244int
Steve French96daf2b2011-05-27 04:34:02 +00004245CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004246 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004247 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004248 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249{
4250 int rc = 0;
4251 TRANSACTION2_QPI_REQ *pSMB = NULL;
4252 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4253 int name_len, bytes_returned;
4254 __u16 params, byte_count;
4255
Joe Perchesb6b38f72010-04-21 03:50:45 +00004256 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004257 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004258 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259
4260GetInodeNumberRetry:
4261 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004262 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 if (rc)
4264 return rc;
4265
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4267 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004268 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004269 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 name_len++; /* trailing null */
4271 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004272 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 name_len = strnlen(searchName, PATH_MAX);
4274 name_len++; /* trailing null */
4275 strncpy(pSMB->FileName, searchName, name_len);
4276 }
4277
4278 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4279 pSMB->TotalDataCount = 0;
4280 pSMB->MaxParameterCount = cpu_to_le16(2);
4281 /* BB find exact max data count below from sess structure BB */
4282 pSMB->MaxDataCount = cpu_to_le16(4000);
4283 pSMB->MaxSetupCount = 0;
4284 pSMB->Reserved = 0;
4285 pSMB->Flags = 0;
4286 pSMB->Timeout = 0;
4287 pSMB->Reserved2 = 0;
4288 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004289 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 pSMB->DataCount = 0;
4291 pSMB->DataOffset = 0;
4292 pSMB->SetupCount = 1;
4293 pSMB->Reserved3 = 0;
4294 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4295 byte_count = params + 1 /* pad */ ;
4296 pSMB->TotalParameterCount = cpu_to_le16(params);
4297 pSMB->ParameterCount = pSMB->TotalParameterCount;
4298 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4299 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004300 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 pSMB->ByteCount = cpu_to_le16(byte_count);
4302
4303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4305 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004306 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 } else {
4308 /* decode response */
4309 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004311 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 /* If rc should we check for EOPNOSUPP and
4313 disable the srvino flag? or in caller? */
4314 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004315 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4317 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004318 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004320 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004321 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 rc = -EIO;
4323 goto GetInodeNumOut;
4324 }
4325 pfinfo = (struct file_internal_info *)
4326 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004327 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 }
4329 }
4330GetInodeNumOut:
4331 cifs_buf_release(pSMB);
4332 if (rc == -EAGAIN)
4333 goto GetInodeNumberRetry;
4334 return rc;
4335}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336
Igor Mammedovfec45852008-05-16 13:06:30 +04004337/* parses DFS refferal V3 structure
4338 * caller is responsible for freeing target_nodes
4339 * returns:
4340 * on success - 0
4341 * on failure - errno
4342 */
4343static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004344parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004345 unsigned int *num_of_nodes,
4346 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004347 const struct nls_table *nls_codepage, int remap,
4348 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004349{
4350 int i, rc = 0;
4351 char *data_end;
4352 bool is_unicode;
4353 struct dfs_referral_level_3 *ref;
4354
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004355 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4356 is_unicode = true;
4357 else
4358 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004359 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4360
4361 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004362 cERROR(1, "num_referrals: must be at least > 0,"
4363 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004364 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004365 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004366 }
4367
4368 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004369 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004370 cERROR(1, "Referrals of V%d version are not supported,"
4371 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004372 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004373 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004374 }
4375
4376 /* get the upper boundary of the resp buffer */
4377 data_end = (char *)(&(pSMBr->PathConsumed)) +
4378 le16_to_cpu(pSMBr->t2.DataCount);
4379
Steve Frenchf19159d2010-04-21 04:12:10 +00004380 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004381 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004382 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004383
4384 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4385 *num_of_nodes, GFP_KERNEL);
4386 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004387 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004388 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004389 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004390 }
4391
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004392 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004393 for (i = 0; i < *num_of_nodes; i++) {
4394 char *temp;
4395 int max_len;
4396 struct dfs_info3_param *node = (*target_nodes)+i;
4397
Steve French0e0d2cf2009-05-01 05:27:32 +00004398 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004399 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004400 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4401 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004402 if (tmp == NULL) {
4403 rc = -ENOMEM;
4404 goto parse_DFS_referrals_exit;
4405 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004406 cifsConvertToUCS((__le16 *) tmp, searchName,
4407 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004408 node->path_consumed = cifs_ucs2_bytes(tmp,
4409 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004410 nls_codepage);
4411 kfree(tmp);
4412 } else
4413 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4414
Igor Mammedovfec45852008-05-16 13:06:30 +04004415 node->server_type = le16_to_cpu(ref->ServerType);
4416 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4417
4418 /* copy DfsPath */
4419 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4420 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004421 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4422 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004423 if (!node->path_name) {
4424 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004425 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004426 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004427
4428 /* copy link target UNC */
4429 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4430 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004431 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4432 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004433 if (!node->node_name)
4434 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004435 }
4436
Steve Frencha1fe78f2008-05-16 18:48:38 +00004437parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004438 if (rc) {
4439 free_dfs_info_array(*target_nodes, *num_of_nodes);
4440 *target_nodes = NULL;
4441 *num_of_nodes = 0;
4442 }
4443 return rc;
4444}
4445
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446int
Steve French96daf2b2011-05-27 04:34:02 +00004447CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004449 struct dfs_info3_param **target_nodes,
4450 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004451 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452{
4453/* TRANS2_GET_DFS_REFERRAL */
4454 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4455 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 int rc = 0;
4457 int bytes_returned;
4458 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004460 *num_of_nodes = 0;
4461 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462
Joe Perchesb6b38f72010-04-21 03:50:45 +00004463 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 if (ses == NULL)
4465 return -ENODEV;
4466getDFSRetry:
4467 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4468 (void **) &pSMBr);
4469 if (rc)
4470 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004471
4472 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004473 but should never be null here anyway */
4474 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 pSMB->hdr.Tid = ses->ipc_tid;
4476 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004477 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004479 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481
4482 if (ses->capabilities & CAP_UNICODE) {
4483 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4484 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004485 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004486 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 name_len++; /* trailing null */
4488 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004489 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 name_len = strnlen(searchName, PATH_MAX);
4491 name_len++; /* trailing null */
4492 strncpy(pSMB->RequestFileName, searchName, name_len);
4493 }
4494
Steve French790fe572007-07-07 19:25:05 +00004495 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004496 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004497 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4498 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4499 }
4500
Steve French50c2f752007-07-13 00:33:32 +00004501 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004502
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 params = 2 /* level */ + name_len /*includes null */ ;
4504 pSMB->TotalDataCount = 0;
4505 pSMB->DataCount = 0;
4506 pSMB->DataOffset = 0;
4507 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004508 /* BB find exact max SMB PDU from sess structure BB */
4509 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 pSMB->MaxSetupCount = 0;
4511 pSMB->Reserved = 0;
4512 pSMB->Flags = 0;
4513 pSMB->Timeout = 0;
4514 pSMB->Reserved2 = 0;
4515 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004516 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 pSMB->SetupCount = 1;
4518 pSMB->Reserved3 = 0;
4519 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4520 byte_count = params + 3 /* pad */ ;
4521 pSMB->ParameterCount = cpu_to_le16(params);
4522 pSMB->TotalParameterCount = pSMB->ParameterCount;
4523 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004524 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 pSMB->ByteCount = cpu_to_le16(byte_count);
4526
4527 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4528 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4529 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004530 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004531 goto GetDFSRefExit;
4532 }
4533 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004535 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004536 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004537 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004538 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004540
Joe Perchesb6b38f72010-04-21 03:50:45 +00004541 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004542 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004543 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004544
4545 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004546 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004547 target_nodes, nls_codepage, remap,
4548 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004549
Linus Torvalds1da177e2005-04-16 15:20:36 -07004550GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004551 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552
4553 if (rc == -EAGAIN)
4554 goto getDFSRetry;
4555
4556 return rc;
4557}
4558
Steve French20962432005-09-21 22:05:57 -07004559/* Query File System Info such as free space to old servers such as Win 9x */
4560int
Steve French96daf2b2011-05-27 04:34:02 +00004561SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004562{
4563/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4564 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4565 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4566 FILE_SYSTEM_ALLOC_INFO *response_data;
4567 int rc = 0;
4568 int bytes_returned = 0;
4569 __u16 params, byte_count;
4570
Joe Perchesb6b38f72010-04-21 03:50:45 +00004571 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004572oldQFSInfoRetry:
4573 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4574 (void **) &pSMBr);
4575 if (rc)
4576 return rc;
Steve French20962432005-09-21 22:05:57 -07004577
4578 params = 2; /* level */
4579 pSMB->TotalDataCount = 0;
4580 pSMB->MaxParameterCount = cpu_to_le16(2);
4581 pSMB->MaxDataCount = cpu_to_le16(1000);
4582 pSMB->MaxSetupCount = 0;
4583 pSMB->Reserved = 0;
4584 pSMB->Flags = 0;
4585 pSMB->Timeout = 0;
4586 pSMB->Reserved2 = 0;
4587 byte_count = params + 1 /* pad */ ;
4588 pSMB->TotalParameterCount = cpu_to_le16(params);
4589 pSMB->ParameterCount = pSMB->TotalParameterCount;
4590 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4591 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4592 pSMB->DataCount = 0;
4593 pSMB->DataOffset = 0;
4594 pSMB->SetupCount = 1;
4595 pSMB->Reserved3 = 0;
4596 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4597 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004598 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004599 pSMB->ByteCount = cpu_to_le16(byte_count);
4600
4601 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4602 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4603 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004604 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004605 } else { /* decode response */
4606 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4607
Jeff Layton820a8032011-05-04 08:05:26 -04004608 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004609 rc = -EIO; /* bad smb */
4610 else {
4611 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004612 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004613 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004614
Steve French50c2f752007-07-13 00:33:32 +00004615 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004616 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4617 FSData->f_bsize =
4618 le16_to_cpu(response_data->BytesPerSector) *
4619 le32_to_cpu(response_data->
4620 SectorsPerAllocationUnit);
4621 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004622 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004623 FSData->f_bfree = FSData->f_bavail =
4624 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004625 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4626 (unsigned long long)FSData->f_blocks,
4627 (unsigned long long)FSData->f_bfree,
4628 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004629 }
4630 }
4631 cifs_buf_release(pSMB);
4632
4633 if (rc == -EAGAIN)
4634 goto oldQFSInfoRetry;
4635
4636 return rc;
4637}
4638
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639int
Steve French96daf2b2011-05-27 04:34:02 +00004640CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641{
4642/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4643 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4644 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4645 FILE_SYSTEM_INFO *response_data;
4646 int rc = 0;
4647 int bytes_returned = 0;
4648 __u16 params, byte_count;
4649
Joe Perchesb6b38f72010-04-21 03:50:45 +00004650 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651QFSInfoRetry:
4652 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4653 (void **) &pSMBr);
4654 if (rc)
4655 return rc;
4656
4657 params = 2; /* level */
4658 pSMB->TotalDataCount = 0;
4659 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004660 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 pSMB->MaxSetupCount = 0;
4662 pSMB->Reserved = 0;
4663 pSMB->Flags = 0;
4664 pSMB->Timeout = 0;
4665 pSMB->Reserved2 = 0;
4666 byte_count = params + 1 /* pad */ ;
4667 pSMB->TotalParameterCount = cpu_to_le16(params);
4668 pSMB->ParameterCount = pSMB->TotalParameterCount;
4669 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004670 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 pSMB->DataCount = 0;
4672 pSMB->DataOffset = 0;
4673 pSMB->SetupCount = 1;
4674 pSMB->Reserved3 = 0;
4675 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4676 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004677 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 pSMB->ByteCount = cpu_to_le16(byte_count);
4679
4680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4682 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004683 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004685 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686
Jeff Layton820a8032011-05-04 08:05:26 -04004687 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 rc = -EIO; /* bad smb */
4689 else {
4690 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691
4692 response_data =
4693 (FILE_SYSTEM_INFO
4694 *) (((char *) &pSMBr->hdr.Protocol) +
4695 data_offset);
4696 FSData->f_bsize =
4697 le32_to_cpu(response_data->BytesPerSector) *
4698 le32_to_cpu(response_data->
4699 SectorsPerAllocationUnit);
4700 FSData->f_blocks =
4701 le64_to_cpu(response_data->TotalAllocationUnits);
4702 FSData->f_bfree = FSData->f_bavail =
4703 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004704 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4705 (unsigned long long)FSData->f_blocks,
4706 (unsigned long long)FSData->f_bfree,
4707 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 }
4709 }
4710 cifs_buf_release(pSMB);
4711
4712 if (rc == -EAGAIN)
4713 goto QFSInfoRetry;
4714
4715 return rc;
4716}
4717
4718int
Steve French96daf2b2011-05-27 04:34:02 +00004719CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720{
4721/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4722 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4723 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4724 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4725 int rc = 0;
4726 int bytes_returned = 0;
4727 __u16 params, byte_count;
4728
Joe Perchesb6b38f72010-04-21 03:50:45 +00004729 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730QFSAttributeRetry:
4731 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4732 (void **) &pSMBr);
4733 if (rc)
4734 return rc;
4735
4736 params = 2; /* level */
4737 pSMB->TotalDataCount = 0;
4738 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004739 /* BB find exact max SMB PDU from sess structure BB */
4740 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 pSMB->MaxSetupCount = 0;
4742 pSMB->Reserved = 0;
4743 pSMB->Flags = 0;
4744 pSMB->Timeout = 0;
4745 pSMB->Reserved2 = 0;
4746 byte_count = params + 1 /* pad */ ;
4747 pSMB->TotalParameterCount = cpu_to_le16(params);
4748 pSMB->ParameterCount = pSMB->TotalParameterCount;
4749 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004750 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 pSMB->DataCount = 0;
4752 pSMB->DataOffset = 0;
4753 pSMB->SetupCount = 1;
4754 pSMB->Reserved3 = 0;
4755 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4756 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004757 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 pSMB->ByteCount = cpu_to_le16(byte_count);
4759
4760 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4761 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4762 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004763 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 } else { /* decode response */
4765 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4766
Jeff Layton820a8032011-05-04 08:05:26 -04004767 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004768 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 rc = -EIO; /* bad smb */
4770 } else {
4771 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4772 response_data =
4773 (FILE_SYSTEM_ATTRIBUTE_INFO
4774 *) (((char *) &pSMBr->hdr.Protocol) +
4775 data_offset);
4776 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004777 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 }
4779 }
4780 cifs_buf_release(pSMB);
4781
4782 if (rc == -EAGAIN)
4783 goto QFSAttributeRetry;
4784
4785 return rc;
4786}
4787
4788int
Steve French96daf2b2011-05-27 04:34:02 +00004789CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790{
4791/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4792 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4793 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4794 FILE_SYSTEM_DEVICE_INFO *response_data;
4795 int rc = 0;
4796 int bytes_returned = 0;
4797 __u16 params, byte_count;
4798
Joe Perchesb6b38f72010-04-21 03:50:45 +00004799 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800QFSDeviceRetry:
4801 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4802 (void **) &pSMBr);
4803 if (rc)
4804 return rc;
4805
4806 params = 2; /* level */
4807 pSMB->TotalDataCount = 0;
4808 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004809 /* BB find exact max SMB PDU from sess structure BB */
4810 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 pSMB->MaxSetupCount = 0;
4812 pSMB->Reserved = 0;
4813 pSMB->Flags = 0;
4814 pSMB->Timeout = 0;
4815 pSMB->Reserved2 = 0;
4816 byte_count = params + 1 /* pad */ ;
4817 pSMB->TotalParameterCount = cpu_to_le16(params);
4818 pSMB->ParameterCount = pSMB->TotalParameterCount;
4819 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004820 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821
4822 pSMB->DataCount = 0;
4823 pSMB->DataOffset = 0;
4824 pSMB->SetupCount = 1;
4825 pSMB->Reserved3 = 0;
4826 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4827 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004828 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 pSMB->ByteCount = cpu_to_le16(byte_count);
4830
4831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4833 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004834 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 } else { /* decode response */
4836 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4837
Jeff Layton820a8032011-05-04 08:05:26 -04004838 if (rc || get_bcc(&pSMBr->hdr) <
4839 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 rc = -EIO; /* bad smb */
4841 else {
4842 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4843 response_data =
Steve French737b7582005-04-28 22:41:06 -07004844 (FILE_SYSTEM_DEVICE_INFO *)
4845 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 data_offset);
4847 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004848 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849 }
4850 }
4851 cifs_buf_release(pSMB);
4852
4853 if (rc == -EAGAIN)
4854 goto QFSDeviceRetry;
4855
4856 return rc;
4857}
4858
4859int
Steve French96daf2b2011-05-27 04:34:02 +00004860CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861{
4862/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4863 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4864 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4865 FILE_SYSTEM_UNIX_INFO *response_data;
4866 int rc = 0;
4867 int bytes_returned = 0;
4868 __u16 params, byte_count;
4869
Joe Perchesb6b38f72010-04-21 03:50:45 +00004870 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004872 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4873 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 if (rc)
4875 return rc;
4876
4877 params = 2; /* level */
4878 pSMB->TotalDataCount = 0;
4879 pSMB->DataCount = 0;
4880 pSMB->DataOffset = 0;
4881 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004882 /* BB find exact max SMB PDU from sess structure BB */
4883 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884 pSMB->MaxSetupCount = 0;
4885 pSMB->Reserved = 0;
4886 pSMB->Flags = 0;
4887 pSMB->Timeout = 0;
4888 pSMB->Reserved2 = 0;
4889 byte_count = params + 1 /* pad */ ;
4890 pSMB->ParameterCount = cpu_to_le16(params);
4891 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004892 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4893 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 pSMB->SetupCount = 1;
4895 pSMB->Reserved3 = 0;
4896 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4897 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004898 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004899 pSMB->ByteCount = cpu_to_le16(byte_count);
4900
4901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4903 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004904 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 } else { /* decode response */
4906 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4907
Jeff Layton820a8032011-05-04 08:05:26 -04004908 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 rc = -EIO; /* bad smb */
4910 } else {
4911 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4912 response_data =
4913 (FILE_SYSTEM_UNIX_INFO
4914 *) (((char *) &pSMBr->hdr.Protocol) +
4915 data_offset);
4916 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004917 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918 }
4919 }
4920 cifs_buf_release(pSMB);
4921
4922 if (rc == -EAGAIN)
4923 goto QFSUnixRetry;
4924
4925
4926 return rc;
4927}
4928
Jeremy Allisonac670552005-06-22 17:26:35 -07004929int
Steve French96daf2b2011-05-27 04:34:02 +00004930CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004931{
4932/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4933 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4934 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4935 int rc = 0;
4936 int bytes_returned = 0;
4937 __u16 params, param_offset, offset, byte_count;
4938
Joe Perchesb6b38f72010-04-21 03:50:45 +00004939 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004940SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004941 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004942 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4943 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004944 if (rc)
4945 return rc;
4946
4947 params = 4; /* 2 bytes zero followed by info level. */
4948 pSMB->MaxSetupCount = 0;
4949 pSMB->Reserved = 0;
4950 pSMB->Flags = 0;
4951 pSMB->Timeout = 0;
4952 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004953 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4954 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004955 offset = param_offset + params;
4956
4957 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004958 /* BB find exact max SMB PDU from sess structure BB */
4959 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004960 pSMB->SetupCount = 1;
4961 pSMB->Reserved3 = 0;
4962 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4963 byte_count = 1 /* pad */ + params + 12;
4964
4965 pSMB->DataCount = cpu_to_le16(12);
4966 pSMB->ParameterCount = cpu_to_le16(params);
4967 pSMB->TotalDataCount = pSMB->DataCount;
4968 pSMB->TotalParameterCount = pSMB->ParameterCount;
4969 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4970 pSMB->DataOffset = cpu_to_le16(offset);
4971
4972 /* Params. */
4973 pSMB->FileNum = 0;
4974 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4975
4976 /* Data. */
4977 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4978 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4979 pSMB->ClientUnixCap = cpu_to_le64(cap);
4980
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004981 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004982 pSMB->ByteCount = cpu_to_le16(byte_count);
4983
4984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4986 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004987 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004988 } else { /* decode response */
4989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004990 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004991 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004992 }
4993 cifs_buf_release(pSMB);
4994
4995 if (rc == -EAGAIN)
4996 goto SETFSUnixRetry;
4997
4998 return rc;
4999}
5000
5001
Linus Torvalds1da177e2005-04-16 15:20:36 -07005002
5003int
Steve French96daf2b2011-05-27 04:34:02 +00005004CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005005 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006{
5007/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5008 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5009 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5010 FILE_SYSTEM_POSIX_INFO *response_data;
5011 int rc = 0;
5012 int bytes_returned = 0;
5013 __u16 params, byte_count;
5014
Joe Perchesb6b38f72010-04-21 03:50:45 +00005015 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016QFSPosixRetry:
5017 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5018 (void **) &pSMBr);
5019 if (rc)
5020 return rc;
5021
5022 params = 2; /* level */
5023 pSMB->TotalDataCount = 0;
5024 pSMB->DataCount = 0;
5025 pSMB->DataOffset = 0;
5026 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005027 /* BB find exact max SMB PDU from sess structure BB */
5028 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 pSMB->MaxSetupCount = 0;
5030 pSMB->Reserved = 0;
5031 pSMB->Flags = 0;
5032 pSMB->Timeout = 0;
5033 pSMB->Reserved2 = 0;
5034 byte_count = params + 1 /* pad */ ;
5035 pSMB->ParameterCount = cpu_to_le16(params);
5036 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005037 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5038 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005039 pSMB->SetupCount = 1;
5040 pSMB->Reserved3 = 0;
5041 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5042 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005043 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005044 pSMB->ByteCount = cpu_to_le16(byte_count);
5045
5046 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5047 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5048 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005049 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 } else { /* decode response */
5051 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5052
Jeff Layton820a8032011-05-04 08:05:26 -04005053 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 rc = -EIO; /* bad smb */
5055 } else {
5056 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5057 response_data =
5058 (FILE_SYSTEM_POSIX_INFO
5059 *) (((char *) &pSMBr->hdr.Protocol) +
5060 data_offset);
5061 FSData->f_bsize =
5062 le32_to_cpu(response_data->BlockSize);
5063 FSData->f_blocks =
5064 le64_to_cpu(response_data->TotalBlocks);
5065 FSData->f_bfree =
5066 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005067 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 FSData->f_bavail = FSData->f_bfree;
5069 } else {
5070 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005071 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 }
Steve French790fe572007-07-07 19:25:05 +00005073 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005075 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005076 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005077 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005078 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005079 }
5080 }
5081 cifs_buf_release(pSMB);
5082
5083 if (rc == -EAGAIN)
5084 goto QFSPosixRetry;
5085
5086 return rc;
5087}
5088
5089
Steve French50c2f752007-07-13 00:33:32 +00005090/* We can not use write of zero bytes trick to
5091 set file size due to need for large file support. Also note that
5092 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 routine which is only needed to work around a sharing violation bug
5094 in Samba which this routine can run into */
5095
5096int
Steve French96daf2b2011-05-27 04:34:02 +00005097CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005098 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005099 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005100{
5101 struct smb_com_transaction2_spi_req *pSMB = NULL;
5102 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5103 struct file_end_of_file_info *parm_data;
5104 int name_len;
5105 int rc = 0;
5106 int bytes_returned = 0;
5107 __u16 params, byte_count, data_count, param_offset, offset;
5108
Joe Perchesb6b38f72010-04-21 03:50:45 +00005109 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005110SetEOFRetry:
5111 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5112 (void **) &pSMBr);
5113 if (rc)
5114 return rc;
5115
5116 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5117 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005118 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005119 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 name_len++; /* trailing null */
5121 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005122 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 name_len = strnlen(fileName, PATH_MAX);
5124 name_len++; /* trailing null */
5125 strncpy(pSMB->FileName, fileName, name_len);
5126 }
5127 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005128 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005130 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 pSMB->MaxSetupCount = 0;
5132 pSMB->Reserved = 0;
5133 pSMB->Flags = 0;
5134 pSMB->Timeout = 0;
5135 pSMB->Reserved2 = 0;
5136 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005137 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005139 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005140 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5141 pSMB->InformationLevel =
5142 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5143 else
5144 pSMB->InformationLevel =
5145 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5146 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5148 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005149 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 else
5151 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005152 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005153 }
5154
5155 parm_data =
5156 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5157 offset);
5158 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5159 pSMB->DataOffset = cpu_to_le16(offset);
5160 pSMB->SetupCount = 1;
5161 pSMB->Reserved3 = 0;
5162 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5163 byte_count = 3 /* pad */ + params + data_count;
5164 pSMB->DataCount = cpu_to_le16(data_count);
5165 pSMB->TotalDataCount = pSMB->DataCount;
5166 pSMB->ParameterCount = cpu_to_le16(params);
5167 pSMB->TotalParameterCount = pSMB->ParameterCount;
5168 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005169 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 parm_data->FileSize = cpu_to_le64(size);
5171 pSMB->ByteCount = cpu_to_le16(byte_count);
5172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005174 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005175 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176
5177 cifs_buf_release(pSMB);
5178
5179 if (rc == -EAGAIN)
5180 goto SetEOFRetry;
5181
5182 return rc;
5183}
5184
5185int
Steve French96daf2b2011-05-27 04:34:02 +00005186CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005187 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188{
5189 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 struct file_end_of_file_info *parm_data;
5191 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192 __u16 params, param_offset, offset, byte_count, count;
5193
Joe Perchesb6b38f72010-04-21 03:50:45 +00005194 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5195 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005196 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5197
Linus Torvalds1da177e2005-04-16 15:20:36 -07005198 if (rc)
5199 return rc;
5200
5201 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5202 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005203
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 params = 6;
5205 pSMB->MaxSetupCount = 0;
5206 pSMB->Reserved = 0;
5207 pSMB->Flags = 0;
5208 pSMB->Timeout = 0;
5209 pSMB->Reserved2 = 0;
5210 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5211 offset = param_offset + params;
5212
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 count = sizeof(struct file_end_of_file_info);
5214 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005215 /* BB find exact max SMB PDU from sess structure BB */
5216 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 pSMB->SetupCount = 1;
5218 pSMB->Reserved3 = 0;
5219 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5220 byte_count = 3 /* pad */ + params + count;
5221 pSMB->DataCount = cpu_to_le16(count);
5222 pSMB->ParameterCount = cpu_to_le16(params);
5223 pSMB->TotalDataCount = pSMB->DataCount;
5224 pSMB->TotalParameterCount = pSMB->ParameterCount;
5225 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5226 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005227 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5228 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 pSMB->DataOffset = cpu_to_le16(offset);
5230 parm_data->FileSize = cpu_to_le64(size);
5231 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005232 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5234 pSMB->InformationLevel =
5235 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5236 else
5237 pSMB->InformationLevel =
5238 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005239 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5241 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005242 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 else
5244 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005245 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 }
5247 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005248 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005250 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005252 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 }
5254
Steve French50c2f752007-07-13 00:33:32 +00005255 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005256 since file handle passed in no longer valid */
5257
5258 return rc;
5259}
5260
Steve French50c2f752007-07-13 00:33:32 +00005261/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262 an open handle, rather than by pathname - this is awkward due to
5263 potential access conflicts on the open, but it is unavoidable for these
5264 old servers since the only other choice is to go from 100 nanosecond DCE
5265 time and resort to the original setpathinfo level which takes the ancient
5266 DOS time format with 2 second granularity */
5267int
Steve French96daf2b2011-05-27 04:34:02 +00005268CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005269 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270{
5271 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005272 char *data_offset;
5273 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274 __u16 params, param_offset, offset, byte_count, count;
5275
Joe Perchesb6b38f72010-04-21 03:50:45 +00005276 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005277 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5278
Linus Torvalds1da177e2005-04-16 15:20:36 -07005279 if (rc)
5280 return rc;
5281
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005282 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5283 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005284
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285 params = 6;
5286 pSMB->MaxSetupCount = 0;
5287 pSMB->Reserved = 0;
5288 pSMB->Flags = 0;
5289 pSMB->Timeout = 0;
5290 pSMB->Reserved2 = 0;
5291 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5292 offset = param_offset + params;
5293
Steve French50c2f752007-07-13 00:33:32 +00005294 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295
Steve French26f57362007-08-30 22:09:15 +00005296 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005298 /* BB find max SMB PDU from sess */
5299 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300 pSMB->SetupCount = 1;
5301 pSMB->Reserved3 = 0;
5302 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5303 byte_count = 3 /* pad */ + params + count;
5304 pSMB->DataCount = cpu_to_le16(count);
5305 pSMB->ParameterCount = cpu_to_le16(params);
5306 pSMB->TotalDataCount = pSMB->DataCount;
5307 pSMB->TotalParameterCount = pSMB->ParameterCount;
5308 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5309 pSMB->DataOffset = cpu_to_le16(offset);
5310 pSMB->Fid = fid;
5311 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5312 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5313 else
5314 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5315 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005316 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005318 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005319 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005320 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005321 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005322
Steve French50c2f752007-07-13 00:33:32 +00005323 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324 since file handle passed in no longer valid */
5325
5326 return rc;
5327}
5328
Jeff Layton6d22f092008-09-23 11:48:35 -04005329int
Steve French96daf2b2011-05-27 04:34:02 +00005330CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005331 bool delete_file, __u16 fid, __u32 pid_of_opener)
5332{
5333 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5334 char *data_offset;
5335 int rc = 0;
5336 __u16 params, param_offset, offset, byte_count, count;
5337
Joe Perchesb6b38f72010-04-21 03:50:45 +00005338 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005339 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5340
5341 if (rc)
5342 return rc;
5343
5344 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5345 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5346
5347 params = 6;
5348 pSMB->MaxSetupCount = 0;
5349 pSMB->Reserved = 0;
5350 pSMB->Flags = 0;
5351 pSMB->Timeout = 0;
5352 pSMB->Reserved2 = 0;
5353 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5354 offset = param_offset + params;
5355
5356 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5357
5358 count = 1;
5359 pSMB->MaxParameterCount = cpu_to_le16(2);
5360 /* BB find max SMB PDU from sess */
5361 pSMB->MaxDataCount = cpu_to_le16(1000);
5362 pSMB->SetupCount = 1;
5363 pSMB->Reserved3 = 0;
5364 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5365 byte_count = 3 /* pad */ + params + count;
5366 pSMB->DataCount = cpu_to_le16(count);
5367 pSMB->ParameterCount = cpu_to_le16(params);
5368 pSMB->TotalDataCount = pSMB->DataCount;
5369 pSMB->TotalParameterCount = pSMB->ParameterCount;
5370 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5371 pSMB->DataOffset = cpu_to_le16(offset);
5372 pSMB->Fid = fid;
5373 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5374 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005375 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005376 pSMB->ByteCount = cpu_to_le16(byte_count);
5377 *data_offset = delete_file ? 1 : 0;
5378 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5379 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005380 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005381
5382 return rc;
5383}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384
5385int
Steve French96daf2b2011-05-27 04:34:02 +00005386CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005387 const char *fileName, const FILE_BASIC_INFO *data,
5388 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389{
5390 TRANSACTION2_SPI_REQ *pSMB = NULL;
5391 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5392 int name_len;
5393 int rc = 0;
5394 int bytes_returned = 0;
5395 char *data_offset;
5396 __u16 params, param_offset, offset, byte_count, count;
5397
Joe Perchesb6b38f72010-04-21 03:50:45 +00005398 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399
5400SetTimesRetry:
5401 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5402 (void **) &pSMBr);
5403 if (rc)
5404 return rc;
5405
5406 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5407 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005408 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005409 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 name_len++; /* trailing null */
5411 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005412 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005413 name_len = strnlen(fileName, PATH_MAX);
5414 name_len++; /* trailing null */
5415 strncpy(pSMB->FileName, fileName, name_len);
5416 }
5417
5418 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005419 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005421 /* BB find max SMB PDU from sess structure BB */
5422 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 pSMB->MaxSetupCount = 0;
5424 pSMB->Reserved = 0;
5425 pSMB->Flags = 0;
5426 pSMB->Timeout = 0;
5427 pSMB->Reserved2 = 0;
5428 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005429 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 offset = param_offset + params;
5431 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5432 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5433 pSMB->DataOffset = cpu_to_le16(offset);
5434 pSMB->SetupCount = 1;
5435 pSMB->Reserved3 = 0;
5436 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5437 byte_count = 3 /* pad */ + params + count;
5438
5439 pSMB->DataCount = cpu_to_le16(count);
5440 pSMB->ParameterCount = cpu_to_le16(params);
5441 pSMB->TotalDataCount = pSMB->DataCount;
5442 pSMB->TotalParameterCount = pSMB->ParameterCount;
5443 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5444 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5445 else
5446 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5447 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005448 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005449 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 pSMB->ByteCount = cpu_to_le16(byte_count);
5451 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5452 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005453 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005454 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455
5456 cifs_buf_release(pSMB);
5457
5458 if (rc == -EAGAIN)
5459 goto SetTimesRetry;
5460
5461 return rc;
5462}
5463
5464/* Can not be used to set time stamps yet (due to old DOS time format) */
5465/* Can be used to set attributes */
5466#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5467 handling it anyway and NT4 was what we thought it would be needed for
5468 Do not delete it until we prove whether needed for Win9x though */
5469int
Steve French96daf2b2011-05-27 04:34:02 +00005470CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471 __u16 dos_attrs, const struct nls_table *nls_codepage)
5472{
5473 SETATTR_REQ *pSMB = NULL;
5474 SETATTR_RSP *pSMBr = NULL;
5475 int rc = 0;
5476 int bytes_returned;
5477 int name_len;
5478
Joe Perchesb6b38f72010-04-21 03:50:45 +00005479 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480
5481SetAttrLgcyRetry:
5482 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5483 (void **) &pSMBr);
5484 if (rc)
5485 return rc;
5486
5487 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5488 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005489 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 PATH_MAX, nls_codepage);
5491 name_len++; /* trailing null */
5492 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005493 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 name_len = strnlen(fileName, PATH_MAX);
5495 name_len++; /* trailing null */
5496 strncpy(pSMB->fileName, fileName, name_len);
5497 }
5498 pSMB->attr = cpu_to_le16(dos_attrs);
5499 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005500 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005504 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005505 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506
5507 cifs_buf_release(pSMB);
5508
5509 if (rc == -EAGAIN)
5510 goto SetAttrLgcyRetry;
5511
5512 return rc;
5513}
5514#endif /* temporarily unneeded SetAttr legacy function */
5515
Jeff Layton654cf142009-07-09 20:02:49 -04005516static void
5517cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5518 const struct cifs_unix_set_info_args *args)
5519{
5520 u64 mode = args->mode;
5521
5522 /*
5523 * Samba server ignores set of file size to zero due to bugs in some
5524 * older clients, but we should be precise - we use SetFileSize to
5525 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005526 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005527 * zero instead of -1 here
5528 */
5529 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5530 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5531 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5532 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5533 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5534 data_offset->Uid = cpu_to_le64(args->uid);
5535 data_offset->Gid = cpu_to_le64(args->gid);
5536 /* better to leave device as zero when it is */
5537 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5538 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5539 data_offset->Permissions = cpu_to_le64(mode);
5540
5541 if (S_ISREG(mode))
5542 data_offset->Type = cpu_to_le32(UNIX_FILE);
5543 else if (S_ISDIR(mode))
5544 data_offset->Type = cpu_to_le32(UNIX_DIR);
5545 else if (S_ISLNK(mode))
5546 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5547 else if (S_ISCHR(mode))
5548 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5549 else if (S_ISBLK(mode))
5550 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5551 else if (S_ISFIFO(mode))
5552 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5553 else if (S_ISSOCK(mode))
5554 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5555}
5556
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557int
Steve French96daf2b2011-05-27 04:34:02 +00005558CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005559 const struct cifs_unix_set_info_args *args,
5560 u16 fid, u32 pid_of_opener)
5561{
5562 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5563 FILE_UNIX_BASIC_INFO *data_offset;
5564 int rc = 0;
5565 u16 params, param_offset, offset, byte_count, count;
5566
Joe Perchesb6b38f72010-04-21 03:50:45 +00005567 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005568 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5569
5570 if (rc)
5571 return rc;
5572
5573 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5574 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5575
5576 params = 6;
5577 pSMB->MaxSetupCount = 0;
5578 pSMB->Reserved = 0;
5579 pSMB->Flags = 0;
5580 pSMB->Timeout = 0;
5581 pSMB->Reserved2 = 0;
5582 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5583 offset = param_offset + params;
5584
5585 data_offset = (FILE_UNIX_BASIC_INFO *)
5586 ((char *)(&pSMB->hdr.Protocol) + offset);
5587 count = sizeof(FILE_UNIX_BASIC_INFO);
5588
5589 pSMB->MaxParameterCount = cpu_to_le16(2);
5590 /* BB find max SMB PDU from sess */
5591 pSMB->MaxDataCount = cpu_to_le16(1000);
5592 pSMB->SetupCount = 1;
5593 pSMB->Reserved3 = 0;
5594 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5595 byte_count = 3 /* pad */ + params + count;
5596 pSMB->DataCount = cpu_to_le16(count);
5597 pSMB->ParameterCount = cpu_to_le16(params);
5598 pSMB->TotalDataCount = pSMB->DataCount;
5599 pSMB->TotalParameterCount = pSMB->ParameterCount;
5600 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5601 pSMB->DataOffset = cpu_to_le16(offset);
5602 pSMB->Fid = fid;
5603 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5604 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005605 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005606 pSMB->ByteCount = cpu_to_le16(byte_count);
5607
5608 cifs_fill_unix_set_info(data_offset, args);
5609
5610 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5611 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005612 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005613
5614 /* Note: On -EAGAIN error only caller can retry on handle based calls
5615 since file handle passed in no longer valid */
5616
5617 return rc;
5618}
5619
5620int
Steve French96daf2b2011-05-27 04:34:02 +00005621CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005622 const struct cifs_unix_set_info_args *args,
5623 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624{
5625 TRANSACTION2_SPI_REQ *pSMB = NULL;
5626 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5627 int name_len;
5628 int rc = 0;
5629 int bytes_returned = 0;
5630 FILE_UNIX_BASIC_INFO *data_offset;
5631 __u16 params, param_offset, offset, count, byte_count;
5632
Joe Perchesb6b38f72010-04-21 03:50:45 +00005633 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005634setPermsRetry:
5635 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5636 (void **) &pSMBr);
5637 if (rc)
5638 return rc;
5639
5640 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5641 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005642 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005643 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 name_len++; /* trailing null */
5645 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005646 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 name_len = strnlen(fileName, PATH_MAX);
5648 name_len++; /* trailing null */
5649 strncpy(pSMB->FileName, fileName, name_len);
5650 }
5651
5652 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005653 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005655 /* BB find max SMB PDU from sess structure BB */
5656 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657 pSMB->MaxSetupCount = 0;
5658 pSMB->Reserved = 0;
5659 pSMB->Flags = 0;
5660 pSMB->Timeout = 0;
5661 pSMB->Reserved2 = 0;
5662 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005663 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664 offset = param_offset + params;
5665 data_offset =
5666 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5667 offset);
5668 memset(data_offset, 0, count);
5669 pSMB->DataOffset = cpu_to_le16(offset);
5670 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5671 pSMB->SetupCount = 1;
5672 pSMB->Reserved3 = 0;
5673 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5674 byte_count = 3 /* pad */ + params + count;
5675 pSMB->ParameterCount = cpu_to_le16(params);
5676 pSMB->DataCount = cpu_to_le16(count);
5677 pSMB->TotalParameterCount = pSMB->ParameterCount;
5678 pSMB->TotalDataCount = pSMB->DataCount;
5679 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5680 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005681 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005682
Jeff Layton654cf142009-07-09 20:02:49 -04005683 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684
5685 pSMB->ByteCount = cpu_to_le16(byte_count);
5686 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5687 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005688 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005689 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690
Steve French0d817bc2008-05-22 02:02:03 +00005691 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005692 if (rc == -EAGAIN)
5693 goto setPermsRetry;
5694 return rc;
5695}
5696
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005698/*
5699 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5700 * function used by listxattr and getxattr type calls. When ea_name is set,
5701 * it looks for that attribute name and stuffs that value into the EAData
5702 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5703 * buffer. In both cases, the return value is either the length of the
5704 * resulting data or a negative error code. If EAData is a NULL pointer then
5705 * the data isn't copied to it, but the length is returned.
5706 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005707ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00005708CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005709 const unsigned char *searchName, const unsigned char *ea_name,
5710 char *EAData, size_t buf_size,
5711 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005712{
5713 /* BB assumes one setup word */
5714 TRANSACTION2_QPI_REQ *pSMB = NULL;
5715 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5716 int rc = 0;
5717 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005718 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005719 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005720 struct fea *temp_fea;
5721 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005722 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005723 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04005724 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725
Joe Perchesb6b38f72010-04-21 03:50:45 +00005726 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727QAllEAsRetry:
5728 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5729 (void **) &pSMBr);
5730 if (rc)
5731 return rc;
5732
5733 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005734 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005735 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005736 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005737 list_len++; /* trailing null */
5738 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005740 list_len = strnlen(searchName, PATH_MAX);
5741 list_len++; /* trailing null */
5742 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005743 }
5744
Jeff Layton6e462b92010-02-10 16:18:26 -05005745 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 pSMB->TotalDataCount = 0;
5747 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005748 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005749 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005750 pSMB->MaxSetupCount = 0;
5751 pSMB->Reserved = 0;
5752 pSMB->Flags = 0;
5753 pSMB->Timeout = 0;
5754 pSMB->Reserved2 = 0;
5755 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005756 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005757 pSMB->DataCount = 0;
5758 pSMB->DataOffset = 0;
5759 pSMB->SetupCount = 1;
5760 pSMB->Reserved3 = 0;
5761 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5762 byte_count = params + 1 /* pad */ ;
5763 pSMB->TotalParameterCount = cpu_to_le16(params);
5764 pSMB->ParameterCount = pSMB->TotalParameterCount;
5765 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5766 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005767 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005768 pSMB->ByteCount = cpu_to_le16(byte_count);
5769
5770 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5771 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5772 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005773 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005774 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005775 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005776
5777
5778 /* BB also check enough total bytes returned */
5779 /* BB we need to improve the validity checking
5780 of these trans2 responses */
5781
5782 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005783 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005784 rc = -EIO; /* bad smb */
5785 goto QAllEAsOut;
5786 }
5787
5788 /* check that length of list is not more than bcc */
5789 /* check that each entry does not go beyond length
5790 of list */
5791 /* check that each element of each entry does not
5792 go beyond end of list */
5793 /* validate_trans2_offsets() */
5794 /* BB check if start of smb + data_offset > &bcc+ bcc */
5795
5796 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5797 ea_response_data = (struct fealist *)
5798 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5799
Jeff Layton6e462b92010-02-10 16:18:26 -05005800 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005801 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005802 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005803 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005804 goto QAllEAsOut;
5805 }
5806
Jeff Layton0cd126b2010-02-10 16:18:26 -05005807 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005808 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005809 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005810 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005811 rc = -EIO;
5812 goto QAllEAsOut;
5813 }
5814
Jeff Laytonf0d38682010-02-10 16:18:26 -05005815 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005816 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005817 temp_fea = ea_response_data->list;
5818 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005819 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005820 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005821 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005822
Jeff Layton6e462b92010-02-10 16:18:26 -05005823 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005824 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005825 /* make sure we can read name_len and value_len */
5826 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005827 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005828 rc = -EIO;
5829 goto QAllEAsOut;
5830 }
5831
5832 name_len = temp_fea->name_len;
5833 value_len = le16_to_cpu(temp_fea->value_len);
5834 list_len -= name_len + 1 + value_len;
5835 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005836 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005837 rc = -EIO;
5838 goto QAllEAsOut;
5839 }
5840
Jeff Layton31c05192010-02-10 16:18:26 -05005841 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04005842 if (ea_name_len == name_len &&
5843 strncmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05005844 temp_ptr += name_len + 1;
5845 rc = value_len;
5846 if (buf_size == 0)
5847 goto QAllEAsOut;
5848 if ((size_t)value_len > buf_size) {
5849 rc = -ERANGE;
5850 goto QAllEAsOut;
5851 }
5852 memcpy(EAData, temp_ptr, value_len);
5853 goto QAllEAsOut;
5854 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005855 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005856 /* account for prefix user. and trailing null */
5857 rc += (5 + 1 + name_len);
5858 if (rc < (int) buf_size) {
5859 memcpy(EAData, "user.", 5);
5860 EAData += 5;
5861 memcpy(EAData, temp_ptr, name_len);
5862 EAData += name_len;
5863 /* null terminate name */
5864 *EAData = 0;
5865 ++EAData;
5866 } else if (buf_size == 0) {
5867 /* skip copy - calc size only */
5868 } else {
5869 /* stop before overrun buffer */
5870 rc = -ERANGE;
5871 break;
5872 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005873 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005874 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005875 temp_fea = (struct fea *)temp_ptr;
5876 }
5877
Jeff Layton31c05192010-02-10 16:18:26 -05005878 /* didn't find the named attribute */
5879 if (ea_name)
5880 rc = -ENODATA;
5881
Jeff Laytonf0d38682010-02-10 16:18:26 -05005882QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005883 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005884 if (rc == -EAGAIN)
5885 goto QAllEAsRetry;
5886
5887 return (ssize_t)rc;
5888}
5889
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890int
Steve French96daf2b2011-05-27 04:34:02 +00005891CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005892 const char *ea_name, const void *ea_value,
5893 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5894 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895{
5896 struct smb_com_transaction2_spi_req *pSMB = NULL;
5897 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5898 struct fealist *parm_data;
5899 int name_len;
5900 int rc = 0;
5901 int bytes_returned = 0;
5902 __u16 params, param_offset, byte_count, offset, count;
5903
Joe Perchesb6b38f72010-04-21 03:50:45 +00005904 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905SetEARetry:
5906 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5907 (void **) &pSMBr);
5908 if (rc)
5909 return rc;
5910
5911 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5912 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005913 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005914 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 name_len++; /* trailing null */
5916 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005917 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005918 name_len = strnlen(fileName, PATH_MAX);
5919 name_len++; /* trailing null */
5920 strncpy(pSMB->FileName, fileName, name_len);
5921 }
5922
5923 params = 6 + name_len;
5924
5925 /* done calculating parms using name_len of file name,
5926 now use name_len to calculate length of ea name
5927 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005928 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 name_len = 0;
5930 else
Steve French50c2f752007-07-13 00:33:32 +00005931 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005933 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005935 /* BB find max SMB PDU from sess */
5936 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005937 pSMB->MaxSetupCount = 0;
5938 pSMB->Reserved = 0;
5939 pSMB->Flags = 0;
5940 pSMB->Timeout = 0;
5941 pSMB->Reserved2 = 0;
5942 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005943 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005944 offset = param_offset + params;
5945 pSMB->InformationLevel =
5946 cpu_to_le16(SMB_SET_FILE_EA);
5947
5948 parm_data =
5949 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5950 offset);
5951 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5952 pSMB->DataOffset = cpu_to_le16(offset);
5953 pSMB->SetupCount = 1;
5954 pSMB->Reserved3 = 0;
5955 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5956 byte_count = 3 /* pad */ + params + count;
5957 pSMB->DataCount = cpu_to_le16(count);
5958 parm_data->list_len = cpu_to_le32(count);
5959 parm_data->list[0].EA_flags = 0;
5960 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005961 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005963 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005964 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005965 parm_data->list[0].name[name_len] = 0;
5966 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5967 /* caller ensures that ea_value_len is less than 64K but
5968 we need to ensure that it fits within the smb */
5969
Steve French50c2f752007-07-13 00:33:32 +00005970 /*BB add length check to see if it would fit in
5971 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005972 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5973 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005974 memcpy(parm_data->list[0].name+name_len+1,
5975 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005976
5977 pSMB->TotalDataCount = pSMB->DataCount;
5978 pSMB->ParameterCount = cpu_to_le16(params);
5979 pSMB->TotalParameterCount = pSMB->ParameterCount;
5980 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005981 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982 pSMB->ByteCount = cpu_to_le16(byte_count);
5983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005985 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005986 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987
5988 cifs_buf_release(pSMB);
5989
5990 if (rc == -EAGAIN)
5991 goto SetEARetry;
5992
5993 return rc;
5994}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005995#endif
Steve French0eff0e22011-02-24 05:39:23 +00005996
5997#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5998/*
5999 * Years ago the kernel added a "dnotify" function for Samba server,
6000 * to allow network clients (such as Windows) to display updated
6001 * lists of files in directory listings automatically when
6002 * files are added by one user when another user has the
6003 * same directory open on their desktop. The Linux cifs kernel
6004 * client hooked into the kernel side of this interface for
6005 * the same reason, but ironically when the VFS moved from
6006 * "dnotify" to "inotify" it became harder to plug in Linux
6007 * network file system clients (the most obvious use case
6008 * for notify interfaces is when multiple users can update
6009 * the contents of the same directory - exactly what network
6010 * file systems can do) although the server (Samba) could
6011 * still use it. For the short term we leave the worker
6012 * function ifdeffed out (below) until inotify is fixed
6013 * in the VFS to make it easier to plug in network file
6014 * system clients. If inotify turns out to be permanently
6015 * incompatible for network fs clients, we could instead simply
6016 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6017 */
Steve French96daf2b2011-05-27 04:34:02 +00006018int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006019 const int notify_subdirs, const __u16 netfid,
6020 __u32 filter, struct file *pfile, int multishot,
6021 const struct nls_table *nls_codepage)
6022{
6023 int rc = 0;
6024 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6025 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6026 struct dir_notify_req *dnotify_req;
6027 int bytes_returned;
6028
6029 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6030 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6031 (void **) &pSMBr);
6032 if (rc)
6033 return rc;
6034
6035 pSMB->TotalParameterCount = 0 ;
6036 pSMB->TotalDataCount = 0;
6037 pSMB->MaxParameterCount = cpu_to_le32(2);
6038 /* BB find exact data count max from sess structure BB */
6039 pSMB->MaxDataCount = 0; /* same in little endian or be */
6040/* BB VERIFY verify which is correct for above BB */
6041 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
6042 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
6043
6044 pSMB->MaxSetupCount = 4;
6045 pSMB->Reserved = 0;
6046 pSMB->ParameterOffset = 0;
6047 pSMB->DataCount = 0;
6048 pSMB->DataOffset = 0;
6049 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6050 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6051 pSMB->ParameterCount = pSMB->TotalParameterCount;
6052 if (notify_subdirs)
6053 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6054 pSMB->Reserved2 = 0;
6055 pSMB->CompletionFilter = cpu_to_le32(filter);
6056 pSMB->Fid = netfid; /* file handle always le */
6057 pSMB->ByteCount = 0;
6058
6059 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6060 (struct smb_hdr *)pSMBr, &bytes_returned,
6061 CIFS_ASYNC_OP);
6062 if (rc) {
6063 cFYI(1, "Error in Notify = %d", rc);
6064 } else {
6065 /* Add file to outstanding requests */
6066 /* BB change to kmem cache alloc */
6067 dnotify_req = kmalloc(
6068 sizeof(struct dir_notify_req),
6069 GFP_KERNEL);
6070 if (dnotify_req) {
6071 dnotify_req->Pid = pSMB->hdr.Pid;
6072 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6073 dnotify_req->Mid = pSMB->hdr.Mid;
6074 dnotify_req->Tid = pSMB->hdr.Tid;
6075 dnotify_req->Uid = pSMB->hdr.Uid;
6076 dnotify_req->netfid = netfid;
6077 dnotify_req->pfile = pfile;
6078 dnotify_req->filter = filter;
6079 dnotify_req->multishot = multishot;
6080 spin_lock(&GlobalMid_Lock);
6081 list_add_tail(&dnotify_req->lhead,
6082 &GlobalDnotifyReqList);
6083 spin_unlock(&GlobalMid_Lock);
6084 } else
6085 rc = -ENOMEM;
6086 }
6087 cifs_buf_release(pSMB);
6088 return rc;
6089}
6090#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */