blob: 0613df4d8e744b91f037a7a455d0450fe7fd49ee [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);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400456 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000457 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000458 /* even though we do not use raw we might as well set this
459 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000460 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000462 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
463 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000464 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000465 server->capabilities = CAP_MPX_MODE;
466 }
Steve Frenchb815f1e2006-10-02 05:53:29 +0000467 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000468 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000469 /* OS/2 often does not set timezone therefore
470 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000471 * Could deviate slightly from the right zone.
472 * Smallest defined timezone difference is 15 minutes
473 * (i.e. Nepal). Rounding up/down is done to match
474 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000475 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000476 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000477 struct timespec ts, utc;
478 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400479 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
480 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000482 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000483 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000484 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000485 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000486 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000487 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000488 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000489 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000490 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000491 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000492 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000493 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000494 server->timeAdj = (int)tmp;
495 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000496 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000497 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000498
Steve French39798772006-05-31 22:40:51 +0000499
Steve French254e55e2006-06-04 05:53:15 +0000500 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000501 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000502
Steve French50c2f752007-07-13 00:33:32 +0000503 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000504 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500505 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000506 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000507 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000508 rc = -EIO; /* need cryptkey unless plain text */
509 goto neg_err_exit;
510 }
Steve French39798772006-05-31 22:40:51 +0000511
Steve Frenchf19159d2010-04-21 04:12:10 +0000512 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000513 /* we will not end up setting signing flags - as no signing
514 was in LANMAN and server did not return the flags on */
515 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000516#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000517 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000518 cERROR(1, "mount failed, cifs module not built "
519 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300520 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000521#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000522 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000523 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000524 /* unknown wct */
525 rc = -EOPNOTSUPP;
526 goto neg_err_exit;
527 }
528 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000529 server->sec_mode = pSMBr->SecurityMode;
530 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000531 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000532
Steve French96daf2b2011-05-27 04:34:02 +0000533 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000534#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000535 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000536#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000537 cERROR(1, "Server requests plain text password"
538 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000539
Steve French790fe572007-07-07 19:25:05 +0000540 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000541 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000542 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000543 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000544 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000545 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000546 else if (secFlags & CIFSSEC_MAY_KRB5)
547 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000549 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_LANMAN)
551 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000552 else {
553 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000554 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000555 goto neg_err_exit;
556 }
557 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000558
Steve French254e55e2006-06-04 05:53:15 +0000559 /* one byte, so no need to convert this or EncryptionKeyLen from
560 little endian */
561 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
562 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400563 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000564 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000565 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000566 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e2006-10-02 05:53:29 +0000567 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
568 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000569 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500570 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000571 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000572 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
573 server->capabilities & CAP_EXTENDED_SECURITY) &&
574 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000575 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400576 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000577 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000579 goto neg_err_exit;
580 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530581 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500582 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530583 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000584 if (memcmp(server->server_GUID,
585 pSMBr->u.extended_response.
586 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000587 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000588 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000589 pSMBr->u.extended_response.GUID,
590 16);
591 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500592 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530593 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000594 memcpy(server->server_GUID,
595 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500596 }
Jeff Laytone187e442007-10-16 17:10:44 +0000597
598 if (count == 16) {
599 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000600 } else {
601 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400602 SecurityBlob, count - 16,
603 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000604 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000605 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000606 else
Steve French254e55e2006-06-04 05:53:15 +0000607 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500608 if (server->secType == Kerberos) {
609 if (!server->sec_kerberos &&
610 !server->sec_mskerberos)
611 rc = -EOPNOTSUPP;
612 } else if (server->secType == RawNTLMSSP) {
613 if (!server->sec_ntlmssp)
614 rc = -EOPNOTSUPP;
615 } else
616 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Steve French96daf2b2011-05-27 04:34:02 +0000618 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000619 rc = -EIO; /* no crypt key only if plain text pwd */
620 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000621 } else
622 server->capabilities &= ~CAP_EXTENDED_SECURITY;
623
Steve French6344a422006-06-12 04:18:35 +0000624#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000625signing_check:
Steve French6344a422006-06-12 04:18:35 +0000626#endif
Steve French762e5ab2007-06-28 18:41:42 +0000627 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
628 /* MUST_SIGN already includes the MAY_SIGN FLAG
629 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000630 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000631 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000632 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000633 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000634 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000635 rc = -EOPNOTSUPP;
636 }
Steve French96daf2b2011-05-27 04:34:02 +0000637 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000638 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000639 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
640 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000642 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000643 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000644 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000645 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else
Steve French96daf2b2011-05-27 04:34:02 +0000647 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000648 } else {
649 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000650 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
651 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000652 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Steve French50c2f752007-07-13 00:33:32 +0000654
655neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700656 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000657
Joe Perchesb6b38f72010-04-21 03:50:45 +0000658 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 return rc;
660}
661
662int
Steve French96daf2b2011-05-27 04:34:02 +0000663CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Joe Perchesb6b38f72010-04-21 03:50:45 +0000668 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500669
670 /* BB: do we need to check this? These should never be NULL. */
671 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
672 return -EIO;
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675 * No need to return error on this operation if tid invalidated and
676 * closed on server already e.g. due to tcp session crashing. Also,
677 * the tcon is no longer on the list, so no need to take lock before
678 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 */
Steve French268875b2009-06-25 00:29:21 +0000680 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Steve French50c2f752007-07-13 00:33:32 +0000683 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700684 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500685 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return rc;
Steve French133672e2007-11-13 22:41:37 +0000687
688 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000690 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Steve French50c2f752007-07-13 00:33:32 +0000692 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500693 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (rc == -EAGAIN)
695 rc = 0;
696
697 return rc;
698}
699
Jeff Layton766fdbb2011-01-11 07:24:21 -0500700/*
701 * This is a no-op for now. We're not really interested in the reply, but
702 * rather in the fact that the server sent one and that server->lstrp
703 * gets updated.
704 *
705 * FIXME: maybe we should consider checking that the reply matches request?
706 */
707static void
708cifs_echo_callback(struct mid_q_entry *mid)
709{
710 struct TCP_Server_Info *server = mid->callback_data;
711
712 DeleteMidQEntry(mid);
713 atomic_dec(&server->inFlight);
714 wake_up(&server->request_q);
715}
716
717int
718CIFSSMBEcho(struct TCP_Server_Info *server)
719{
720 ECHO_REQ *smb;
721 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400722 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500723
724 cFYI(1, "In echo request");
725
726 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
727 if (rc)
728 return rc;
729
730 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000731 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500732 smb->hdr.WordCount = 1;
733 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400734 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500735 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000736 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400737 iov.iov_base = smb;
738 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500739
Jeff Layton44d22d82011-10-19 15:29:49 -0400740 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
741 server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742 if (rc)
743 cFYI(1, "Echo request failed: %d", rc);
744
745 cifs_small_buf_release(smb);
746
747 return rc;
748}
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750int
Steve French96daf2b2011-05-27 04:34:02 +0000751CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 LOGOFF_ANDX_REQ *pSMB;
754 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755
Joe Perchesb6b38f72010-04-21 03:50:45 +0000756 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500757
758 /*
759 * BB: do we need to check validity of ses and server? They should
760 * always be valid since we have an active reference. If not, that
761 * should probably be a BUG()
762 */
763 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return -EIO;
765
Steve Frenchd7b619c2010-02-25 05:36:46 +0000766 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000767 if (ses->need_reconnect)
768 goto session_already_dead; /* no need to send SMBlogoff if uid
769 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
771 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000772 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return rc;
774 }
775
Steve French3b795212008-11-13 19:45:32 +0000776 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700777
Steve French96daf2b2011-05-27 04:34:02 +0000778 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
780 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 pSMB->hdr.Uid = ses->Suid;
783
784 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000785 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000786session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000787 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
789 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000790 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 error */
792 if (rc == -EAGAIN)
793 rc = 0;
794 return rc;
795}
796
797int
Steve French96daf2b2011-05-27 04:34:02 +0000798CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000799 __u16 type, const struct nls_table *nls_codepage, int remap)
800{
801 TRANSACTION2_SPI_REQ *pSMB = NULL;
802 TRANSACTION2_SPI_RSP *pSMBr = NULL;
803 struct unlink_psx_rq *pRqD;
804 int name_len;
805 int rc = 0;
806 int bytes_returned = 0;
807 __u16 params, param_offset, offset, byte_count;
808
Joe Perchesb6b38f72010-04-21 03:50:45 +0000809 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000810PsxDelete:
811 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
812 (void **) &pSMBr);
813 if (rc)
814 return rc;
815
816 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
817 name_len =
818 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
819 PATH_MAX, nls_codepage, remap);
820 name_len++; /* trailing null */
821 name_len *= 2;
822 } else { /* BB add path length overrun check */
823 name_len = strnlen(fileName, PATH_MAX);
824 name_len++; /* trailing null */
825 strncpy(pSMB->FileName, fileName, name_len);
826 }
827
828 params = 6 + name_len;
829 pSMB->MaxParameterCount = cpu_to_le16(2);
830 pSMB->MaxDataCount = 0; /* BB double check this with jra */
831 pSMB->MaxSetupCount = 0;
832 pSMB->Reserved = 0;
833 pSMB->Flags = 0;
834 pSMB->Timeout = 0;
835 pSMB->Reserved2 = 0;
836 param_offset = offsetof(struct smb_com_transaction2_spi_req,
837 InformationLevel) - 4;
838 offset = param_offset + params;
839
840 /* Setup pointer to Request Data (inode type) */
841 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
842 pRqD->type = cpu_to_le16(type);
843 pSMB->ParameterOffset = cpu_to_le16(param_offset);
844 pSMB->DataOffset = cpu_to_le16(offset);
845 pSMB->SetupCount = 1;
846 pSMB->Reserved3 = 0;
847 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
848 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
849
850 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
851 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
852 pSMB->ParameterCount = cpu_to_le16(params);
853 pSMB->TotalParameterCount = pSMB->ParameterCount;
854 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
855 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000856 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000857 pSMB->ByteCount = cpu_to_le16(byte_count);
858 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000860 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000861 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000862 cifs_buf_release(pSMB);
863
864 cifs_stats_inc(&tcon->num_deletes);
865
866 if (rc == -EAGAIN)
867 goto PsxDelete;
868
869 return rc;
870}
871
872int
Steve French96daf2b2011-05-27 04:34:02 +0000873CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700874 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875{
876 DELETE_FILE_REQ *pSMB = NULL;
877 DELETE_FILE_RSP *pSMBr = NULL;
878 int rc = 0;
879 int bytes_returned;
880 int name_len;
881
882DelFileRetry:
883 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
884 (void **) &pSMBr);
885 if (rc)
886 return rc;
887
888 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
889 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000890 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700891 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 name_len++; /* trailing null */
893 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700894 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 name_len = strnlen(fileName, PATH_MAX);
896 name_len++; /* trailing null */
897 strncpy(pSMB->fileName, fileName, name_len);
898 }
899 pSMB->SearchAttributes =
900 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
901 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000902 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 pSMB->ByteCount = cpu_to_le16(name_len + 1);
904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700906 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000907 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000908 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909
910 cifs_buf_release(pSMB);
911 if (rc == -EAGAIN)
912 goto DelFileRetry;
913
914 return rc;
915}
916
917int
Steve French96daf2b2011-05-27 04:34:02 +0000918CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700919 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920{
921 DELETE_DIRECTORY_REQ *pSMB = NULL;
922 DELETE_DIRECTORY_RSP *pSMBr = NULL;
923 int rc = 0;
924 int bytes_returned;
925 int name_len;
926
Joe Perchesb6b38f72010-04-21 03:50:45 +0000927 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928RmDirRetry:
929 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
930 (void **) &pSMBr);
931 if (rc)
932 return rc;
933
934 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700935 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
936 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 name_len++; /* trailing null */
938 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700939 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 name_len = strnlen(dirName, PATH_MAX);
941 name_len++; /* trailing null */
942 strncpy(pSMB->DirName, dirName, name_len);
943 }
944
945 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000946 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 pSMB->ByteCount = cpu_to_le16(name_len + 1);
948 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
949 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700950 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000951 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000952 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 cifs_buf_release(pSMB);
955 if (rc == -EAGAIN)
956 goto RmDirRetry;
957 return rc;
958}
959
960int
Steve French96daf2b2011-05-27 04:34:02 +0000961CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700962 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
964 int rc = 0;
965 CREATE_DIRECTORY_REQ *pSMB = NULL;
966 CREATE_DIRECTORY_RSP *pSMBr = NULL;
967 int bytes_returned;
968 int name_len;
969
Joe Perchesb6b38f72010-04-21 03:50:45 +0000970 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971MkDirRetry:
972 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
973 (void **) &pSMBr);
974 if (rc)
975 return rc;
976
977 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000978 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700979 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 name_len++; /* trailing null */
981 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700982 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 name_len = strnlen(name, PATH_MAX);
984 name_len++; /* trailing null */
985 strncpy(pSMB->DirName, name, name_len);
986 }
987
988 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000989 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 pSMB->ByteCount = cpu_to_le16(name_len + 1);
991 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
992 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700993 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000994 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000995 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 cifs_buf_release(pSMB);
998 if (rc == -EAGAIN)
999 goto MkDirRetry;
1000 return rc;
1001}
1002
Steve French2dd29d32007-04-23 22:07:35 +00001003int
Steve French96daf2b2011-05-27 04:34:02 +00001004CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001005 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001006 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001007 const struct nls_table *nls_codepage, int remap)
1008{
1009 TRANSACTION2_SPI_REQ *pSMB = NULL;
1010 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1011 int name_len;
1012 int rc = 0;
1013 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001014 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001015 OPEN_PSX_REQ *pdata;
1016 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001017
Joe Perchesb6b38f72010-04-21 03:50:45 +00001018 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001019PsxCreat:
1020 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1021 (void **) &pSMBr);
1022 if (rc)
1023 return rc;
1024
1025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1026 name_len =
1027 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1028 PATH_MAX, nls_codepage, remap);
1029 name_len++; /* trailing null */
1030 name_len *= 2;
1031 } else { /* BB improve the check for buffer overruns BB */
1032 name_len = strnlen(name, PATH_MAX);
1033 name_len++; /* trailing null */
1034 strncpy(pSMB->FileName, name, name_len);
1035 }
1036
1037 params = 6 + name_len;
1038 count = sizeof(OPEN_PSX_REQ);
1039 pSMB->MaxParameterCount = cpu_to_le16(2);
1040 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1041 pSMB->MaxSetupCount = 0;
1042 pSMB->Reserved = 0;
1043 pSMB->Flags = 0;
1044 pSMB->Timeout = 0;
1045 pSMB->Reserved2 = 0;
1046 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001047 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001048 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001049 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001050 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001051 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001052 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001053 pdata->OpenFlags = cpu_to_le32(*pOplock);
1054 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1055 pSMB->DataOffset = cpu_to_le16(offset);
1056 pSMB->SetupCount = 1;
1057 pSMB->Reserved3 = 0;
1058 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1059 byte_count = 3 /* pad */ + params + count;
1060
1061 pSMB->DataCount = cpu_to_le16(count);
1062 pSMB->ParameterCount = cpu_to_le16(params);
1063 pSMB->TotalDataCount = pSMB->DataCount;
1064 pSMB->TotalParameterCount = pSMB->ParameterCount;
1065 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1066 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001067 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001068 pSMB->ByteCount = cpu_to_le16(byte_count);
1069 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1070 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1071 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001072 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001073 goto psx_create_err;
1074 }
1075
Joe Perchesb6b38f72010-04-21 03:50:45 +00001076 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001077 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1078
Jeff Layton820a8032011-05-04 08:05:26 -04001079 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001080 rc = -EIO; /* bad smb */
1081 goto psx_create_err;
1082 }
1083
1084 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001085 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001086 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001087
Steve French2dd29d32007-04-23 22:07:35 +00001088 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001089 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001090 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1091 /* Let caller know file was created so we can set the mode. */
1092 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001093 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001094 *pOplock |= CIFS_CREATE_ACTION;
1095 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001096 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1097 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001098 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001099 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001100 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001101 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001102 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001103 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001104 goto psx_create_err;
1105 }
Steve French50c2f752007-07-13 00:33:32 +00001106 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001107 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001108 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001109 }
Steve French2dd29d32007-04-23 22:07:35 +00001110
1111psx_create_err:
1112 cifs_buf_release(pSMB);
1113
Steve French65bc98b2009-07-10 15:27:25 +00001114 if (posix_flags & SMB_O_DIRECTORY)
1115 cifs_stats_inc(&tcon->num_posixmkdirs);
1116 else
1117 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001118
1119 if (rc == -EAGAIN)
1120 goto PsxCreat;
1121
Steve French50c2f752007-07-13 00:33:32 +00001122 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001123}
1124
Steve Frencha9d02ad2005-08-24 23:06:05 -07001125static __u16 convert_disposition(int disposition)
1126{
1127 __u16 ofun = 0;
1128
1129 switch (disposition) {
1130 case FILE_SUPERSEDE:
1131 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1132 break;
1133 case FILE_OPEN:
1134 ofun = SMBOPEN_OAPPEND;
1135 break;
1136 case FILE_CREATE:
1137 ofun = SMBOPEN_OCREATE;
1138 break;
1139 case FILE_OPEN_IF:
1140 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1141 break;
1142 case FILE_OVERWRITE:
1143 ofun = SMBOPEN_OTRUNC;
1144 break;
1145 case FILE_OVERWRITE_IF:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1147 break;
1148 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001149 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001150 ofun = SMBOPEN_OAPPEND; /* regular open */
1151 }
1152 return ofun;
1153}
1154
Jeff Layton35fc37d2008-05-14 10:22:03 -07001155static int
1156access_flags_to_smbopen_mode(const int access_flags)
1157{
1158 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1159
1160 if (masked_flags == GENERIC_READ)
1161 return SMBOPEN_READ;
1162 else if (masked_flags == GENERIC_WRITE)
1163 return SMBOPEN_WRITE;
1164
1165 /* just go for read/write */
1166 return SMBOPEN_READWRITE;
1167}
1168
Steve Frencha9d02ad2005-08-24 23:06:05 -07001169int
Steve French96daf2b2011-05-27 04:34:02 +00001170SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001171 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001172 const int access_flags, const int create_options, __u16 *netfid,
1173 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 const struct nls_table *nls_codepage, int remap)
1175{
1176 int rc = -EACCES;
1177 OPENX_REQ *pSMB = NULL;
1178 OPENX_RSP *pSMBr = NULL;
1179 int bytes_returned;
1180 int name_len;
1181 __u16 count;
1182
1183OldOpenRetry:
1184 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1185 (void **) &pSMBr);
1186 if (rc)
1187 return rc;
1188
1189 pSMB->AndXCommand = 0xFF; /* none */
1190
1191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1192 count = 1; /* account for one byte pad to word boundary */
1193 name_len =
1194 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1195 fileName, PATH_MAX, nls_codepage, remap);
1196 name_len++; /* trailing null */
1197 name_len *= 2;
1198 } else { /* BB improve check for buffer overruns BB */
1199 count = 0; /* no pad */
1200 name_len = strnlen(fileName, PATH_MAX);
1201 name_len++; /* trailing null */
1202 strncpy(pSMB->fileName, fileName, name_len);
1203 }
1204 if (*pOplock & REQ_OPLOCK)
1205 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001206 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001208
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001210 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001211 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1212 /* set file as system file if special file such
1213 as fifo and server expecting SFU style and
1214 no Unix extensions */
1215
Steve French790fe572007-07-07 19:25:05 +00001216 if (create_options & CREATE_OPTION_SPECIAL)
1217 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001218 else /* BB FIXME BB */
1219 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220
Jeff Layton67750fb2008-05-09 22:28:02 +00001221 if (create_options & CREATE_OPTION_READONLY)
1222 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223
1224 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001225/* pSMB->CreateOptions = cpu_to_le32(create_options &
1226 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001228
1229 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001230 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001231 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001232 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233
1234 pSMB->ByteCount = cpu_to_le16(count);
1235 /* long_op set to 1 to allow for oplock break timeouts */
1236 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001237 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001238 cifs_stats_inc(&tcon->num_opens);
1239 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001240 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001241 } else {
1242 /* BB verify if wct == 15 */
1243
Steve French582d21e2008-05-13 04:54:12 +00001244/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001245
1246 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1247 /* Let caller know file was created so we can set the mode. */
1248 /* Do we care about the CreateAction in any other cases? */
1249 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001250/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 *pOplock |= CIFS_CREATE_ACTION; */
1252 /* BB FIXME END */
1253
Steve French790fe572007-07-07 19:25:05 +00001254 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001255 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1256 pfile_info->LastAccessTime = 0; /* BB fixme */
1257 pfile_info->LastWriteTime = 0; /* BB fixme */
1258 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001259 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001260 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001262 pfile_info->AllocationSize =
1263 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1264 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001265 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001266 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 }
1268 }
1269
1270 cifs_buf_release(pSMB);
1271 if (rc == -EAGAIN)
1272 goto OldOpenRetry;
1273 return rc;
1274}
1275
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276int
Steve French96daf2b2011-05-27 04:34:02 +00001277CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001279 const int access_flags, const int create_options, __u16 *netfid,
1280 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001281 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
1283 int rc = -EACCES;
1284 OPEN_REQ *pSMB = NULL;
1285 OPEN_RSP *pSMBr = NULL;
1286 int bytes_returned;
1287 int name_len;
1288 __u16 count;
1289
1290openRetry:
1291 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1292 (void **) &pSMBr);
1293 if (rc)
1294 return rc;
1295
1296 pSMB->AndXCommand = 0xFF; /* none */
1297
1298 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1299 count = 1; /* account for one byte pad to word boundary */
1300 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001301 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001302 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 name_len++; /* trailing null */
1304 name_len *= 2;
1305 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001306 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 count = 0; /* no pad */
1308 name_len = strnlen(fileName, PATH_MAX);
1309 name_len++; /* trailing null */
1310 pSMB->NameLength = cpu_to_le16(name_len);
1311 strncpy(pSMB->fileName, fileName, name_len);
1312 }
1313 if (*pOplock & REQ_OPLOCK)
1314 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001315 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1318 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001319 /* set file as system file if special file such
1320 as fifo and server expecting SFU style and
1321 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001322 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001323 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1324 else
1325 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001326
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 /* XP does not handle ATTR_POSIX_SEMANTICS */
1328 /* but it helps speed up case sensitive checks for other
1329 servers such as Samba */
1330 if (tcon->ses->capabilities & CAP_UNIX)
1331 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1332
Jeff Layton67750fb2008-05-09 22:28:02 +00001333 if (create_options & CREATE_OPTION_READONLY)
1334 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1335
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1337 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001338 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001339 /* BB Expirement with various impersonation levels and verify */
1340 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 pSMB->SecurityFlags =
1342 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1343
1344 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001345 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346
1347 pSMB->ByteCount = cpu_to_le16(count);
1348 /* long_op set to 1 to allow for oplock break timeouts */
1349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001350 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001351 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001353 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 } else {
Steve French09d1db52005-04-28 22:41:08 -07001355 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1357 /* Let caller know file was created so we can set the mode. */
1358 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001359 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001360 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001361 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001362 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1363 36 /* CreationTime to Attributes */);
1364 /* the file_info buf is endian converted by caller */
1365 pfile_info->AllocationSize = pSMBr->AllocationSize;
1366 pfile_info->EndOfFile = pSMBr->EndOfFile;
1367 pfile_info->NumberOfLinks = cpu_to_le32(1);
1368 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001371
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 cifs_buf_release(pSMB);
1373 if (rc == -EAGAIN)
1374 goto openRetry;
1375 return rc;
1376}
1377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001379CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001380 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
1382 int rc = -EACCES;
1383 READ_REQ *pSMB = NULL;
1384 READ_RSP *pSMBr = NULL;
1385 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001386 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001387 int resp_buf_type = 0;
1388 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001389 __u32 pid = io_parms->pid;
1390 __u16 netfid = io_parms->netfid;
1391 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001392 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001393 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
Joe Perchesb6b38f72010-04-21 03:50:45 +00001395 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001396 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001397 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001398 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001399 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001400 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001401 /* can not handle this big offset for old */
1402 return -EIO;
1403 }
1404 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
1406 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001407 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 if (rc)
1409 return rc;
1410
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001411 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1412 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1413
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 /* tcon and ses pointer are checked in smb_init */
1415 if (tcon->ses->server == NULL)
1416 return -ECONNABORTED;
1417
Steve Frenchec637e32005-12-12 20:53:18 -08001418 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001420 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001421 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001422 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 pSMB->Remaining = 0;
1425 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1426 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001427 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001428 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1429 else {
1430 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001431 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001432 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001433 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001434 }
Steve Frenchec637e32005-12-12 20:53:18 -08001435
1436 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001437 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001438 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001439 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001440 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001441 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001443 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 } else {
1445 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1446 data_length = data_length << 16;
1447 data_length += le16_to_cpu(pSMBr->DataLength);
1448 *nbytes = data_length;
1449
1450 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001451 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001453 cFYI(1, "bad length %d for count %d",
1454 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 rc = -EIO;
1456 *nbytes = 0;
1457 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001458 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001459 le16_to_cpu(pSMBr->DataOffset);
1460/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001461 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001462 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001463 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001464 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001465 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 }
1467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Steve French4b8f9302006-02-26 16:41:18 +00001469/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001470 if (*buf) {
1471 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001472 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001473 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001474 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001475 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001476 /* return buffer to caller to free */
1477 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001478 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001479 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001480 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001481 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001482 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001483
1484 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 since file handle passed in no longer valid */
1486 return rc;
1487}
1488
Steve Frenchec637e32005-12-12 20:53:18 -08001489
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001491CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1492 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001493 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
1495 int rc = -EACCES;
1496 WRITE_REQ *pSMB = NULL;
1497 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001498 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 __u32 bytes_sent;
1500 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001501 __u32 pid = io_parms->pid;
1502 __u16 netfid = io_parms->netfid;
1503 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001504 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001505 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506
Steve Frencha24e2d72010-04-03 17:20:21 +00001507 *nbytes = 0;
1508
Joe Perchesb6b38f72010-04-21 03:50:45 +00001509 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001510 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001511 return -ECONNABORTED;
1512
Steve French790fe572007-07-07 19:25:05 +00001513 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001514 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001515 else {
Steve French1c955182005-08-30 20:58:07 -07001516 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001517 if ((offset >> 32) > 0) {
1518 /* can not handle big offset for old srv */
1519 return -EIO;
1520 }
1521 }
Steve French1c955182005-08-30 20:58:07 -07001522
1523 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 (void **) &pSMBr);
1525 if (rc)
1526 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001527
1528 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1529 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1530
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 /* tcon and ses pointer are checked in smb_init */
1532 if (tcon->ses->server == NULL)
1533 return -ECONNABORTED;
1534
1535 pSMB->AndXCommand = 0xFF; /* none */
1536 pSMB->Fid = netfid;
1537 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001538 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001539 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001540
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 pSMB->Reserved = 0xFFFFFFFF;
1542 pSMB->WriteMode = 0;
1543 pSMB->Remaining = 0;
1544
Steve French50c2f752007-07-13 00:33:32 +00001545 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 can send more if LARGE_WRITE_X capability returned by the server and if
1547 our buffer is big enough or if we convert to iovecs on socket writes
1548 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001549 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1551 } else {
1552 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1553 & ~0xFF;
1554 }
1555
1556 if (bytes_sent > count)
1557 bytes_sent = count;
1558 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001559 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001560 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001561 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001562 else if (ubuf) {
1563 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 cifs_buf_release(pSMB);
1565 return -EFAULT;
1566 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001567 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 /* No buffer */
1569 cifs_buf_release(pSMB);
1570 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001571 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001572 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001573 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001574 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001575 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1578 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001579 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001580
Steve French790fe572007-07-07 19:25:05 +00001581 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001582 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001583 else { /* old style write has byte count 4 bytes earlier
1584 so 4 bytes pad */
1585 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001586 (struct smb_com_writex_req *)pSMB;
1587 pSMBW->ByteCount = cpu_to_le16(byte_count);
1588 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1591 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001592 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001593 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001594 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 } else {
1596 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1597 *nbytes = (*nbytes) << 16;
1598 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301599
1600 /*
1601 * Mask off high 16 bits when bytes written as returned by the
1602 * server is greater than bytes requested by the client. Some
1603 * OS/2 servers are known to set incorrect CountHigh values.
1604 */
1605 if (*nbytes > count)
1606 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 }
1608
1609 cifs_buf_release(pSMB);
1610
Steve French50c2f752007-07-13 00:33:32 +00001611 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 since file handle passed in no longer valid */
1613
1614 return rc;
1615}
1616
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001617void
1618cifs_writedata_release(struct kref *refcount)
1619{
1620 struct cifs_writedata *wdata = container_of(refcount,
1621 struct cifs_writedata, refcount);
1622
1623 if (wdata->cfile)
1624 cifsFileInfo_put(wdata->cfile);
1625
1626 kfree(wdata);
1627}
1628
1629/*
1630 * Write failed with a retryable error. Resend the write request. It's also
1631 * possible that the page was redirtied so re-clean the page.
1632 */
1633static void
1634cifs_writev_requeue(struct cifs_writedata *wdata)
1635{
1636 int i, rc;
1637 struct inode *inode = wdata->cfile->dentry->d_inode;
1638
1639 for (i = 0; i < wdata->nr_pages; i++) {
1640 lock_page(wdata->pages[i]);
1641 clear_page_dirty_for_io(wdata->pages[i]);
1642 }
1643
1644 do {
1645 rc = cifs_async_writev(wdata);
1646 } while (rc == -EAGAIN);
1647
1648 for (i = 0; i < wdata->nr_pages; i++) {
1649 if (rc != 0)
1650 SetPageError(wdata->pages[i]);
1651 unlock_page(wdata->pages[i]);
1652 }
1653
1654 mapping_set_error(inode->i_mapping, rc);
1655 kref_put(&wdata->refcount, cifs_writedata_release);
1656}
1657
1658static void
1659cifs_writev_complete(struct work_struct *work)
1660{
1661 struct cifs_writedata *wdata = container_of(work,
1662 struct cifs_writedata, work);
1663 struct inode *inode = wdata->cfile->dentry->d_inode;
1664 int i = 0;
1665
1666 if (wdata->result == 0) {
1667 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1668 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1669 wdata->bytes);
1670 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1671 return cifs_writev_requeue(wdata);
1672
1673 for (i = 0; i < wdata->nr_pages; i++) {
1674 struct page *page = wdata->pages[i];
1675 if (wdata->result == -EAGAIN)
1676 __set_page_dirty_nobuffers(page);
1677 else if (wdata->result < 0)
1678 SetPageError(page);
1679 end_page_writeback(page);
1680 page_cache_release(page);
1681 }
1682 if (wdata->result != -EAGAIN)
1683 mapping_set_error(inode->i_mapping, wdata->result);
1684 kref_put(&wdata->refcount, cifs_writedata_release);
1685}
1686
1687struct cifs_writedata *
1688cifs_writedata_alloc(unsigned int nr_pages)
1689{
1690 struct cifs_writedata *wdata;
1691
1692 /* this would overflow */
1693 if (nr_pages == 0) {
1694 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1695 return NULL;
1696 }
1697
1698 /* writedata + number of page pointers */
1699 wdata = kzalloc(sizeof(*wdata) +
1700 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1701 if (wdata != NULL) {
1702 INIT_WORK(&wdata->work, cifs_writev_complete);
1703 kref_init(&wdata->refcount);
1704 }
1705 return wdata;
1706}
1707
1708/*
1709 * Check the midState and signature on received buffer (if any), and queue the
1710 * workqueue completion task.
1711 */
1712static void
1713cifs_writev_callback(struct mid_q_entry *mid)
1714{
1715 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001716 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001717 unsigned int written;
1718 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1719
1720 switch (mid->midState) {
1721 case MID_RESPONSE_RECEIVED:
1722 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1723 if (wdata->result != 0)
1724 break;
1725
1726 written = le16_to_cpu(smb->CountHigh);
1727 written <<= 16;
1728 written += le16_to_cpu(smb->Count);
1729 /*
1730 * Mask off high 16 bits when bytes written as returned
1731 * by the server is greater than bytes requested by the
1732 * client. OS/2 servers are known to set incorrect
1733 * CountHigh values.
1734 */
1735 if (written > wdata->bytes)
1736 written &= 0xFFFF;
1737
1738 if (written < wdata->bytes)
1739 wdata->result = -ENOSPC;
1740 else
1741 wdata->bytes = written;
1742 break;
1743 case MID_REQUEST_SUBMITTED:
1744 case MID_RETRY_NEEDED:
1745 wdata->result = -EAGAIN;
1746 break;
1747 default:
1748 wdata->result = -EIO;
1749 break;
1750 }
1751
1752 queue_work(system_nrt_wq, &wdata->work);
1753 DeleteMidQEntry(mid);
1754 atomic_dec(&tcon->ses->server->inFlight);
1755 wake_up(&tcon->ses->server->request_q);
1756}
1757
1758/* cifs_async_writev - send an async write, and set up mid to handle result */
1759int
1760cifs_async_writev(struct cifs_writedata *wdata)
1761{
1762 int i, rc = -EACCES;
1763 WRITE_REQ *smb = NULL;
1764 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00001765 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001766 struct inode *inode = wdata->cfile->dentry->d_inode;
1767 struct kvec *iov = NULL;
1768
1769 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1770 wct = 14;
1771 } else {
1772 wct = 12;
1773 if (wdata->offset >> 32 > 0) {
1774 /* can not handle big offset for old srv */
1775 return -EIO;
1776 }
1777 }
1778
1779 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
1780 if (rc)
1781 goto async_writev_out;
1782
1783 /* 1 iov per page + 1 for header */
1784 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
1785 if (iov == NULL) {
1786 rc = -ENOMEM;
1787 goto async_writev_out;
1788 }
1789
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001790 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
1791 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
1792
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001793 smb->AndXCommand = 0xFF; /* none */
1794 smb->Fid = wdata->cfile->netfid;
1795 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
1796 if (wct == 14)
1797 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
1798 smb->Reserved = 0xFFFFFFFF;
1799 smb->WriteMode = 0;
1800 smb->Remaining = 0;
1801
1802 smb->DataOffset =
1803 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1804
1805 /* 4 for RFC1001 length + 1 for BCC */
1806 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
1807 iov[0].iov_base = smb;
1808
1809 /* marshal up the pages into iov array */
1810 wdata->bytes = 0;
1811 for (i = 0; i < wdata->nr_pages; i++) {
1812 iov[i + 1].iov_len = min(inode->i_size -
1813 page_offset(wdata->pages[i]),
1814 (loff_t)PAGE_CACHE_SIZE);
1815 iov[i + 1].iov_base = kmap(wdata->pages[i]);
1816 wdata->bytes += iov[i + 1].iov_len;
1817 }
1818
1819 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
1820
1821 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
1822 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
1823
1824 if (wct == 14) {
1825 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
1826 put_bcc(wdata->bytes + 1, &smb->hdr);
1827 } else {
1828 /* wct == 12 */
1829 struct smb_com_writex_req *smbw =
1830 (struct smb_com_writex_req *)smb;
1831 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
1832 put_bcc(wdata->bytes + 5, &smbw->hdr);
1833 iov[0].iov_len += 4; /* pad bigger by four bytes */
1834 }
1835
1836 kref_get(&wdata->refcount);
1837 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
Jeff Layton44d22d82011-10-19 15:29:49 -04001838 NULL, cifs_writev_callback, wdata, false);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001839
1840 if (rc == 0)
1841 cifs_stats_inc(&tcon->num_writes);
1842 else
1843 kref_put(&wdata->refcount, cifs_writedata_release);
1844
1845 /* send is done, unmap pages */
1846 for (i = 0; i < wdata->nr_pages; i++)
1847 kunmap(wdata->pages[i]);
1848
1849async_writev_out:
1850 cifs_small_buf_release(smb);
1851 kfree(iov);
1852 return rc;
1853}
1854
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001855int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001856CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
1857 unsigned int *nbytes, struct kvec *iov, int n_vec,
1858 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859{
1860 int rc = -EACCES;
1861 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001862 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001863 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001864 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001865 __u32 pid = io_parms->pid;
1866 __u16 netfid = io_parms->netfid;
1867 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001868 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001869 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001871 *nbytes = 0;
1872
Joe Perchesb6b38f72010-04-21 03:50:45 +00001873 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001874
Steve French4c3130e2008-12-09 00:28:16 +00001875 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001876 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001877 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001878 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001879 if ((offset >> 32) > 0) {
1880 /* can not handle big offset for old srv */
1881 return -EIO;
1882 }
1883 }
Steve French8cc64c62005-10-03 13:49:43 -07001884 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 if (rc)
1886 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001887
1888 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1889 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1890
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 /* tcon and ses pointer are checked in smb_init */
1892 if (tcon->ses->server == NULL)
1893 return -ECONNABORTED;
1894
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001895 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 pSMB->Fid = netfid;
1897 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001898 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001899 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 pSMB->Reserved = 0xFFFFFFFF;
1901 pSMB->WriteMode = 0;
1902 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001903
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001905 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906
Steve French3e844692005-10-03 13:37:24 -07001907 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1908 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001909 /* header + 1 byte pad */
1910 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001911 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001912 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001913 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001914 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001915 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001916 pSMB->ByteCount = cpu_to_le16(count + 1);
1917 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001918 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001919 (struct smb_com_writex_req *)pSMB;
1920 pSMBW->ByteCount = cpu_to_le16(count + 5);
1921 }
Steve French3e844692005-10-03 13:37:24 -07001922 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001923 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001924 iov[0].iov_len = smb_hdr_len + 4;
1925 else /* wct == 12 pad bigger by four bytes */
1926 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001927
Steve French3e844692005-10-03 13:37:24 -07001928
Steve Frenchec637e32005-12-12 20:53:18 -08001929 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001930 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001931 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001933 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001934 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001935 /* presumably this can not happen, but best to be safe */
1936 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001937 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001938 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001939 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1940 *nbytes = (*nbytes) << 16;
1941 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301942
1943 /*
1944 * Mask off high 16 bits when bytes written as returned by the
1945 * server is greater than bytes requested by the client. OS/2
1946 * servers are known to set incorrect CountHigh values.
1947 */
1948 if (*nbytes > count)
1949 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951
Steve French4b8f9302006-02-26 16:41:18 +00001952/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001953 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001954 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001955 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001956 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Steve French50c2f752007-07-13 00:33:32 +00001958 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 since file handle passed in no longer valid */
1960
1961 return rc;
1962}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001963
1964
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965int
Steve French96daf2b2011-05-27 04:34:02 +00001966CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Pavel Shilovsky03776f42010-08-17 11:26:00 +04001967 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001969 const __u32 numLock, const __u8 lockType,
1970 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971{
1972 int rc = 0;
1973 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001974/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 int bytes_returned;
1976 int timeout = 0;
1977 __u16 count;
1978
Joe Perchesb6b38f72010-04-21 03:50:45 +00001979 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001980 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1981
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 if (rc)
1983 return rc;
1984
Steve French790fe572007-07-07 19:25:05 +00001985 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001986 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001988 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001989 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1991 } else {
1992 pSMB->Timeout = 0;
1993 }
1994
1995 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1996 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1997 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001998 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 pSMB->AndXCommand = 0xFF; /* none */
2000 pSMB->Fid = smb_file_id; /* netfid stays le */
2001
Steve French790fe572007-07-07 19:25:05 +00002002 if ((numLock != 0) || (numUnlock != 0)) {
Pavel Shilovsky03776f42010-08-17 11:26:00 +04002003 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 /* BB where to store pid high? */
2005 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2006 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2007 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2008 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2009 count = sizeof(LOCKING_ANDX_RANGE);
2010 } else {
2011 /* oplock break */
2012 count = 0;
2013 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002014 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015 pSMB->ByteCount = cpu_to_le16(count);
2016
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002017 if (waitFlag) {
2018 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002019 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002020 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002021 } else {
Steve French133672e2007-11-13 22:41:37 +00002022 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2023 timeout);
2024 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002025 }
Steve Frencha4544342005-08-24 13:59:35 -07002026 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002027 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002028 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029
Steve French50c2f752007-07-13 00:33:32 +00002030 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 since file handle passed in no longer valid */
2032 return rc;
2033}
2034
2035int
Steve French96daf2b2011-05-27 04:34:02 +00002036CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Steve French08547b02006-02-28 22:39:25 +00002037 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00002038 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00002039 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002040{
2041 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2042 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002043 struct cifs_posix_lock *parm_data;
2044 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002045 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002046 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002047 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002048 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002049 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002050
Joe Perchesb6b38f72010-04-21 03:50:45 +00002051 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002052
Steve French790fe572007-07-07 19:25:05 +00002053 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002054 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002055
Steve French08547b02006-02-28 22:39:25 +00002056 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2057
2058 if (rc)
2059 return rc;
2060
2061 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2062
Steve French50c2f752007-07-13 00:33:32 +00002063 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002064 pSMB->MaxSetupCount = 0;
2065 pSMB->Reserved = 0;
2066 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002067 pSMB->Reserved2 = 0;
2068 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2069 offset = param_offset + params;
2070
Steve French08547b02006-02-28 22:39:25 +00002071 count = sizeof(struct cifs_posix_lock);
2072 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002073 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002074 pSMB->SetupCount = 1;
2075 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002076 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002077 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2078 else
2079 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2080 byte_count = 3 /* pad */ + params + count;
2081 pSMB->DataCount = cpu_to_le16(count);
2082 pSMB->ParameterCount = cpu_to_le16(params);
2083 pSMB->TotalDataCount = pSMB->DataCount;
2084 pSMB->TotalParameterCount = pSMB->ParameterCount;
2085 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002086 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002087 (((char *) &pSMB->hdr.Protocol) + offset);
2088
2089 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002090 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002091 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002092 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002093 pSMB->Timeout = cpu_to_le32(-1);
2094 } else
2095 pSMB->Timeout = 0;
2096
Steve French08547b02006-02-28 22:39:25 +00002097 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002098 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002099 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002100
2101 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002102 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002103 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2104 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002105 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002106 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002107 if (waitFlag) {
2108 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2109 (struct smb_hdr *) pSMBr, &bytes_returned);
2110 } else {
Steve French133672e2007-11-13 22:41:37 +00002111 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002112 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002113 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2114 &resp_buf_type, timeout);
2115 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2116 not try to free it twice below on exit */
2117 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002118 }
2119
Steve French08547b02006-02-28 22:39:25 +00002120 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002121 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002122 } else if (get_flag) {
2123 /* lock structure can be returned on get */
2124 __u16 data_offset;
2125 __u16 data_count;
2126 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002127
Jeff Layton820a8032011-05-04 08:05:26 -04002128 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002129 rc = -EIO; /* bad smb */
2130 goto plk_err_exit;
2131 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002132 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2133 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002134 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002135 rc = -EIO;
2136 goto plk_err_exit;
2137 }
2138 parm_data = (struct cifs_posix_lock *)
2139 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002140 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002141 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002142 else {
2143 if (parm_data->lock_type ==
2144 __constant_cpu_to_le16(CIFS_RDLCK))
2145 pLockData->fl_type = F_RDLCK;
2146 else if (parm_data->lock_type ==
2147 __constant_cpu_to_le16(CIFS_WRLCK))
2148 pLockData->fl_type = F_WRLCK;
2149
Steve French5443d132011-03-13 05:08:25 +00002150 pLockData->fl_start = le64_to_cpu(parm_data->start);
2151 pLockData->fl_end = pLockData->fl_start +
2152 le64_to_cpu(parm_data->length) - 1;
2153 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002154 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002155 }
Steve French50c2f752007-07-13 00:33:32 +00002156
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002157plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002158 if (pSMB)
2159 cifs_small_buf_release(pSMB);
2160
Steve French133672e2007-11-13 22:41:37 +00002161 if (resp_buf_type == CIFS_SMALL_BUFFER)
2162 cifs_small_buf_release(iov[0].iov_base);
2163 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2164 cifs_buf_release(iov[0].iov_base);
2165
Steve French08547b02006-02-28 22:39:25 +00002166 /* Note: On -EAGAIN error only caller can retry on handle based calls
2167 since file handle passed in no longer valid */
2168
2169 return rc;
2170}
2171
2172
2173int
Steve French96daf2b2011-05-27 04:34:02 +00002174CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175{
2176 int rc = 0;
2177 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002178 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
2180/* do not retry on dead session on close */
2181 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002182 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 return 0;
2184 if (rc)
2185 return rc;
2186
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002188 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002190 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002191 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002193 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002195 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 }
2197 }
2198
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002200 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 rc = 0;
2202
2203 return rc;
2204}
2205
2206int
Steve French96daf2b2011-05-27 04:34:02 +00002207CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002208{
2209 int rc = 0;
2210 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002211 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002212
2213 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2214 if (rc)
2215 return rc;
2216
2217 pSMB->FileID = (__u16) smb_file_id;
2218 pSMB->ByteCount = 0;
2219 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2220 cifs_stats_inc(&tcon->num_flushes);
2221 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002222 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002223
2224 return rc;
2225}
2226
2227int
Steve French96daf2b2011-05-27 04:34:02 +00002228CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002230 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
2232 int rc = 0;
2233 RENAME_REQ *pSMB = NULL;
2234 RENAME_RSP *pSMBr = NULL;
2235 int bytes_returned;
2236 int name_len, name_len2;
2237 __u16 count;
2238
Joe Perchesb6b38f72010-04-21 03:50:45 +00002239 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002240renameRetry:
2241 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2242 (void **) &pSMBr);
2243 if (rc)
2244 return rc;
2245
2246 pSMB->BufferFormat = 0x04;
2247 pSMB->SearchAttributes =
2248 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2249 ATTR_DIRECTORY);
2250
2251 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2252 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002253 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002254 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 name_len++; /* trailing null */
2256 name_len *= 2;
2257 pSMB->OldFileName[name_len] = 0x04; /* pad */
2258 /* protocol requires ASCII signature byte on Unicode string */
2259 pSMB->OldFileName[name_len + 1] = 0x00;
2260 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002261 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002262 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2264 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002265 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266 name_len = strnlen(fromName, PATH_MAX);
2267 name_len++; /* trailing null */
2268 strncpy(pSMB->OldFileName, fromName, name_len);
2269 name_len2 = strnlen(toName, PATH_MAX);
2270 name_len2++; /* trailing null */
2271 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2272 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2273 name_len2++; /* trailing null */
2274 name_len2++; /* signature byte */
2275 }
2276
2277 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002278 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 pSMB->ByteCount = cpu_to_le16(count);
2280
2281 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2282 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002283 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002284 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002285 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 cifs_buf_release(pSMB);
2288
2289 if (rc == -EAGAIN)
2290 goto renameRetry;
2291
2292 return rc;
2293}
2294
Steve French96daf2b2011-05-27 04:34:02 +00002295int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002296 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002297 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298{
2299 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2300 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002301 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 char *data_offset;
2303 char dummy_string[30];
2304 int rc = 0;
2305 int bytes_returned = 0;
2306 int len_of_str;
2307 __u16 params, param_offset, offset, count, byte_count;
2308
Joe Perchesb6b38f72010-04-21 03:50:45 +00002309 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2311 (void **) &pSMBr);
2312 if (rc)
2313 return rc;
2314
2315 params = 6;
2316 pSMB->MaxSetupCount = 0;
2317 pSMB->Reserved = 0;
2318 pSMB->Flags = 0;
2319 pSMB->Timeout = 0;
2320 pSMB->Reserved2 = 0;
2321 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2322 offset = param_offset + params;
2323
2324 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2325 rename_info = (struct set_file_rename *) data_offset;
2326 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002327 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 pSMB->SetupCount = 1;
2329 pSMB->Reserved3 = 0;
2330 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2331 byte_count = 3 /* pad */ + params;
2332 pSMB->ParameterCount = cpu_to_le16(params);
2333 pSMB->TotalParameterCount = pSMB->ParameterCount;
2334 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2335 pSMB->DataOffset = cpu_to_le16(offset);
2336 /* construct random name ".cifs_tmp<inodenum><mid>" */
2337 rename_info->overwrite = cpu_to_le32(1);
2338 rename_info->root_fid = 0;
2339 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002340 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002341 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2342 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002343 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002345 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002346 target_name, PATH_MAX, nls_codepage,
2347 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 }
2349 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002350 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 byte_count += count;
2352 pSMB->DataCount = cpu_to_le16(count);
2353 pSMB->TotalDataCount = pSMB->DataCount;
2354 pSMB->Fid = netfid;
2355 pSMB->InformationLevel =
2356 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2357 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002358 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 pSMB->ByteCount = cpu_to_le16(byte_count);
2360 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002361 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002362 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002363 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002364 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 cifs_buf_release(pSMB);
2367
2368 /* Note: On -EAGAIN error only caller can retry on handle based calls
2369 since file handle passed in no longer valid */
2370
2371 return rc;
2372}
2373
2374int
Steve French96daf2b2011-05-27 04:34:02 +00002375CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002376 const __u16 target_tid, const char *toName, const int flags,
2377 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378{
2379 int rc = 0;
2380 COPY_REQ *pSMB = NULL;
2381 COPY_RSP *pSMBr = NULL;
2382 int bytes_returned;
2383 int name_len, name_len2;
2384 __u16 count;
2385
Joe Perchesb6b38f72010-04-21 03:50:45 +00002386 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002387copyRetry:
2388 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2389 (void **) &pSMBr);
2390 if (rc)
2391 return rc;
2392
2393 pSMB->BufferFormat = 0x04;
2394 pSMB->Tid2 = target_tid;
2395
2396 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2397
2398 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002399 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002400 fromName, PATH_MAX, nls_codepage,
2401 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 name_len++; /* trailing null */
2403 name_len *= 2;
2404 pSMB->OldFileName[name_len] = 0x04; /* pad */
2405 /* protocol requires ASCII signature byte on Unicode string */
2406 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002407 name_len2 =
2408 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002409 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2411 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002412 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 name_len = strnlen(fromName, PATH_MAX);
2414 name_len++; /* trailing null */
2415 strncpy(pSMB->OldFileName, fromName, name_len);
2416 name_len2 = strnlen(toName, PATH_MAX);
2417 name_len2++; /* trailing null */
2418 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2419 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2420 name_len2++; /* trailing null */
2421 name_len2++; /* signature byte */
2422 }
2423
2424 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002425 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 pSMB->ByteCount = cpu_to_le16(count);
2427
2428 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2429 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2430 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002431 cFYI(1, "Send error in copy = %d with %d files copied",
2432 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 }
Steve French0d817bc2008-05-22 02:02:03 +00002434 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
2436 if (rc == -EAGAIN)
2437 goto copyRetry;
2438
2439 return rc;
2440}
2441
2442int
Steve French96daf2b2011-05-27 04:34:02 +00002443CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 const char *fromName, const char *toName,
2445 const struct nls_table *nls_codepage)
2446{
2447 TRANSACTION2_SPI_REQ *pSMB = NULL;
2448 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2449 char *data_offset;
2450 int name_len;
2451 int name_len_target;
2452 int rc = 0;
2453 int bytes_returned = 0;
2454 __u16 params, param_offset, offset, byte_count;
2455
Joe Perchesb6b38f72010-04-21 03:50:45 +00002456 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457createSymLinkRetry:
2458 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2459 (void **) &pSMBr);
2460 if (rc)
2461 return rc;
2462
2463 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2464 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002465 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 /* find define for this maxpathcomponent */
2467 , nls_codepage);
2468 name_len++; /* trailing null */
2469 name_len *= 2;
2470
Steve French50c2f752007-07-13 00:33:32 +00002471 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 name_len = strnlen(fromName, PATH_MAX);
2473 name_len++; /* trailing null */
2474 strncpy(pSMB->FileName, fromName, name_len);
2475 }
2476 params = 6 + name_len;
2477 pSMB->MaxSetupCount = 0;
2478 pSMB->Reserved = 0;
2479 pSMB->Flags = 0;
2480 pSMB->Timeout = 0;
2481 pSMB->Reserved2 = 0;
2482 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002483 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 offset = param_offset + params;
2485
2486 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2487 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2488 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002489 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 /* find define for this maxpathcomponent */
2491 , nls_codepage);
2492 name_len_target++; /* trailing null */
2493 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002494 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 name_len_target = strnlen(toName, PATH_MAX);
2496 name_len_target++; /* trailing null */
2497 strncpy(data_offset, toName, name_len_target);
2498 }
2499
2500 pSMB->MaxParameterCount = cpu_to_le16(2);
2501 /* BB find exact max on data count below from sess */
2502 pSMB->MaxDataCount = cpu_to_le16(1000);
2503 pSMB->SetupCount = 1;
2504 pSMB->Reserved3 = 0;
2505 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2506 byte_count = 3 /* pad */ + params + name_len_target;
2507 pSMB->DataCount = cpu_to_le16(name_len_target);
2508 pSMB->ParameterCount = cpu_to_le16(params);
2509 pSMB->TotalDataCount = pSMB->DataCount;
2510 pSMB->TotalParameterCount = pSMB->ParameterCount;
2511 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2512 pSMB->DataOffset = cpu_to_le16(offset);
2513 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2514 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002515 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516 pSMB->ByteCount = cpu_to_le16(byte_count);
2517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2518 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002519 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002520 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002521 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522
Steve French0d817bc2008-05-22 02:02:03 +00002523 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524
2525 if (rc == -EAGAIN)
2526 goto createSymLinkRetry;
2527
2528 return rc;
2529}
2530
2531int
Steve French96daf2b2011-05-27 04:34:02 +00002532CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002534 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535{
2536 TRANSACTION2_SPI_REQ *pSMB = NULL;
2537 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2538 char *data_offset;
2539 int name_len;
2540 int name_len_target;
2541 int rc = 0;
2542 int bytes_returned = 0;
2543 __u16 params, param_offset, offset, byte_count;
2544
Joe Perchesb6b38f72010-04-21 03:50:45 +00002545 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546createHardLinkRetry:
2547 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2548 (void **) &pSMBr);
2549 if (rc)
2550 return rc;
2551
2552 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002553 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002554 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 name_len++; /* trailing null */
2556 name_len *= 2;
2557
Steve French50c2f752007-07-13 00:33:32 +00002558 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 name_len = strnlen(toName, PATH_MAX);
2560 name_len++; /* trailing null */
2561 strncpy(pSMB->FileName, toName, name_len);
2562 }
2563 params = 6 + name_len;
2564 pSMB->MaxSetupCount = 0;
2565 pSMB->Reserved = 0;
2566 pSMB->Flags = 0;
2567 pSMB->Timeout = 0;
2568 pSMB->Reserved2 = 0;
2569 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002570 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 offset = param_offset + params;
2572
2573 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2574 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2575 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002576 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002577 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 name_len_target++; /* trailing null */
2579 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002580 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 name_len_target = strnlen(fromName, PATH_MAX);
2582 name_len_target++; /* trailing null */
2583 strncpy(data_offset, fromName, name_len_target);
2584 }
2585
2586 pSMB->MaxParameterCount = cpu_to_le16(2);
2587 /* BB find exact max on data count below from sess*/
2588 pSMB->MaxDataCount = cpu_to_le16(1000);
2589 pSMB->SetupCount = 1;
2590 pSMB->Reserved3 = 0;
2591 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2592 byte_count = 3 /* pad */ + params + name_len_target;
2593 pSMB->ParameterCount = cpu_to_le16(params);
2594 pSMB->TotalParameterCount = pSMB->ParameterCount;
2595 pSMB->DataCount = cpu_to_le16(name_len_target);
2596 pSMB->TotalDataCount = pSMB->DataCount;
2597 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2598 pSMB->DataOffset = cpu_to_le16(offset);
2599 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2600 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002601 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 pSMB->ByteCount = cpu_to_le16(byte_count);
2603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002605 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002606 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002607 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608
2609 cifs_buf_release(pSMB);
2610 if (rc == -EAGAIN)
2611 goto createHardLinkRetry;
2612
2613 return rc;
2614}
2615
2616int
Steve French96daf2b2011-05-27 04:34:02 +00002617CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002619 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620{
2621 int rc = 0;
2622 NT_RENAME_REQ *pSMB = NULL;
2623 RENAME_RSP *pSMBr = NULL;
2624 int bytes_returned;
2625 int name_len, name_len2;
2626 __u16 count;
2627
Joe Perchesb6b38f72010-04-21 03:50:45 +00002628 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629winCreateHardLinkRetry:
2630
2631 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2632 (void **) &pSMBr);
2633 if (rc)
2634 return rc;
2635
2636 pSMB->SearchAttributes =
2637 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2638 ATTR_DIRECTORY);
2639 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2640 pSMB->ClusterCount = 0;
2641
2642 pSMB->BufferFormat = 0x04;
2643
2644 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2645 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002646 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002647 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 name_len++; /* trailing null */
2649 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002650
2651 /* protocol specifies ASCII buffer format (0x04) for unicode */
2652 pSMB->OldFileName[name_len] = 0x04;
2653 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002655 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002656 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2658 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002659 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 name_len = strnlen(fromName, PATH_MAX);
2661 name_len++; /* trailing null */
2662 strncpy(pSMB->OldFileName, fromName, name_len);
2663 name_len2 = strnlen(toName, PATH_MAX);
2664 name_len2++; /* trailing null */
2665 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2666 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2667 name_len2++; /* trailing null */
2668 name_len2++; /* signature byte */
2669 }
2670
2671 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002672 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 pSMB->ByteCount = cpu_to_le16(count);
2674
2675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002677 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002678 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002679 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 cifs_buf_release(pSMB);
2682 if (rc == -EAGAIN)
2683 goto winCreateHardLinkRetry;
2684
2685 return rc;
2686}
2687
2688int
Steve French96daf2b2011-05-27 04:34:02 +00002689CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002690 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 const struct nls_table *nls_codepage)
2692{
2693/* SMB_QUERY_FILE_UNIX_LINK */
2694 TRANSACTION2_QPI_REQ *pSMB = NULL;
2695 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2696 int rc = 0;
2697 int bytes_returned;
2698 int name_len;
2699 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002700 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Joe Perchesb6b38f72010-04-21 03:50:45 +00002702 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
2704querySymLinkRetry:
2705 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2706 (void **) &pSMBr);
2707 if (rc)
2708 return rc;
2709
2710 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2711 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002712 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2713 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 name_len++; /* trailing null */
2715 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002716 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 name_len = strnlen(searchName, PATH_MAX);
2718 name_len++; /* trailing null */
2719 strncpy(pSMB->FileName, searchName, name_len);
2720 }
2721
2722 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2723 pSMB->TotalDataCount = 0;
2724 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002725 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 pSMB->MaxSetupCount = 0;
2727 pSMB->Reserved = 0;
2728 pSMB->Flags = 0;
2729 pSMB->Timeout = 0;
2730 pSMB->Reserved2 = 0;
2731 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002732 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 pSMB->DataCount = 0;
2734 pSMB->DataOffset = 0;
2735 pSMB->SetupCount = 1;
2736 pSMB->Reserved3 = 0;
2737 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2738 byte_count = params + 1 /* pad */ ;
2739 pSMB->TotalParameterCount = cpu_to_le16(params);
2740 pSMB->ParameterCount = pSMB->TotalParameterCount;
2741 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2742 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002743 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 pSMB->ByteCount = cpu_to_le16(byte_count);
2745
2746 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2747 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2748 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002749 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 } else {
2751 /* decode response */
2752
2753 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002755 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002756 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002758 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002759 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760
Jeff Layton460b9692009-04-30 07:17:56 -04002761 data_start = ((char *) &pSMBr->hdr.Protocol) +
2762 le16_to_cpu(pSMBr->t2.DataOffset);
2763
Steve French0e0d2cf2009-05-01 05:27:32 +00002764 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2765 is_unicode = true;
2766 else
2767 is_unicode = false;
2768
Steve French737b7582005-04-28 22:41:06 -07002769 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002770 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002771 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002772 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002773 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 }
2775 }
2776 cifs_buf_release(pSMB);
2777 if (rc == -EAGAIN)
2778 goto querySymLinkRetry;
2779 return rc;
2780}
2781
Steve Frenchc52a9552011-02-24 06:16:22 +00002782#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2783/*
2784 * Recent Windows versions now create symlinks more frequently
2785 * and they use the "reparse point" mechanism below. We can of course
2786 * do symlinks nicely to Samba and other servers which support the
2787 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2788 * "MF" symlinks optionally, but for recent Windows we really need to
2789 * reenable the code below and fix the cifs_symlink callers to handle this.
2790 * In the interim this code has been moved to its own config option so
2791 * it is not compiled in by default until callers fixed up and more tested.
2792 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793int
Steve French96daf2b2011-05-27 04:34:02 +00002794CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002796 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 const struct nls_table *nls_codepage)
2798{
2799 int rc = 0;
2800 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002801 struct smb_com_transaction_ioctl_req *pSMB;
2802 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
Joe Perchesb6b38f72010-04-21 03:50:45 +00002804 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2806 (void **) &pSMBr);
2807 if (rc)
2808 return rc;
2809
2810 pSMB->TotalParameterCount = 0 ;
2811 pSMB->TotalDataCount = 0;
2812 pSMB->MaxParameterCount = cpu_to_le32(2);
2813 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04002814 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 pSMB->MaxSetupCount = 4;
2816 pSMB->Reserved = 0;
2817 pSMB->ParameterOffset = 0;
2818 pSMB->DataCount = 0;
2819 pSMB->DataOffset = 0;
2820 pSMB->SetupCount = 4;
2821 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2822 pSMB->ParameterCount = pSMB->TotalParameterCount;
2823 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2824 pSMB->IsFsctl = 1; /* FSCTL */
2825 pSMB->IsRootFlag = 0;
2826 pSMB->Fid = fid; /* file handle always le */
2827 pSMB->ByteCount = 0;
2828
2829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2831 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002832 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 } else { /* decode response */
2834 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2835 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002836 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2837 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002839 goto qreparse_out;
2840 }
2841 if (data_count && (data_count < 2048)) {
2842 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002843 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
Steve Frenchafe48c32009-05-02 05:25:46 +00002845 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002846 (struct reparse_data *)
2847 ((char *)&pSMBr->hdr.Protocol
2848 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002849 if ((char *)reparse_buf >= end_of_smb) {
2850 rc = -EIO;
2851 goto qreparse_out;
2852 }
2853 if ((reparse_buf->LinkNamesBuf +
2854 reparse_buf->TargetNameOffset +
2855 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002856 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002857 rc = -EIO;
2858 goto qreparse_out;
2859 }
Steve French50c2f752007-07-13 00:33:32 +00002860
Steve Frenchafe48c32009-05-02 05:25:46 +00002861 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2862 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002863 (reparse_buf->LinkNamesBuf +
2864 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002865 buflen,
2866 reparse_buf->TargetNameLen,
2867 nls_codepage, 0);
2868 } else { /* ASCII names */
2869 strncpy(symlinkinfo,
2870 reparse_buf->LinkNamesBuf +
2871 reparse_buf->TargetNameOffset,
2872 min_t(const int, buflen,
2873 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002875 } else {
2876 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002877 cFYI(1, "Invalid return data count on "
2878 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002880 symlinkinfo[buflen] = 0; /* just in case so the caller
2881 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002882 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 }
Steve French989c7e52009-05-02 05:32:20 +00002884
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002886 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
2888 /* Note: On -EAGAIN error only caller can retry on handle based calls
2889 since file handle passed in no longer valid */
2890
2891 return rc;
2892}
Steve Frenchc52a9552011-02-24 06:16:22 +00002893#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895#ifdef CONFIG_CIFS_POSIX
2896
2897/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002898static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2899 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900{
2901 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002902 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2903 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2904 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002905 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
2907 return;
2908}
2909
2910/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002911static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2912 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913{
2914 int size = 0;
2915 int i;
2916 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002917 struct cifs_posix_ace *pACE;
2918 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2919 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
2921 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2922 return -EOPNOTSUPP;
2923
Steve French790fe572007-07-07 19:25:05 +00002924 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 count = le16_to_cpu(cifs_acl->access_entry_count);
2926 pACE = &cifs_acl->ace_array[0];
2927 size = sizeof(struct cifs_posix_acl);
2928 size += sizeof(struct cifs_posix_ace) * count;
2929 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002930 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002931 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2932 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 return -EINVAL;
2934 }
Steve French790fe572007-07-07 19:25:05 +00002935 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 count = le16_to_cpu(cifs_acl->access_entry_count);
2937 size = sizeof(struct cifs_posix_acl);
2938 size += sizeof(struct cifs_posix_ace) * count;
2939/* skip past access ACEs to get to default ACEs */
2940 pACE = &cifs_acl->ace_array[count];
2941 count = le16_to_cpu(cifs_acl->default_entry_count);
2942 size += sizeof(struct cifs_posix_ace) * count;
2943 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002944 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 return -EINVAL;
2946 } else {
2947 /* illegal type */
2948 return -EINVAL;
2949 }
2950
2951 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002952 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002953 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002954 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 return -ERANGE;
2956 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002957 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002958 for (i = 0; i < count ; i++) {
2959 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2960 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 }
2962 }
2963 return size;
2964}
2965
Steve French50c2f752007-07-13 00:33:32 +00002966static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2967 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968{
2969 __u16 rc = 0; /* 0 = ACL converted ok */
2970
Steve Frenchff7feac2005-11-15 16:45:16 -08002971 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2972 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002974 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 /* Probably no need to le convert -1 on any arch but can not hurt */
2976 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002977 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002978 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002979 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 return rc;
2981}
2982
2983/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002984static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2985 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002988 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2989 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 int count;
2991 int i;
2992
Steve French790fe572007-07-07 19:25:05 +00002993 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 return 0;
2995
2996 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002997 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002998 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002999 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003000 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003001 cFYI(1, "unknown POSIX ACL version %d",
3002 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 return 0;
3004 }
3005 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003006 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003007 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003008 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003009 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003011 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 return 0;
3013 }
Steve French50c2f752007-07-13 00:33:32 +00003014 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3016 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003017 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 /* ACE not converted */
3019 break;
3020 }
3021 }
Steve French790fe572007-07-07 19:25:05 +00003022 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3024 rc += sizeof(struct cifs_posix_acl);
3025 /* BB add check to make sure ACL does not overflow SMB */
3026 }
3027 return rc;
3028}
3029
3030int
Steve French96daf2b2011-05-27 04:34:02 +00003031CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003032 const unsigned char *searchName,
3033 char *acl_inf, const int buflen, const int acl_type,
3034 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035{
3036/* SMB_QUERY_POSIX_ACL */
3037 TRANSACTION2_QPI_REQ *pSMB = NULL;
3038 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3039 int rc = 0;
3040 int bytes_returned;
3041 int name_len;
3042 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003043
Joe Perchesb6b38f72010-04-21 03:50:45 +00003044 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
3046queryAclRetry:
3047 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3048 (void **) &pSMBr);
3049 if (rc)
3050 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003051
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3053 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003054 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003055 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 name_len++; /* trailing null */
3057 name_len *= 2;
3058 pSMB->FileName[name_len] = 0;
3059 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003060 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 name_len = strnlen(searchName, PATH_MAX);
3062 name_len++; /* trailing null */
3063 strncpy(pSMB->FileName, searchName, name_len);
3064 }
3065
3066 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3067 pSMB->TotalDataCount = 0;
3068 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003069 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 pSMB->MaxDataCount = cpu_to_le16(4000);
3071 pSMB->MaxSetupCount = 0;
3072 pSMB->Reserved = 0;
3073 pSMB->Flags = 0;
3074 pSMB->Timeout = 0;
3075 pSMB->Reserved2 = 0;
3076 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003077 offsetof(struct smb_com_transaction2_qpi_req,
3078 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 pSMB->DataCount = 0;
3080 pSMB->DataOffset = 0;
3081 pSMB->SetupCount = 1;
3082 pSMB->Reserved3 = 0;
3083 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3084 byte_count = params + 1 /* pad */ ;
3085 pSMB->TotalParameterCount = cpu_to_le16(params);
3086 pSMB->ParameterCount = pSMB->TotalParameterCount;
3087 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3088 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003089 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 pSMB->ByteCount = cpu_to_le16(byte_count);
3091
3092 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3093 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003094 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003096 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 } else {
3098 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003099
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003102 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 rc = -EIO; /* bad smb */
3104 else {
3105 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3106 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3107 rc = cifs_copy_posix_acl(acl_inf,
3108 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003109 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 }
3111 }
3112 cifs_buf_release(pSMB);
3113 if (rc == -EAGAIN)
3114 goto queryAclRetry;
3115 return rc;
3116}
3117
3118int
Steve French96daf2b2011-05-27 04:34:02 +00003119CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003120 const unsigned char *fileName,
3121 const char *local_acl, const int buflen,
3122 const int acl_type,
3123 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124{
3125 struct smb_com_transaction2_spi_req *pSMB = NULL;
3126 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3127 char *parm_data;
3128 int name_len;
3129 int rc = 0;
3130 int bytes_returned = 0;
3131 __u16 params, byte_count, data_count, param_offset, offset;
3132
Joe Perchesb6b38f72010-04-21 03:50:45 +00003133 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134setAclRetry:
3135 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003136 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 if (rc)
3138 return rc;
3139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3140 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003141 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003142 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 name_len++; /* trailing null */
3144 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003145 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 name_len = strnlen(fileName, PATH_MAX);
3147 name_len++; /* trailing null */
3148 strncpy(pSMB->FileName, fileName, name_len);
3149 }
3150 params = 6 + name_len;
3151 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003152 /* BB find max SMB size from sess */
3153 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 pSMB->MaxSetupCount = 0;
3155 pSMB->Reserved = 0;
3156 pSMB->Flags = 0;
3157 pSMB->Timeout = 0;
3158 pSMB->Reserved2 = 0;
3159 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003160 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 offset = param_offset + params;
3162 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3163 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3164
3165 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003166 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
Steve French790fe572007-07-07 19:25:05 +00003168 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 rc = -EOPNOTSUPP;
3170 goto setACLerrorExit;
3171 }
3172 pSMB->DataOffset = cpu_to_le16(offset);
3173 pSMB->SetupCount = 1;
3174 pSMB->Reserved3 = 0;
3175 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3176 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3177 byte_count = 3 /* pad */ + params + data_count;
3178 pSMB->DataCount = cpu_to_le16(data_count);
3179 pSMB->TotalDataCount = pSMB->DataCount;
3180 pSMB->ParameterCount = cpu_to_le16(params);
3181 pSMB->TotalParameterCount = pSMB->ParameterCount;
3182 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003183 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 pSMB->ByteCount = cpu_to_le16(byte_count);
3185 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003186 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003187 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003188 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190setACLerrorExit:
3191 cifs_buf_release(pSMB);
3192 if (rc == -EAGAIN)
3193 goto setAclRetry;
3194 return rc;
3195}
3196
Steve Frenchf654bac2005-04-28 22:41:04 -07003197/* BB fix tabs in this function FIXME BB */
3198int
Steve French96daf2b2011-05-27 04:34:02 +00003199CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003200 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003201{
Steve French50c2f752007-07-13 00:33:32 +00003202 int rc = 0;
3203 struct smb_t2_qfi_req *pSMB = NULL;
3204 struct smb_t2_qfi_rsp *pSMBr = NULL;
3205 int bytes_returned;
3206 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003207
Joe Perchesb6b38f72010-04-21 03:50:45 +00003208 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003209 if (tcon == NULL)
3210 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003211
3212GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003213 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3214 (void **) &pSMBr);
3215 if (rc)
3216 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003217
Steve Frenchad7a2922008-02-07 23:25:02 +00003218 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003219 pSMB->t2.TotalDataCount = 0;
3220 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3221 /* BB find exact max data count below from sess structure BB */
3222 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3223 pSMB->t2.MaxSetupCount = 0;
3224 pSMB->t2.Reserved = 0;
3225 pSMB->t2.Flags = 0;
3226 pSMB->t2.Timeout = 0;
3227 pSMB->t2.Reserved2 = 0;
3228 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3229 Fid) - 4);
3230 pSMB->t2.DataCount = 0;
3231 pSMB->t2.DataOffset = 0;
3232 pSMB->t2.SetupCount = 1;
3233 pSMB->t2.Reserved3 = 0;
3234 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3235 byte_count = params + 1 /* pad */ ;
3236 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3237 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3238 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3239 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003240 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003241 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003242 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003243
Steve French790fe572007-07-07 19:25:05 +00003244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003247 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003248 } else {
3249 /* decode response */
3250 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003251 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003252 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003253 /* If rc should we check for EOPNOSUPP and
3254 disable the srvino flag? or in caller? */
3255 rc = -EIO; /* bad smb */
3256 else {
3257 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3258 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3259 struct file_chattr_info *pfinfo;
3260 /* BB Do we need a cast or hash here ? */
3261 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003262 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003263 rc = -EIO;
3264 goto GetExtAttrOut;
3265 }
3266 pfinfo = (struct file_chattr_info *)
3267 (data_offset + (char *) &pSMBr->hdr.Protocol);
3268 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003269 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003270 }
3271 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003272GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003273 cifs_buf_release(pSMB);
3274 if (rc == -EAGAIN)
3275 goto GetExtAttrRetry;
3276 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003277}
3278
Steve Frenchf654bac2005-04-28 22:41:04 -07003279#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
Jeff Layton79df1ba2010-12-06 12:52:08 -05003281#ifdef CONFIG_CIFS_ACL
3282/*
3283 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3284 * all NT TRANSACTS that we init here have total parm and data under about 400
3285 * bytes (to fit in small cifs buffer size), which is the case so far, it
3286 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3287 * returned setup area) and MaxParameterCount (returned parms size) must be set
3288 * by caller
3289 */
3290static int
3291smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003292 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003293 void **ret_buf)
3294{
3295 int rc;
3296 __u32 temp_offset;
3297 struct smb_com_ntransact_req *pSMB;
3298
3299 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3300 (void **)&pSMB);
3301 if (rc)
3302 return rc;
3303 *ret_buf = (void *)pSMB;
3304 pSMB->Reserved = 0;
3305 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3306 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003307 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003308 pSMB->ParameterCount = pSMB->TotalParameterCount;
3309 pSMB->DataCount = pSMB->TotalDataCount;
3310 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3311 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3312 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3313 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3314 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3315 pSMB->SubCommand = cpu_to_le16(sub_command);
3316 return 0;
3317}
3318
3319static int
3320validate_ntransact(char *buf, char **ppparm, char **ppdata,
3321 __u32 *pparmlen, __u32 *pdatalen)
3322{
3323 char *end_of_smb;
3324 __u32 data_count, data_offset, parm_count, parm_offset;
3325 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003326 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003327
3328 *pdatalen = 0;
3329 *pparmlen = 0;
3330
3331 if (buf == NULL)
3332 return -EINVAL;
3333
3334 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3335
Jeff Layton820a8032011-05-04 08:05:26 -04003336 bcc = get_bcc(&pSMBr->hdr);
3337 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003338 (char *)&pSMBr->ByteCount;
3339
3340 data_offset = le32_to_cpu(pSMBr->DataOffset);
3341 data_count = le32_to_cpu(pSMBr->DataCount);
3342 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3343 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3344
3345 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3346 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3347
3348 /* should we also check that parm and data areas do not overlap? */
3349 if (*ppparm > end_of_smb) {
3350 cFYI(1, "parms start after end of smb");
3351 return -EINVAL;
3352 } else if (parm_count + *ppparm > end_of_smb) {
3353 cFYI(1, "parm end after end of smb");
3354 return -EINVAL;
3355 } else if (*ppdata > end_of_smb) {
3356 cFYI(1, "data starts after end of smb");
3357 return -EINVAL;
3358 } else if (data_count + *ppdata > end_of_smb) {
3359 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3360 *ppdata, data_count, (data_count + *ppdata),
3361 end_of_smb, pSMBr);
3362 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003363 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003364 cFYI(1, "parm count and data count larger than SMB");
3365 return -EINVAL;
3366 }
3367 *pdatalen = data_count;
3368 *pparmlen = parm_count;
3369 return 0;
3370}
3371
Steve French0a4b92c2006-01-12 15:44:21 -08003372/* Get Security Descriptor (by handle) from remote server for a file or dir */
3373int
Steve French96daf2b2011-05-27 04:34:02 +00003374CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003375 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003376{
3377 int rc = 0;
3378 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003379 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003380 struct kvec iov[1];
3381
Joe Perchesb6b38f72010-04-21 03:50:45 +00003382 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003383
Steve French630f3f02007-10-25 21:17:17 +00003384 *pbuflen = 0;
3385 *acl_inf = NULL;
3386
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003387 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003388 8 /* parm len */, tcon, (void **) &pSMB);
3389 if (rc)
3390 return rc;
3391
3392 pSMB->MaxParameterCount = cpu_to_le32(4);
3393 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3394 pSMB->MaxSetupCount = 0;
3395 pSMB->Fid = fid; /* file handle always le */
3396 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3397 CIFS_ACL_DACL);
3398 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003399 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003400 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003401 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003402
Steve Frencha761ac52007-10-18 21:45:27 +00003403 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003404 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003405 cifs_stats_inc(&tcon->num_acl_get);
3406 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003407 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003408 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003409 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003410 __u32 parm_len;
3411 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003412 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003413 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003414
3415/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003416 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003417 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003418 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003419 goto qsec_out;
3420 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3421
Joe Perchesb6b38f72010-04-21 03:50:45 +00003422 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003423
3424 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3425 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003426 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003427 goto qsec_out;
3428 }
3429
3430/* BB check that data area is minimum length and as big as acl_len */
3431
Steve Frenchaf6f4612007-10-16 18:40:37 +00003432 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003433 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003434 cERROR(1, "acl length %d does not match %d",
3435 acl_len, *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003436 if (*pbuflen > acl_len)
3437 *pbuflen = acl_len;
3438 }
Steve French0a4b92c2006-01-12 15:44:21 -08003439
Steve French630f3f02007-10-25 21:17:17 +00003440 /* check if buffer is big enough for the acl
3441 header followed by the smallest SID */
3442 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3443 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003444 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003445 rc = -EINVAL;
3446 *pbuflen = 0;
3447 } else {
3448 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3449 if (*acl_inf == NULL) {
3450 *pbuflen = 0;
3451 rc = -ENOMEM;
3452 }
3453 memcpy(*acl_inf, pdata, *pbuflen);
3454 }
Steve French0a4b92c2006-01-12 15:44:21 -08003455 }
3456qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003457 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003458 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003459 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003460 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003461/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003462 return rc;
3463}
Steve French97837582007-12-31 07:47:21 +00003464
3465int
Steve French96daf2b2011-05-27 04:34:02 +00003466CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003467 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
Steve French97837582007-12-31 07:47:21 +00003468{
3469 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3470 int rc = 0;
3471 int bytes_returned = 0;
3472 SET_SEC_DESC_REQ *pSMB = NULL;
3473 NTRANSACT_RSP *pSMBr = NULL;
3474
3475setCifsAclRetry:
3476 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3477 (void **) &pSMBr);
3478 if (rc)
3479 return (rc);
3480
3481 pSMB->MaxSetupCount = 0;
3482 pSMB->Reserved = 0;
3483
3484 param_count = 8;
3485 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3486 data_count = acllen;
3487 data_offset = param_offset + param_count;
3488 byte_count = 3 /* pad */ + param_count;
3489
3490 pSMB->DataCount = cpu_to_le32(data_count);
3491 pSMB->TotalDataCount = pSMB->DataCount;
3492 pSMB->MaxParameterCount = cpu_to_le32(4);
3493 pSMB->MaxDataCount = cpu_to_le32(16384);
3494 pSMB->ParameterCount = cpu_to_le32(param_count);
3495 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3496 pSMB->TotalParameterCount = pSMB->ParameterCount;
3497 pSMB->DataOffset = cpu_to_le32(data_offset);
3498 pSMB->SetupCount = 0;
3499 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3500 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3501
3502 pSMB->Fid = fid; /* file handle always le */
3503 pSMB->Reserved2 = 0;
Shirish Pargaonkara5ff3762011-10-13 10:26:03 -05003504 pSMB->AclFlags = cpu_to_le32(aclflag);
Steve French97837582007-12-31 07:47:21 +00003505
3506 if (pntsd && acllen) {
3507 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3508 (char *) pntsd,
3509 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003510 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003511 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003512 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003513
3514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3515 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3516
Joe Perchesb6b38f72010-04-21 03:50:45 +00003517 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003518 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003519 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003520 cifs_buf_release(pSMB);
3521
3522 if (rc == -EAGAIN)
3523 goto setCifsAclRetry;
3524
3525 return (rc);
3526}
3527
Jeff Layton79df1ba2010-12-06 12:52:08 -05003528#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003529
Steve French6b8edfe2005-08-23 20:26:03 -07003530/* Legacy Query Path Information call for lookup to old servers such
3531 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003532int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003533 const unsigned char *searchName,
3534 FILE_ALL_INFO *pFinfo,
3535 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003536{
Steve Frenchad7a2922008-02-07 23:25:02 +00003537 QUERY_INFORMATION_REQ *pSMB;
3538 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003539 int rc = 0;
3540 int bytes_returned;
3541 int name_len;
3542
Joe Perchesb6b38f72010-04-21 03:50:45 +00003543 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003544QInfRetry:
3545 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003546 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003547 if (rc)
3548 return rc;
3549
3550 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3551 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003552 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3553 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003554 name_len++; /* trailing null */
3555 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003556 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003557 name_len = strnlen(searchName, PATH_MAX);
3558 name_len++; /* trailing null */
3559 strncpy(pSMB->FileName, searchName, name_len);
3560 }
3561 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003562 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003563 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003564 pSMB->ByteCount = cpu_to_le16(name_len);
3565
3566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003568 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003569 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003570 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003571 struct timespec ts;
3572 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003573
3574 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003575 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003576 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003577 ts.tv_nsec = 0;
3578 ts.tv_sec = time;
3579 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003580 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003581 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3582 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003583 pFinfo->AllocationSize =
3584 cpu_to_le64(le32_to_cpu(pSMBr->size));
3585 pFinfo->EndOfFile = pFinfo->AllocationSize;
3586 pFinfo->Attributes =
3587 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003588 } else
3589 rc = -EIO; /* bad buffer passed in */
3590
3591 cifs_buf_release(pSMB);
3592
3593 if (rc == -EAGAIN)
3594 goto QInfRetry;
3595
3596 return rc;
3597}
3598
Jeff Laytonbcd53572010-02-12 07:44:16 -05003599int
Steve French96daf2b2011-05-27 04:34:02 +00003600CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003601 u16 netfid, FILE_ALL_INFO *pFindData)
3602{
3603 struct smb_t2_qfi_req *pSMB = NULL;
3604 struct smb_t2_qfi_rsp *pSMBr = NULL;
3605 int rc = 0;
3606 int bytes_returned;
3607 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003608
Jeff Laytonbcd53572010-02-12 07:44:16 -05003609QFileInfoRetry:
3610 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3611 (void **) &pSMBr);
3612 if (rc)
3613 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003614
Jeff Laytonbcd53572010-02-12 07:44:16 -05003615 params = 2 /* level */ + 2 /* fid */;
3616 pSMB->t2.TotalDataCount = 0;
3617 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3618 /* BB find exact max data count below from sess structure BB */
3619 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3620 pSMB->t2.MaxSetupCount = 0;
3621 pSMB->t2.Reserved = 0;
3622 pSMB->t2.Flags = 0;
3623 pSMB->t2.Timeout = 0;
3624 pSMB->t2.Reserved2 = 0;
3625 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3626 Fid) - 4);
3627 pSMB->t2.DataCount = 0;
3628 pSMB->t2.DataOffset = 0;
3629 pSMB->t2.SetupCount = 1;
3630 pSMB->t2.Reserved3 = 0;
3631 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3632 byte_count = params + 1 /* pad */ ;
3633 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3634 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3635 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3636 pSMB->Pad = 0;
3637 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003638 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003639
3640 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3641 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3642 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003643 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003644 } else { /* decode response */
3645 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3646
3647 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3648 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003649 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003650 rc = -EIO; /* bad smb */
3651 else if (pFindData) {
3652 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3653 memcpy((char *) pFindData,
3654 (char *) &pSMBr->hdr.Protocol +
3655 data_offset, sizeof(FILE_ALL_INFO));
3656 } else
3657 rc = -ENOMEM;
3658 }
3659 cifs_buf_release(pSMB);
3660 if (rc == -EAGAIN)
3661 goto QFileInfoRetry;
3662
3663 return rc;
3664}
Steve French6b8edfe2005-08-23 20:26:03 -07003665
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666int
Steve French96daf2b2011-05-27 04:34:02 +00003667CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003669 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003670 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003671 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672{
3673/* level 263 SMB_QUERY_FILE_ALL_INFO */
3674 TRANSACTION2_QPI_REQ *pSMB = NULL;
3675 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3676 int rc = 0;
3677 int bytes_returned;
3678 int name_len;
3679 __u16 params, byte_count;
3680
Joe Perchesb6b38f72010-04-21 03:50:45 +00003681/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682QPathInfoRetry:
3683 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3684 (void **) &pSMBr);
3685 if (rc)
3686 return rc;
3687
3688 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3689 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003690 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003691 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 name_len++; /* trailing null */
3693 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003694 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 name_len = strnlen(searchName, PATH_MAX);
3696 name_len++; /* trailing null */
3697 strncpy(pSMB->FileName, searchName, name_len);
3698 }
3699
Steve French50c2f752007-07-13 00:33:32 +00003700 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 pSMB->TotalDataCount = 0;
3702 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003703 /* BB find exact max SMB PDU from sess structure BB */
3704 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 pSMB->MaxSetupCount = 0;
3706 pSMB->Reserved = 0;
3707 pSMB->Flags = 0;
3708 pSMB->Timeout = 0;
3709 pSMB->Reserved2 = 0;
3710 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003711 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003712 pSMB->DataCount = 0;
3713 pSMB->DataOffset = 0;
3714 pSMB->SetupCount = 1;
3715 pSMB->Reserved3 = 0;
3716 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3717 byte_count = params + 1 /* pad */ ;
3718 pSMB->TotalParameterCount = cpu_to_le16(params);
3719 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003720 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003721 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3722 else
3723 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003725 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 pSMB->ByteCount = cpu_to_le16(byte_count);
3727
3728 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3729 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3730 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003731 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 } else { /* decode response */
3733 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3734
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003735 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3736 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003737 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003739 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003740 rc = -EIO; /* 24 or 26 expected but we do not read
3741 last field */
3742 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003743 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003744 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003745
3746 /* On legacy responses we do not read the last field,
3747 EAsize, fortunately since it varies by subdialect and
3748 also note it differs on Set vs. Get, ie two bytes or 4
3749 bytes depending but we don't care here */
3750 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003751 size = sizeof(FILE_INFO_STANDARD);
3752 else
3753 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 memcpy((char *) pFindData,
3755 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003756 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 } else
3758 rc = -ENOMEM;
3759 }
3760 cifs_buf_release(pSMB);
3761 if (rc == -EAGAIN)
3762 goto QPathInfoRetry;
3763
3764 return rc;
3765}
3766
3767int
Steve French96daf2b2011-05-27 04:34:02 +00003768CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003769 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3770{
3771 struct smb_t2_qfi_req *pSMB = NULL;
3772 struct smb_t2_qfi_rsp *pSMBr = NULL;
3773 int rc = 0;
3774 int bytes_returned;
3775 __u16 params, byte_count;
3776
3777UnixQFileInfoRetry:
3778 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3779 (void **) &pSMBr);
3780 if (rc)
3781 return rc;
3782
3783 params = 2 /* level */ + 2 /* fid */;
3784 pSMB->t2.TotalDataCount = 0;
3785 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3786 /* BB find exact max data count below from sess structure BB */
3787 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3788 pSMB->t2.MaxSetupCount = 0;
3789 pSMB->t2.Reserved = 0;
3790 pSMB->t2.Flags = 0;
3791 pSMB->t2.Timeout = 0;
3792 pSMB->t2.Reserved2 = 0;
3793 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3794 Fid) - 4);
3795 pSMB->t2.DataCount = 0;
3796 pSMB->t2.DataOffset = 0;
3797 pSMB->t2.SetupCount = 1;
3798 pSMB->t2.Reserved3 = 0;
3799 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3800 byte_count = params + 1 /* pad */ ;
3801 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3802 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3803 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3804 pSMB->Pad = 0;
3805 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003806 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003807
3808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3810 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003811 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003812 } else { /* decode response */
3813 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3814
Jeff Layton820a8032011-05-04 08:05:26 -04003815 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003816 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003817 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003818 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003819 rc = -EIO; /* bad smb */
3820 } else {
3821 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3822 memcpy((char *) pFindData,
3823 (char *) &pSMBr->hdr.Protocol +
3824 data_offset,
3825 sizeof(FILE_UNIX_BASIC_INFO));
3826 }
3827 }
3828
3829 cifs_buf_release(pSMB);
3830 if (rc == -EAGAIN)
3831 goto UnixQFileInfoRetry;
3832
3833 return rc;
3834}
3835
3836int
Steve French96daf2b2011-05-27 04:34:02 +00003837CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003839 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003840 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841{
3842/* SMB_QUERY_FILE_UNIX_BASIC */
3843 TRANSACTION2_QPI_REQ *pSMB = NULL;
3844 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3845 int rc = 0;
3846 int bytes_returned = 0;
3847 int name_len;
3848 __u16 params, byte_count;
3849
Joe Perchesb6b38f72010-04-21 03:50:45 +00003850 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851UnixQPathInfoRetry:
3852 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3853 (void **) &pSMBr);
3854 if (rc)
3855 return rc;
3856
3857 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3858 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003859 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003860 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 name_len++; /* trailing null */
3862 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003863 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 name_len = strnlen(searchName, PATH_MAX);
3865 name_len++; /* trailing null */
3866 strncpy(pSMB->FileName, searchName, name_len);
3867 }
3868
Steve French50c2f752007-07-13 00:33:32 +00003869 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 pSMB->TotalDataCount = 0;
3871 pSMB->MaxParameterCount = cpu_to_le16(2);
3872 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003873 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 pSMB->MaxSetupCount = 0;
3875 pSMB->Reserved = 0;
3876 pSMB->Flags = 0;
3877 pSMB->Timeout = 0;
3878 pSMB->Reserved2 = 0;
3879 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003880 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 pSMB->DataCount = 0;
3882 pSMB->DataOffset = 0;
3883 pSMB->SetupCount = 1;
3884 pSMB->Reserved3 = 0;
3885 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3886 byte_count = params + 1 /* pad */ ;
3887 pSMB->TotalParameterCount = cpu_to_le16(params);
3888 pSMB->ParameterCount = pSMB->TotalParameterCount;
3889 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3890 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003891 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 pSMB->ByteCount = cpu_to_le16(byte_count);
3893
3894 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3895 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3896 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003897 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 } else { /* decode response */
3899 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3900
Jeff Layton820a8032011-05-04 08:05:26 -04003901 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003902 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003903 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003904 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 rc = -EIO; /* bad smb */
3906 } else {
3907 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3908 memcpy((char *) pFindData,
3909 (char *) &pSMBr->hdr.Protocol +
3910 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003911 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 }
3913 }
3914 cifs_buf_release(pSMB);
3915 if (rc == -EAGAIN)
3916 goto UnixQPathInfoRetry;
3917
3918 return rc;
3919}
3920
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921/* xid, tcon, searchName and codepage are input parms, rest are returned */
3922int
Steve French96daf2b2011-05-27 04:34:02 +00003923CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003924 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003926 __u16 *pnetfid,
3927 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928{
3929/* level 257 SMB_ */
3930 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3931 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003932 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 int rc = 0;
3934 int bytes_returned = 0;
3935 int name_len;
3936 __u16 params, byte_count;
3937
Joe Perchesb6b38f72010-04-21 03:50:45 +00003938 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939
3940findFirstRetry:
3941 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3942 (void **) &pSMBr);
3943 if (rc)
3944 return rc;
3945
3946 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3947 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003948 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003949 PATH_MAX, nls_codepage, remap);
3950 /* We can not add the asterik earlier in case
3951 it got remapped to 0xF03A as if it were part of the
3952 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003954 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003955 pSMB->FileName[name_len+1] = 0;
3956 pSMB->FileName[name_len+2] = '*';
3957 pSMB->FileName[name_len+3] = 0;
3958 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3960 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003961 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 } else { /* BB add check for overrun of SMB buf BB */
3963 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003965 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 free buffer exit; BB */
3967 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003968 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003969 pSMB->FileName[name_len+1] = '*';
3970 pSMB->FileName[name_len+2] = 0;
3971 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 }
3973
3974 params = 12 + name_len /* includes null */ ;
3975 pSMB->TotalDataCount = 0; /* no EAs */
3976 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04003977 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 pSMB->MaxSetupCount = 0;
3979 pSMB->Reserved = 0;
3980 pSMB->Flags = 0;
3981 pSMB->Timeout = 0;
3982 pSMB->Reserved2 = 0;
3983 byte_count = params + 1 /* pad */ ;
3984 pSMB->TotalParameterCount = cpu_to_le16(params);
3985 pSMB->ParameterCount = pSMB->TotalParameterCount;
3986 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003987 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3988 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 pSMB->DataCount = 0;
3990 pSMB->DataOffset = 0;
3991 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3992 pSMB->Reserved3 = 0;
3993 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3994 pSMB->SearchAttributes =
3995 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3996 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003997 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3998 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 CIFS_SEARCH_RETURN_RESUME);
4000 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4001
4002 /* BB what should we set StorageType to? Does it matter? BB */
4003 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004004 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 pSMB->ByteCount = cpu_to_le16(byte_count);
4006
4007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004009 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010
Steve French88274812006-03-09 22:21:45 +00004011 if (rc) {/* BB add logic to retry regular search if Unix search
4012 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004014 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004015
Steve French88274812006-03-09 22:21:45 +00004016 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017
4018 /* BB eventually could optimize out free and realloc of buf */
4019 /* for this case */
4020 if (rc == -EAGAIN)
4021 goto findFirstRetry;
4022 } else { /* decode response */
4023 /* BB remember to free buffer if error BB */
4024 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004025 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004026 unsigned int lnoff;
4027
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004029 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 else
Steve French4b18f2a2008-04-29 00:06:05 +00004031 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032
4033 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004034 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004035 psrch_inf->srch_entries_start =
4036 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4039 le16_to_cpu(pSMBr->t2.ParameterOffset));
4040
Steve French790fe572007-07-07 19:25:05 +00004041 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004042 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 else
Steve French4b18f2a2008-04-29 00:06:05 +00004044 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045
Steve French50c2f752007-07-13 00:33:32 +00004046 psrch_inf->entries_in_buffer =
4047 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004048 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004050 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004051 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004052 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004053 psrch_inf->last_entry = NULL;
4054 return rc;
4055 }
4056
Steve French0752f152008-10-07 20:03:33 +00004057 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004058 lnoff;
4059
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060 *pnetfid = parms->SearchHandle;
4061 } else {
4062 cifs_buf_release(pSMB);
4063 }
4064 }
4065
4066 return rc;
4067}
4068
Steve French96daf2b2011-05-27 04:34:02 +00004069int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004070 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071{
4072 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4073 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004074 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 char *response_data;
4076 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004077 int bytes_returned;
4078 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004079 __u16 params, byte_count;
4080
Joe Perchesb6b38f72010-04-21 03:50:45 +00004081 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082
Steve French4b18f2a2008-04-29 00:06:05 +00004083 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 return -ENOENT;
4085
4086 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4087 (void **) &pSMBr);
4088 if (rc)
4089 return rc;
4090
Steve French50c2f752007-07-13 00:33:32 +00004091 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 byte_count = 0;
4093 pSMB->TotalDataCount = 0; /* no EAs */
4094 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004095 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 pSMB->MaxSetupCount = 0;
4097 pSMB->Reserved = 0;
4098 pSMB->Flags = 0;
4099 pSMB->Timeout = 0;
4100 pSMB->Reserved2 = 0;
4101 pSMB->ParameterOffset = cpu_to_le16(
4102 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4103 pSMB->DataCount = 0;
4104 pSMB->DataOffset = 0;
4105 pSMB->SetupCount = 1;
4106 pSMB->Reserved3 = 0;
4107 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4108 pSMB->SearchHandle = searchHandle; /* always kept as le */
4109 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00004110 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4112 pSMB->ResumeKey = psrch_inf->resume_key;
4113 pSMB->SearchFlags =
4114 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4115
4116 name_len = psrch_inf->resume_name_len;
4117 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004118 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4120 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004121 /* 14 byte parm len above enough for 2 byte null terminator */
4122 pSMB->ResumeFileName[name_len] = 0;
4123 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 } else {
4125 rc = -EINVAL;
4126 goto FNext2_err_exit;
4127 }
4128 byte_count = params + 1 /* pad */ ;
4129 pSMB->TotalParameterCount = cpu_to_le16(params);
4130 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004131 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004133
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4135 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004136 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 if (rc) {
4138 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004139 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004140 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004141 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004143 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 } else { /* decode response */
4145 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004146
Steve French790fe572007-07-07 19:25:05 +00004147 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004148 unsigned int lnoff;
4149
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 /* BB fixme add lock for file (srch_info) struct here */
4151 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004152 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 else
Steve French4b18f2a2008-04-29 00:06:05 +00004154 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 response_data = (char *) &pSMBr->hdr.Protocol +
4156 le16_to_cpu(pSMBr->t2.ParameterOffset);
4157 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4158 response_data = (char *)&pSMBr->hdr.Protocol +
4159 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004160 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004161 cifs_small_buf_release(
4162 psrch_inf->ntwrk_buf_start);
4163 else
4164 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 psrch_inf->srch_entries_start = response_data;
4166 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004167 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004168 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004169 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 else
Steve French4b18f2a2008-04-29 00:06:05 +00004171 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004172 psrch_inf->entries_in_buffer =
4173 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 psrch_inf->index_of_last_entry +=
4175 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004176 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004177 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004178 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004179 psrch_inf->last_entry = NULL;
4180 return rc;
4181 } else
4182 psrch_inf->last_entry =
4183 psrch_inf->srch_entries_start + lnoff;
4184
Joe Perchesb6b38f72010-04-21 03:50:45 +00004185/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4186 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
4188 /* BB fixme add unlock here */
4189 }
4190
4191 }
4192
4193 /* BB On error, should we leave previous search buf (and count and
4194 last entry fields) intact or free the previous one? */
4195
4196 /* Note: On -EAGAIN error only caller can retry on handle based calls
4197 since file handle passed in no longer valid */
4198FNext2_err_exit:
4199 if (rc != 0)
4200 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004201 return rc;
4202}
4203
4204int
Steve French96daf2b2011-05-27 04:34:02 +00004205CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004206 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207{
4208 int rc = 0;
4209 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210
Joe Perchesb6b38f72010-04-21 03:50:45 +00004211 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4213
4214 /* no sense returning error if session restarted
4215 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004216 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 return 0;
4218 if (rc)
4219 return rc;
4220
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221 pSMB->FileID = searchHandle;
4222 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004223 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004224 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004225 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004226
Steve Frencha4544342005-08-24 13:59:35 -07004227 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228
4229 /* Since session is dead, search handle closed on server already */
4230 if (rc == -EAGAIN)
4231 rc = 0;
4232
4233 return rc;
4234}
4235
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236int
Steve French96daf2b2011-05-27 04:34:02 +00004237CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004238 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004239 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004240 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241{
4242 int rc = 0;
4243 TRANSACTION2_QPI_REQ *pSMB = NULL;
4244 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4245 int name_len, bytes_returned;
4246 __u16 params, byte_count;
4247
Joe Perchesb6b38f72010-04-21 03:50:45 +00004248 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004249 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004250 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251
4252GetInodeNumberRetry:
4253 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004254 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 if (rc)
4256 return rc;
4257
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4259 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004260 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004261 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 name_len++; /* trailing null */
4263 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004264 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 name_len = strnlen(searchName, PATH_MAX);
4266 name_len++; /* trailing null */
4267 strncpy(pSMB->FileName, searchName, name_len);
4268 }
4269
4270 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4271 pSMB->TotalDataCount = 0;
4272 pSMB->MaxParameterCount = cpu_to_le16(2);
4273 /* BB find exact max data count below from sess structure BB */
4274 pSMB->MaxDataCount = cpu_to_le16(4000);
4275 pSMB->MaxSetupCount = 0;
4276 pSMB->Reserved = 0;
4277 pSMB->Flags = 0;
4278 pSMB->Timeout = 0;
4279 pSMB->Reserved2 = 0;
4280 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004281 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282 pSMB->DataCount = 0;
4283 pSMB->DataOffset = 0;
4284 pSMB->SetupCount = 1;
4285 pSMB->Reserved3 = 0;
4286 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4287 byte_count = params + 1 /* pad */ ;
4288 pSMB->TotalParameterCount = cpu_to_le16(params);
4289 pSMB->ParameterCount = pSMB->TotalParameterCount;
4290 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4291 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004292 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 pSMB->ByteCount = cpu_to_le16(byte_count);
4294
4295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4297 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004298 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 } else {
4300 /* decode response */
4301 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004303 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 /* If rc should we check for EOPNOSUPP and
4305 disable the srvino flag? or in caller? */
4306 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004307 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4309 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004310 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004312 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004313 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 rc = -EIO;
4315 goto GetInodeNumOut;
4316 }
4317 pfinfo = (struct file_internal_info *)
4318 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004319 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 }
4321 }
4322GetInodeNumOut:
4323 cifs_buf_release(pSMB);
4324 if (rc == -EAGAIN)
4325 goto GetInodeNumberRetry;
4326 return rc;
4327}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328
Igor Mammedovfec45852008-05-16 13:06:30 +04004329/* parses DFS refferal V3 structure
4330 * caller is responsible for freeing target_nodes
4331 * returns:
4332 * on success - 0
4333 * on failure - errno
4334 */
4335static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004336parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004337 unsigned int *num_of_nodes,
4338 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004339 const struct nls_table *nls_codepage, int remap,
4340 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004341{
4342 int i, rc = 0;
4343 char *data_end;
4344 bool is_unicode;
4345 struct dfs_referral_level_3 *ref;
4346
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004347 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4348 is_unicode = true;
4349 else
4350 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004351 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4352
4353 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004354 cERROR(1, "num_referrals: must be at least > 0,"
4355 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004356 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004357 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004358 }
4359
4360 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004361 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004362 cERROR(1, "Referrals of V%d version are not supported,"
4363 "should be V3", le16_to_cpu(ref->VersionNumber));
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 /* get the upper boundary of the resp buffer */
4369 data_end = (char *)(&(pSMBr->PathConsumed)) +
4370 le16_to_cpu(pSMBr->t2.DataCount);
4371
Steve Frenchf19159d2010-04-21 04:12:10 +00004372 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004373 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004374 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004375
4376 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4377 *num_of_nodes, GFP_KERNEL);
4378 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004379 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004380 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004381 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004382 }
4383
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004384 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004385 for (i = 0; i < *num_of_nodes; i++) {
4386 char *temp;
4387 int max_len;
4388 struct dfs_info3_param *node = (*target_nodes)+i;
4389
Steve French0e0d2cf2009-05-01 05:27:32 +00004390 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004391 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004392 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4393 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004394 if (tmp == NULL) {
4395 rc = -ENOMEM;
4396 goto parse_DFS_referrals_exit;
4397 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004398 cifsConvertToUCS((__le16 *) tmp, searchName,
4399 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004400 node->path_consumed = cifs_ucs2_bytes(tmp,
4401 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004402 nls_codepage);
4403 kfree(tmp);
4404 } else
4405 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4406
Igor Mammedovfec45852008-05-16 13:06:30 +04004407 node->server_type = le16_to_cpu(ref->ServerType);
4408 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4409
4410 /* copy DfsPath */
4411 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4412 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004413 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4414 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004415 if (!node->path_name) {
4416 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004417 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004418 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004419
4420 /* copy link target UNC */
4421 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4422 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004423 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4424 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004425 if (!node->node_name)
4426 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004427 }
4428
Steve Frencha1fe78f2008-05-16 18:48:38 +00004429parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004430 if (rc) {
4431 free_dfs_info_array(*target_nodes, *num_of_nodes);
4432 *target_nodes = NULL;
4433 *num_of_nodes = 0;
4434 }
4435 return rc;
4436}
4437
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438int
Steve French96daf2b2011-05-27 04:34:02 +00004439CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004441 struct dfs_info3_param **target_nodes,
4442 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004443 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444{
4445/* TRANS2_GET_DFS_REFERRAL */
4446 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4447 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 int rc = 0;
4449 int bytes_returned;
4450 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004452 *num_of_nodes = 0;
4453 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
Joe Perchesb6b38f72010-04-21 03:50:45 +00004455 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 if (ses == NULL)
4457 return -ENODEV;
4458getDFSRetry:
4459 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4460 (void **) &pSMBr);
4461 if (rc)
4462 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004463
4464 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004465 but should never be null here anyway */
4466 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 pSMB->hdr.Tid = ses->ipc_tid;
4468 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004469 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004471 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473
4474 if (ses->capabilities & CAP_UNICODE) {
4475 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4476 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004477 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004478 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 name_len++; /* trailing null */
4480 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004481 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 name_len = strnlen(searchName, PATH_MAX);
4483 name_len++; /* trailing null */
4484 strncpy(pSMB->RequestFileName, searchName, name_len);
4485 }
4486
Steve French790fe572007-07-07 19:25:05 +00004487 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004488 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004489 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4490 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4491 }
4492
Steve French50c2f752007-07-13 00:33:32 +00004493 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004494
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 params = 2 /* level */ + name_len /*includes null */ ;
4496 pSMB->TotalDataCount = 0;
4497 pSMB->DataCount = 0;
4498 pSMB->DataOffset = 0;
4499 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004500 /* BB find exact max SMB PDU from sess structure BB */
4501 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 pSMB->MaxSetupCount = 0;
4503 pSMB->Reserved = 0;
4504 pSMB->Flags = 0;
4505 pSMB->Timeout = 0;
4506 pSMB->Reserved2 = 0;
4507 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004508 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 pSMB->SetupCount = 1;
4510 pSMB->Reserved3 = 0;
4511 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4512 byte_count = params + 3 /* pad */ ;
4513 pSMB->ParameterCount = cpu_to_le16(params);
4514 pSMB->TotalParameterCount = pSMB->ParameterCount;
4515 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004516 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 pSMB->ByteCount = cpu_to_le16(byte_count);
4518
4519 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4520 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4521 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004522 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004523 goto GetDFSRefExit;
4524 }
4525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004527 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004528 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004529 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004530 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004532
Joe Perchesb6b38f72010-04-21 03:50:45 +00004533 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004534 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004535 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004536
4537 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004538 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004539 target_nodes, nls_codepage, remap,
4540 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004541
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004543 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544
4545 if (rc == -EAGAIN)
4546 goto getDFSRetry;
4547
4548 return rc;
4549}
4550
Steve French20962432005-09-21 22:05:57 -07004551/* Query File System Info such as free space to old servers such as Win 9x */
4552int
Steve French96daf2b2011-05-27 04:34:02 +00004553SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004554{
4555/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4556 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4557 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4558 FILE_SYSTEM_ALLOC_INFO *response_data;
4559 int rc = 0;
4560 int bytes_returned = 0;
4561 __u16 params, byte_count;
4562
Joe Perchesb6b38f72010-04-21 03:50:45 +00004563 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004564oldQFSInfoRetry:
4565 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4566 (void **) &pSMBr);
4567 if (rc)
4568 return rc;
Steve French20962432005-09-21 22:05:57 -07004569
4570 params = 2; /* level */
4571 pSMB->TotalDataCount = 0;
4572 pSMB->MaxParameterCount = cpu_to_le16(2);
4573 pSMB->MaxDataCount = cpu_to_le16(1000);
4574 pSMB->MaxSetupCount = 0;
4575 pSMB->Reserved = 0;
4576 pSMB->Flags = 0;
4577 pSMB->Timeout = 0;
4578 pSMB->Reserved2 = 0;
4579 byte_count = params + 1 /* pad */ ;
4580 pSMB->TotalParameterCount = cpu_to_le16(params);
4581 pSMB->ParameterCount = pSMB->TotalParameterCount;
4582 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4583 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4584 pSMB->DataCount = 0;
4585 pSMB->DataOffset = 0;
4586 pSMB->SetupCount = 1;
4587 pSMB->Reserved3 = 0;
4588 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4589 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004590 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004591 pSMB->ByteCount = cpu_to_le16(byte_count);
4592
4593 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4594 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4595 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004596 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004597 } else { /* decode response */
4598 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4599
Jeff Layton820a8032011-05-04 08:05:26 -04004600 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004601 rc = -EIO; /* bad smb */
4602 else {
4603 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004604 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004605 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004606
Steve French50c2f752007-07-13 00:33:32 +00004607 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004608 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4609 FSData->f_bsize =
4610 le16_to_cpu(response_data->BytesPerSector) *
4611 le32_to_cpu(response_data->
4612 SectorsPerAllocationUnit);
4613 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004614 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004615 FSData->f_bfree = FSData->f_bavail =
4616 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004617 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4618 (unsigned long long)FSData->f_blocks,
4619 (unsigned long long)FSData->f_bfree,
4620 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004621 }
4622 }
4623 cifs_buf_release(pSMB);
4624
4625 if (rc == -EAGAIN)
4626 goto oldQFSInfoRetry;
4627
4628 return rc;
4629}
4630
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631int
Steve French96daf2b2011-05-27 04:34:02 +00004632CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633{
4634/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4635 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4636 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4637 FILE_SYSTEM_INFO *response_data;
4638 int rc = 0;
4639 int bytes_returned = 0;
4640 __u16 params, byte_count;
4641
Joe Perchesb6b38f72010-04-21 03:50:45 +00004642 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643QFSInfoRetry:
4644 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4645 (void **) &pSMBr);
4646 if (rc)
4647 return rc;
4648
4649 params = 2; /* level */
4650 pSMB->TotalDataCount = 0;
4651 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004652 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 pSMB->MaxSetupCount = 0;
4654 pSMB->Reserved = 0;
4655 pSMB->Flags = 0;
4656 pSMB->Timeout = 0;
4657 pSMB->Reserved2 = 0;
4658 byte_count = params + 1 /* pad */ ;
4659 pSMB->TotalParameterCount = cpu_to_le16(params);
4660 pSMB->ParameterCount = pSMB->TotalParameterCount;
4661 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004662 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 pSMB->DataCount = 0;
4664 pSMB->DataOffset = 0;
4665 pSMB->SetupCount = 1;
4666 pSMB->Reserved3 = 0;
4667 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4668 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004669 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 pSMB->ByteCount = cpu_to_le16(byte_count);
4671
4672 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4673 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4674 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004675 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004677 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678
Jeff Layton820a8032011-05-04 08:05:26 -04004679 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680 rc = -EIO; /* bad smb */
4681 else {
4682 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683
4684 response_data =
4685 (FILE_SYSTEM_INFO
4686 *) (((char *) &pSMBr->hdr.Protocol) +
4687 data_offset);
4688 FSData->f_bsize =
4689 le32_to_cpu(response_data->BytesPerSector) *
4690 le32_to_cpu(response_data->
4691 SectorsPerAllocationUnit);
4692 FSData->f_blocks =
4693 le64_to_cpu(response_data->TotalAllocationUnits);
4694 FSData->f_bfree = FSData->f_bavail =
4695 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004696 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4697 (unsigned long long)FSData->f_blocks,
4698 (unsigned long long)FSData->f_bfree,
4699 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700 }
4701 }
4702 cifs_buf_release(pSMB);
4703
4704 if (rc == -EAGAIN)
4705 goto QFSInfoRetry;
4706
4707 return rc;
4708}
4709
4710int
Steve French96daf2b2011-05-27 04:34:02 +00004711CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712{
4713/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4714 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4715 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4716 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4717 int rc = 0;
4718 int bytes_returned = 0;
4719 __u16 params, byte_count;
4720
Joe Perchesb6b38f72010-04-21 03:50:45 +00004721 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722QFSAttributeRetry:
4723 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4724 (void **) &pSMBr);
4725 if (rc)
4726 return rc;
4727
4728 params = 2; /* level */
4729 pSMB->TotalDataCount = 0;
4730 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004731 /* BB find exact max SMB PDU from sess structure BB */
4732 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 pSMB->MaxSetupCount = 0;
4734 pSMB->Reserved = 0;
4735 pSMB->Flags = 0;
4736 pSMB->Timeout = 0;
4737 pSMB->Reserved2 = 0;
4738 byte_count = params + 1 /* pad */ ;
4739 pSMB->TotalParameterCount = cpu_to_le16(params);
4740 pSMB->ParameterCount = pSMB->TotalParameterCount;
4741 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004742 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 pSMB->DataCount = 0;
4744 pSMB->DataOffset = 0;
4745 pSMB->SetupCount = 1;
4746 pSMB->Reserved3 = 0;
4747 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4748 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004749 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 pSMB->ByteCount = cpu_to_le16(byte_count);
4751
4752 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4753 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4754 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004755 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 } else { /* decode response */
4757 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4758
Jeff Layton820a8032011-05-04 08:05:26 -04004759 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004760 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 rc = -EIO; /* bad smb */
4762 } else {
4763 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4764 response_data =
4765 (FILE_SYSTEM_ATTRIBUTE_INFO
4766 *) (((char *) &pSMBr->hdr.Protocol) +
4767 data_offset);
4768 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004769 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 }
4771 }
4772 cifs_buf_release(pSMB);
4773
4774 if (rc == -EAGAIN)
4775 goto QFSAttributeRetry;
4776
4777 return rc;
4778}
4779
4780int
Steve French96daf2b2011-05-27 04:34:02 +00004781CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782{
4783/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4784 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4785 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4786 FILE_SYSTEM_DEVICE_INFO *response_data;
4787 int rc = 0;
4788 int bytes_returned = 0;
4789 __u16 params, byte_count;
4790
Joe Perchesb6b38f72010-04-21 03:50:45 +00004791 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792QFSDeviceRetry:
4793 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4794 (void **) &pSMBr);
4795 if (rc)
4796 return rc;
4797
4798 params = 2; /* level */
4799 pSMB->TotalDataCount = 0;
4800 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004801 /* BB find exact max SMB PDU from sess structure BB */
4802 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 pSMB->MaxSetupCount = 0;
4804 pSMB->Reserved = 0;
4805 pSMB->Flags = 0;
4806 pSMB->Timeout = 0;
4807 pSMB->Reserved2 = 0;
4808 byte_count = params + 1 /* pad */ ;
4809 pSMB->TotalParameterCount = cpu_to_le16(params);
4810 pSMB->ParameterCount = pSMB->TotalParameterCount;
4811 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004812 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813
4814 pSMB->DataCount = 0;
4815 pSMB->DataOffset = 0;
4816 pSMB->SetupCount = 1;
4817 pSMB->Reserved3 = 0;
4818 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4819 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004820 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 pSMB->ByteCount = cpu_to_le16(byte_count);
4822
4823 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4825 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004826 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 } else { /* decode response */
4828 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4829
Jeff Layton820a8032011-05-04 08:05:26 -04004830 if (rc || get_bcc(&pSMBr->hdr) <
4831 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 rc = -EIO; /* bad smb */
4833 else {
4834 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4835 response_data =
Steve French737b7582005-04-28 22:41:06 -07004836 (FILE_SYSTEM_DEVICE_INFO *)
4837 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 data_offset);
4839 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004840 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841 }
4842 }
4843 cifs_buf_release(pSMB);
4844
4845 if (rc == -EAGAIN)
4846 goto QFSDeviceRetry;
4847
4848 return rc;
4849}
4850
4851int
Steve French96daf2b2011-05-27 04:34:02 +00004852CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853{
4854/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4855 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4856 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4857 FILE_SYSTEM_UNIX_INFO *response_data;
4858 int rc = 0;
4859 int bytes_returned = 0;
4860 __u16 params, byte_count;
4861
Joe Perchesb6b38f72010-04-21 03:50:45 +00004862 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004864 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4865 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 if (rc)
4867 return rc;
4868
4869 params = 2; /* level */
4870 pSMB->TotalDataCount = 0;
4871 pSMB->DataCount = 0;
4872 pSMB->DataOffset = 0;
4873 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004874 /* BB find exact max SMB PDU from sess structure BB */
4875 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 pSMB->MaxSetupCount = 0;
4877 pSMB->Reserved = 0;
4878 pSMB->Flags = 0;
4879 pSMB->Timeout = 0;
4880 pSMB->Reserved2 = 0;
4881 byte_count = params + 1 /* pad */ ;
4882 pSMB->ParameterCount = cpu_to_le16(params);
4883 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004884 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4885 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886 pSMB->SetupCount = 1;
4887 pSMB->Reserved3 = 0;
4888 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4889 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004890 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->ByteCount = cpu_to_le16(byte_count);
4892
4893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4895 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004896 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 } else { /* decode response */
4898 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4899
Jeff Layton820a8032011-05-04 08:05:26 -04004900 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 rc = -EIO; /* bad smb */
4902 } else {
4903 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4904 response_data =
4905 (FILE_SYSTEM_UNIX_INFO
4906 *) (((char *) &pSMBr->hdr.Protocol) +
4907 data_offset);
4908 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004909 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 }
4911 }
4912 cifs_buf_release(pSMB);
4913
4914 if (rc == -EAGAIN)
4915 goto QFSUnixRetry;
4916
4917
4918 return rc;
4919}
4920
Jeremy Allisonac670552005-06-22 17:26:35 -07004921int
Steve French96daf2b2011-05-27 04:34:02 +00004922CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004923{
4924/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4925 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4926 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4927 int rc = 0;
4928 int bytes_returned = 0;
4929 __u16 params, param_offset, offset, byte_count;
4930
Joe Perchesb6b38f72010-04-21 03:50:45 +00004931 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004932SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004933 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004934 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4935 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004936 if (rc)
4937 return rc;
4938
4939 params = 4; /* 2 bytes zero followed by info level. */
4940 pSMB->MaxSetupCount = 0;
4941 pSMB->Reserved = 0;
4942 pSMB->Flags = 0;
4943 pSMB->Timeout = 0;
4944 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004945 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4946 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004947 offset = param_offset + params;
4948
4949 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004950 /* BB find exact max SMB PDU from sess structure BB */
4951 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004952 pSMB->SetupCount = 1;
4953 pSMB->Reserved3 = 0;
4954 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4955 byte_count = 1 /* pad */ + params + 12;
4956
4957 pSMB->DataCount = cpu_to_le16(12);
4958 pSMB->ParameterCount = cpu_to_le16(params);
4959 pSMB->TotalDataCount = pSMB->DataCount;
4960 pSMB->TotalParameterCount = pSMB->ParameterCount;
4961 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4962 pSMB->DataOffset = cpu_to_le16(offset);
4963
4964 /* Params. */
4965 pSMB->FileNum = 0;
4966 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4967
4968 /* Data. */
4969 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4970 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4971 pSMB->ClientUnixCap = cpu_to_le64(cap);
4972
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004973 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004974 pSMB->ByteCount = cpu_to_le16(byte_count);
4975
4976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4978 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004979 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004980 } else { /* decode response */
4981 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004982 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004983 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004984 }
4985 cifs_buf_release(pSMB);
4986
4987 if (rc == -EAGAIN)
4988 goto SETFSUnixRetry;
4989
4990 return rc;
4991}
4992
4993
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994
4995int
Steve French96daf2b2011-05-27 04:34:02 +00004996CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07004997 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998{
4999/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5000 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5001 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5002 FILE_SYSTEM_POSIX_INFO *response_data;
5003 int rc = 0;
5004 int bytes_returned = 0;
5005 __u16 params, byte_count;
5006
Joe Perchesb6b38f72010-04-21 03:50:45 +00005007 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008QFSPosixRetry:
5009 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5010 (void **) &pSMBr);
5011 if (rc)
5012 return rc;
5013
5014 params = 2; /* level */
5015 pSMB->TotalDataCount = 0;
5016 pSMB->DataCount = 0;
5017 pSMB->DataOffset = 0;
5018 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005019 /* BB find exact max SMB PDU from sess structure BB */
5020 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005021 pSMB->MaxSetupCount = 0;
5022 pSMB->Reserved = 0;
5023 pSMB->Flags = 0;
5024 pSMB->Timeout = 0;
5025 pSMB->Reserved2 = 0;
5026 byte_count = params + 1 /* pad */ ;
5027 pSMB->ParameterCount = cpu_to_le16(params);
5028 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005029 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5030 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005031 pSMB->SetupCount = 1;
5032 pSMB->Reserved3 = 0;
5033 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5034 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005035 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 pSMB->ByteCount = cpu_to_le16(byte_count);
5037
5038 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5039 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5040 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005041 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 } else { /* decode response */
5043 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5044
Jeff Layton820a8032011-05-04 08:05:26 -04005045 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 rc = -EIO; /* bad smb */
5047 } else {
5048 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5049 response_data =
5050 (FILE_SYSTEM_POSIX_INFO
5051 *) (((char *) &pSMBr->hdr.Protocol) +
5052 data_offset);
5053 FSData->f_bsize =
5054 le32_to_cpu(response_data->BlockSize);
5055 FSData->f_blocks =
5056 le64_to_cpu(response_data->TotalBlocks);
5057 FSData->f_bfree =
5058 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005059 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 FSData->f_bavail = FSData->f_bfree;
5061 } else {
5062 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005063 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 }
Steve French790fe572007-07-07 19:25:05 +00005065 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005067 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005068 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005070 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 }
5072 }
5073 cifs_buf_release(pSMB);
5074
5075 if (rc == -EAGAIN)
5076 goto QFSPosixRetry;
5077
5078 return rc;
5079}
5080
5081
Steve French50c2f752007-07-13 00:33:32 +00005082/* We can not use write of zero bytes trick to
5083 set file size due to need for large file support. Also note that
5084 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005085 routine which is only needed to work around a sharing violation bug
5086 in Samba which this routine can run into */
5087
5088int
Steve French96daf2b2011-05-27 04:34:02 +00005089CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005090 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005091 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092{
5093 struct smb_com_transaction2_spi_req *pSMB = NULL;
5094 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5095 struct file_end_of_file_info *parm_data;
5096 int name_len;
5097 int rc = 0;
5098 int bytes_returned = 0;
5099 __u16 params, byte_count, data_count, param_offset, offset;
5100
Joe Perchesb6b38f72010-04-21 03:50:45 +00005101 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102SetEOFRetry:
5103 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5104 (void **) &pSMBr);
5105 if (rc)
5106 return rc;
5107
5108 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5109 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005110 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005111 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005112 name_len++; /* trailing null */
5113 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005114 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 name_len = strnlen(fileName, PATH_MAX);
5116 name_len++; /* trailing null */
5117 strncpy(pSMB->FileName, fileName, name_len);
5118 }
5119 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005120 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005122 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 pSMB->MaxSetupCount = 0;
5124 pSMB->Reserved = 0;
5125 pSMB->Flags = 0;
5126 pSMB->Timeout = 0;
5127 pSMB->Reserved2 = 0;
5128 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005129 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005131 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005132 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5133 pSMB->InformationLevel =
5134 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5135 else
5136 pSMB->InformationLevel =
5137 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5138 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5140 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005141 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 else
5143 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005144 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005145 }
5146
5147 parm_data =
5148 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5149 offset);
5150 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5151 pSMB->DataOffset = cpu_to_le16(offset);
5152 pSMB->SetupCount = 1;
5153 pSMB->Reserved3 = 0;
5154 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5155 byte_count = 3 /* pad */ + params + data_count;
5156 pSMB->DataCount = cpu_to_le16(data_count);
5157 pSMB->TotalDataCount = pSMB->DataCount;
5158 pSMB->ParameterCount = cpu_to_le16(params);
5159 pSMB->TotalParameterCount = pSMB->ParameterCount;
5160 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005161 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162 parm_data->FileSize = cpu_to_le64(size);
5163 pSMB->ByteCount = cpu_to_le16(byte_count);
5164 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5165 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005166 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005167 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168
5169 cifs_buf_release(pSMB);
5170
5171 if (rc == -EAGAIN)
5172 goto SetEOFRetry;
5173
5174 return rc;
5175}
5176
5177int
Steve French96daf2b2011-05-27 04:34:02 +00005178CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005179 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180{
5181 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 struct file_end_of_file_info *parm_data;
5183 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 __u16 params, param_offset, offset, byte_count, count;
5185
Joe Perchesb6b38f72010-04-21 03:50:45 +00005186 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5187 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005188 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5189
Linus Torvalds1da177e2005-04-16 15:20:36 -07005190 if (rc)
5191 return rc;
5192
5193 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5194 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005195
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 params = 6;
5197 pSMB->MaxSetupCount = 0;
5198 pSMB->Reserved = 0;
5199 pSMB->Flags = 0;
5200 pSMB->Timeout = 0;
5201 pSMB->Reserved2 = 0;
5202 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5203 offset = param_offset + params;
5204
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 count = sizeof(struct file_end_of_file_info);
5206 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005207 /* BB find exact max SMB PDU from sess structure BB */
5208 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209 pSMB->SetupCount = 1;
5210 pSMB->Reserved3 = 0;
5211 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5212 byte_count = 3 /* pad */ + params + count;
5213 pSMB->DataCount = cpu_to_le16(count);
5214 pSMB->ParameterCount = cpu_to_le16(params);
5215 pSMB->TotalDataCount = pSMB->DataCount;
5216 pSMB->TotalParameterCount = pSMB->ParameterCount;
5217 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5218 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005219 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5220 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 pSMB->DataOffset = cpu_to_le16(offset);
5222 parm_data->FileSize = cpu_to_le64(size);
5223 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005224 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5226 pSMB->InformationLevel =
5227 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5228 else
5229 pSMB->InformationLevel =
5230 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005231 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5233 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005234 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005235 else
5236 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005237 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005238 }
5239 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005240 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005242 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005244 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 }
5246
Steve French50c2f752007-07-13 00:33:32 +00005247 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 since file handle passed in no longer valid */
5249
5250 return rc;
5251}
5252
Steve French50c2f752007-07-13 00:33:32 +00005253/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005254 an open handle, rather than by pathname - this is awkward due to
5255 potential access conflicts on the open, but it is unavoidable for these
5256 old servers since the only other choice is to go from 100 nanosecond DCE
5257 time and resort to the original setpathinfo level which takes the ancient
5258 DOS time format with 2 second granularity */
5259int
Steve French96daf2b2011-05-27 04:34:02 +00005260CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005261 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005262{
5263 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005264 char *data_offset;
5265 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 __u16 params, param_offset, offset, byte_count, count;
5267
Joe Perchesb6b38f72010-04-21 03:50:45 +00005268 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005269 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5270
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 if (rc)
5272 return rc;
5273
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005274 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5275 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005276
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 params = 6;
5278 pSMB->MaxSetupCount = 0;
5279 pSMB->Reserved = 0;
5280 pSMB->Flags = 0;
5281 pSMB->Timeout = 0;
5282 pSMB->Reserved2 = 0;
5283 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5284 offset = param_offset + params;
5285
Steve French50c2f752007-07-13 00:33:32 +00005286 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287
Steve French26f57362007-08-30 22:09:15 +00005288 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005290 /* BB find max SMB PDU from sess */
5291 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 pSMB->SetupCount = 1;
5293 pSMB->Reserved3 = 0;
5294 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5295 byte_count = 3 /* pad */ + params + count;
5296 pSMB->DataCount = cpu_to_le16(count);
5297 pSMB->ParameterCount = cpu_to_le16(params);
5298 pSMB->TotalDataCount = pSMB->DataCount;
5299 pSMB->TotalParameterCount = pSMB->ParameterCount;
5300 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5301 pSMB->DataOffset = cpu_to_le16(offset);
5302 pSMB->Fid = fid;
5303 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5304 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5305 else
5306 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5307 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005308 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005309 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005310 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005311 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005312 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005313 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314
Steve French50c2f752007-07-13 00:33:32 +00005315 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 since file handle passed in no longer valid */
5317
5318 return rc;
5319}
5320
Jeff Layton6d22f092008-09-23 11:48:35 -04005321int
Steve French96daf2b2011-05-27 04:34:02 +00005322CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005323 bool delete_file, __u16 fid, __u32 pid_of_opener)
5324{
5325 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5326 char *data_offset;
5327 int rc = 0;
5328 __u16 params, param_offset, offset, byte_count, count;
5329
Joe Perchesb6b38f72010-04-21 03:50:45 +00005330 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005331 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5332
5333 if (rc)
5334 return rc;
5335
5336 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5337 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5338
5339 params = 6;
5340 pSMB->MaxSetupCount = 0;
5341 pSMB->Reserved = 0;
5342 pSMB->Flags = 0;
5343 pSMB->Timeout = 0;
5344 pSMB->Reserved2 = 0;
5345 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5346 offset = param_offset + params;
5347
5348 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5349
5350 count = 1;
5351 pSMB->MaxParameterCount = cpu_to_le16(2);
5352 /* BB find max SMB PDU from sess */
5353 pSMB->MaxDataCount = cpu_to_le16(1000);
5354 pSMB->SetupCount = 1;
5355 pSMB->Reserved3 = 0;
5356 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5357 byte_count = 3 /* pad */ + params + count;
5358 pSMB->DataCount = cpu_to_le16(count);
5359 pSMB->ParameterCount = cpu_to_le16(params);
5360 pSMB->TotalDataCount = pSMB->DataCount;
5361 pSMB->TotalParameterCount = pSMB->ParameterCount;
5362 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5363 pSMB->DataOffset = cpu_to_le16(offset);
5364 pSMB->Fid = fid;
5365 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5366 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005367 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005368 pSMB->ByteCount = cpu_to_le16(byte_count);
5369 *data_offset = delete_file ? 1 : 0;
5370 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5371 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005372 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005373
5374 return rc;
5375}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376
5377int
Steve French96daf2b2011-05-27 04:34:02 +00005378CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005379 const char *fileName, const FILE_BASIC_INFO *data,
5380 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381{
5382 TRANSACTION2_SPI_REQ *pSMB = NULL;
5383 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5384 int name_len;
5385 int rc = 0;
5386 int bytes_returned = 0;
5387 char *data_offset;
5388 __u16 params, param_offset, offset, byte_count, count;
5389
Joe Perchesb6b38f72010-04-21 03:50:45 +00005390 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391
5392SetTimesRetry:
5393 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5394 (void **) &pSMBr);
5395 if (rc)
5396 return rc;
5397
5398 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5399 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005400 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005401 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 name_len++; /* trailing null */
5403 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005404 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005405 name_len = strnlen(fileName, PATH_MAX);
5406 name_len++; /* trailing null */
5407 strncpy(pSMB->FileName, fileName, name_len);
5408 }
5409
5410 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005411 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005413 /* BB find max SMB PDU from sess structure BB */
5414 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 pSMB->MaxSetupCount = 0;
5416 pSMB->Reserved = 0;
5417 pSMB->Flags = 0;
5418 pSMB->Timeout = 0;
5419 pSMB->Reserved2 = 0;
5420 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005421 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 offset = param_offset + params;
5423 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5424 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5425 pSMB->DataOffset = cpu_to_le16(offset);
5426 pSMB->SetupCount = 1;
5427 pSMB->Reserved3 = 0;
5428 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5429 byte_count = 3 /* pad */ + params + count;
5430
5431 pSMB->DataCount = cpu_to_le16(count);
5432 pSMB->ParameterCount = cpu_to_le16(params);
5433 pSMB->TotalDataCount = pSMB->DataCount;
5434 pSMB->TotalParameterCount = pSMB->ParameterCount;
5435 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5436 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5437 else
5438 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5439 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005440 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005441 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005442 pSMB->ByteCount = cpu_to_le16(byte_count);
5443 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5444 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005445 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005446 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447
5448 cifs_buf_release(pSMB);
5449
5450 if (rc == -EAGAIN)
5451 goto SetTimesRetry;
5452
5453 return rc;
5454}
5455
5456/* Can not be used to set time stamps yet (due to old DOS time format) */
5457/* Can be used to set attributes */
5458#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5459 handling it anyway and NT4 was what we thought it would be needed for
5460 Do not delete it until we prove whether needed for Win9x though */
5461int
Steve French96daf2b2011-05-27 04:34:02 +00005462CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463 __u16 dos_attrs, const struct nls_table *nls_codepage)
5464{
5465 SETATTR_REQ *pSMB = NULL;
5466 SETATTR_RSP *pSMBr = NULL;
5467 int rc = 0;
5468 int bytes_returned;
5469 int name_len;
5470
Joe Perchesb6b38f72010-04-21 03:50:45 +00005471 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472
5473SetAttrLgcyRetry:
5474 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5475 (void **) &pSMBr);
5476 if (rc)
5477 return rc;
5478
5479 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5480 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005481 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005482 PATH_MAX, nls_codepage);
5483 name_len++; /* trailing null */
5484 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005485 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 name_len = strnlen(fileName, PATH_MAX);
5487 name_len++; /* trailing null */
5488 strncpy(pSMB->fileName, fileName, name_len);
5489 }
5490 pSMB->attr = cpu_to_le16(dos_attrs);
5491 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005492 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5494 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5495 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005496 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005497 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
5499 cifs_buf_release(pSMB);
5500
5501 if (rc == -EAGAIN)
5502 goto SetAttrLgcyRetry;
5503
5504 return rc;
5505}
5506#endif /* temporarily unneeded SetAttr legacy function */
5507
Jeff Layton654cf142009-07-09 20:02:49 -04005508static void
5509cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5510 const struct cifs_unix_set_info_args *args)
5511{
5512 u64 mode = args->mode;
5513
5514 /*
5515 * Samba server ignores set of file size to zero due to bugs in some
5516 * older clients, but we should be precise - we use SetFileSize to
5517 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005518 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005519 * zero instead of -1 here
5520 */
5521 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5522 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5523 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5524 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5525 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5526 data_offset->Uid = cpu_to_le64(args->uid);
5527 data_offset->Gid = cpu_to_le64(args->gid);
5528 /* better to leave device as zero when it is */
5529 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5530 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5531 data_offset->Permissions = cpu_to_le64(mode);
5532
5533 if (S_ISREG(mode))
5534 data_offset->Type = cpu_to_le32(UNIX_FILE);
5535 else if (S_ISDIR(mode))
5536 data_offset->Type = cpu_to_le32(UNIX_DIR);
5537 else if (S_ISLNK(mode))
5538 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5539 else if (S_ISCHR(mode))
5540 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5541 else if (S_ISBLK(mode))
5542 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5543 else if (S_ISFIFO(mode))
5544 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5545 else if (S_ISSOCK(mode))
5546 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5547}
5548
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549int
Steve French96daf2b2011-05-27 04:34:02 +00005550CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005551 const struct cifs_unix_set_info_args *args,
5552 u16 fid, u32 pid_of_opener)
5553{
5554 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5555 FILE_UNIX_BASIC_INFO *data_offset;
5556 int rc = 0;
5557 u16 params, param_offset, offset, byte_count, count;
5558
Joe Perchesb6b38f72010-04-21 03:50:45 +00005559 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005560 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5561
5562 if (rc)
5563 return rc;
5564
5565 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5566 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5567
5568 params = 6;
5569 pSMB->MaxSetupCount = 0;
5570 pSMB->Reserved = 0;
5571 pSMB->Flags = 0;
5572 pSMB->Timeout = 0;
5573 pSMB->Reserved2 = 0;
5574 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5575 offset = param_offset + params;
5576
5577 data_offset = (FILE_UNIX_BASIC_INFO *)
5578 ((char *)(&pSMB->hdr.Protocol) + offset);
5579 count = sizeof(FILE_UNIX_BASIC_INFO);
5580
5581 pSMB->MaxParameterCount = cpu_to_le16(2);
5582 /* BB find max SMB PDU from sess */
5583 pSMB->MaxDataCount = cpu_to_le16(1000);
5584 pSMB->SetupCount = 1;
5585 pSMB->Reserved3 = 0;
5586 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5587 byte_count = 3 /* pad */ + params + count;
5588 pSMB->DataCount = cpu_to_le16(count);
5589 pSMB->ParameterCount = cpu_to_le16(params);
5590 pSMB->TotalDataCount = pSMB->DataCount;
5591 pSMB->TotalParameterCount = pSMB->ParameterCount;
5592 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5593 pSMB->DataOffset = cpu_to_le16(offset);
5594 pSMB->Fid = fid;
5595 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5596 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005597 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005598 pSMB->ByteCount = cpu_to_le16(byte_count);
5599
5600 cifs_fill_unix_set_info(data_offset, args);
5601
5602 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5603 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005604 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005605
5606 /* Note: On -EAGAIN error only caller can retry on handle based calls
5607 since file handle passed in no longer valid */
5608
5609 return rc;
5610}
5611
5612int
Steve French96daf2b2011-05-27 04:34:02 +00005613CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005614 const struct cifs_unix_set_info_args *args,
5615 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616{
5617 TRANSACTION2_SPI_REQ *pSMB = NULL;
5618 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5619 int name_len;
5620 int rc = 0;
5621 int bytes_returned = 0;
5622 FILE_UNIX_BASIC_INFO *data_offset;
5623 __u16 params, param_offset, offset, count, byte_count;
5624
Joe Perchesb6b38f72010-04-21 03:50:45 +00005625 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626setPermsRetry:
5627 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5628 (void **) &pSMBr);
5629 if (rc)
5630 return rc;
5631
5632 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5633 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005634 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005635 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005636 name_len++; /* trailing null */
5637 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005638 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005639 name_len = strnlen(fileName, PATH_MAX);
5640 name_len++; /* trailing null */
5641 strncpy(pSMB->FileName, fileName, name_len);
5642 }
5643
5644 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005645 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005647 /* BB find max SMB PDU from sess structure BB */
5648 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005649 pSMB->MaxSetupCount = 0;
5650 pSMB->Reserved = 0;
5651 pSMB->Flags = 0;
5652 pSMB->Timeout = 0;
5653 pSMB->Reserved2 = 0;
5654 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005655 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 offset = param_offset + params;
5657 data_offset =
5658 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5659 offset);
5660 memset(data_offset, 0, count);
5661 pSMB->DataOffset = cpu_to_le16(offset);
5662 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5663 pSMB->SetupCount = 1;
5664 pSMB->Reserved3 = 0;
5665 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5666 byte_count = 3 /* pad */ + params + count;
5667 pSMB->ParameterCount = cpu_to_le16(params);
5668 pSMB->DataCount = cpu_to_le16(count);
5669 pSMB->TotalParameterCount = pSMB->ParameterCount;
5670 pSMB->TotalDataCount = pSMB->DataCount;
5671 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5672 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005673 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005674
Jeff Layton654cf142009-07-09 20:02:49 -04005675 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676
5677 pSMB->ByteCount = cpu_to_le16(byte_count);
5678 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5679 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005680 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005681 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005682
Steve French0d817bc2008-05-22 02:02:03 +00005683 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005684 if (rc == -EAGAIN)
5685 goto setPermsRetry;
5686 return rc;
5687}
5688
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005690/*
5691 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5692 * function used by listxattr and getxattr type calls. When ea_name is set,
5693 * it looks for that attribute name and stuffs that value into the EAData
5694 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5695 * buffer. In both cases, the return value is either the length of the
5696 * resulting data or a negative error code. If EAData is a NULL pointer then
5697 * the data isn't copied to it, but the length is returned.
5698 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005699ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00005700CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005701 const unsigned char *searchName, const unsigned char *ea_name,
5702 char *EAData, size_t buf_size,
5703 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704{
5705 /* BB assumes one setup word */
5706 TRANSACTION2_QPI_REQ *pSMB = NULL;
5707 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5708 int rc = 0;
5709 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005710 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005711 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005712 struct fea *temp_fea;
5713 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005714 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005715 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04005716 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005717
Joe Perchesb6b38f72010-04-21 03:50:45 +00005718 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719QAllEAsRetry:
5720 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5721 (void **) &pSMBr);
5722 if (rc)
5723 return rc;
5724
5725 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005726 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005727 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005728 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005729 list_len++; /* trailing null */
5730 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005731 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005732 list_len = strnlen(searchName, PATH_MAX);
5733 list_len++; /* trailing null */
5734 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 }
5736
Jeff Layton6e462b92010-02-10 16:18:26 -05005737 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005738 pSMB->TotalDataCount = 0;
5739 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005740 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005741 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 pSMB->MaxSetupCount = 0;
5743 pSMB->Reserved = 0;
5744 pSMB->Flags = 0;
5745 pSMB->Timeout = 0;
5746 pSMB->Reserved2 = 0;
5747 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005748 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 pSMB->DataCount = 0;
5750 pSMB->DataOffset = 0;
5751 pSMB->SetupCount = 1;
5752 pSMB->Reserved3 = 0;
5753 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5754 byte_count = params + 1 /* pad */ ;
5755 pSMB->TotalParameterCount = cpu_to_le16(params);
5756 pSMB->ParameterCount = pSMB->TotalParameterCount;
5757 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5758 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005759 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760 pSMB->ByteCount = cpu_to_le16(byte_count);
5761
5762 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5763 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5764 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005765 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005766 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005767 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005768
5769
5770 /* BB also check enough total bytes returned */
5771 /* BB we need to improve the validity checking
5772 of these trans2 responses */
5773
5774 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005775 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005776 rc = -EIO; /* bad smb */
5777 goto QAllEAsOut;
5778 }
5779
5780 /* check that length of list is not more than bcc */
5781 /* check that each entry does not go beyond length
5782 of list */
5783 /* check that each element of each entry does not
5784 go beyond end of list */
5785 /* validate_trans2_offsets() */
5786 /* BB check if start of smb + data_offset > &bcc+ bcc */
5787
5788 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5789 ea_response_data = (struct fealist *)
5790 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5791
Jeff Layton6e462b92010-02-10 16:18:26 -05005792 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005793 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005794 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005795 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005796 goto QAllEAsOut;
5797 }
5798
Jeff Layton0cd126b2010-02-10 16:18:26 -05005799 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005800 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005801 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005802 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005803 rc = -EIO;
5804 goto QAllEAsOut;
5805 }
5806
Jeff Laytonf0d38682010-02-10 16:18:26 -05005807 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005808 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005809 temp_fea = ea_response_data->list;
5810 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005811 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005812 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005813 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005814
Jeff Layton6e462b92010-02-10 16:18:26 -05005815 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005816 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005817 /* make sure we can read name_len and value_len */
5818 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005819 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005820 rc = -EIO;
5821 goto QAllEAsOut;
5822 }
5823
5824 name_len = temp_fea->name_len;
5825 value_len = le16_to_cpu(temp_fea->value_len);
5826 list_len -= name_len + 1 + value_len;
5827 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005828 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005829 rc = -EIO;
5830 goto QAllEAsOut;
5831 }
5832
Jeff Layton31c05192010-02-10 16:18:26 -05005833 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04005834 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04005835 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05005836 temp_ptr += name_len + 1;
5837 rc = value_len;
5838 if (buf_size == 0)
5839 goto QAllEAsOut;
5840 if ((size_t)value_len > buf_size) {
5841 rc = -ERANGE;
5842 goto QAllEAsOut;
5843 }
5844 memcpy(EAData, temp_ptr, value_len);
5845 goto QAllEAsOut;
5846 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005847 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005848 /* account for prefix user. and trailing null */
5849 rc += (5 + 1 + name_len);
5850 if (rc < (int) buf_size) {
5851 memcpy(EAData, "user.", 5);
5852 EAData += 5;
5853 memcpy(EAData, temp_ptr, name_len);
5854 EAData += name_len;
5855 /* null terminate name */
5856 *EAData = 0;
5857 ++EAData;
5858 } else if (buf_size == 0) {
5859 /* skip copy - calc size only */
5860 } else {
5861 /* stop before overrun buffer */
5862 rc = -ERANGE;
5863 break;
5864 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005865 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005866 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005867 temp_fea = (struct fea *)temp_ptr;
5868 }
5869
Jeff Layton31c05192010-02-10 16:18:26 -05005870 /* didn't find the named attribute */
5871 if (ea_name)
5872 rc = -ENODATA;
5873
Jeff Laytonf0d38682010-02-10 16:18:26 -05005874QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005875 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005876 if (rc == -EAGAIN)
5877 goto QAllEAsRetry;
5878
5879 return (ssize_t)rc;
5880}
5881
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882int
Steve French96daf2b2011-05-27 04:34:02 +00005883CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005884 const char *ea_name, const void *ea_value,
5885 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5886 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887{
5888 struct smb_com_transaction2_spi_req *pSMB = NULL;
5889 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5890 struct fealist *parm_data;
5891 int name_len;
5892 int rc = 0;
5893 int bytes_returned = 0;
5894 __u16 params, param_offset, byte_count, offset, count;
5895
Joe Perchesb6b38f72010-04-21 03:50:45 +00005896 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897SetEARetry:
5898 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5899 (void **) &pSMBr);
5900 if (rc)
5901 return rc;
5902
5903 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5904 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005905 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005906 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907 name_len++; /* trailing null */
5908 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005909 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 name_len = strnlen(fileName, PATH_MAX);
5911 name_len++; /* trailing null */
5912 strncpy(pSMB->FileName, fileName, name_len);
5913 }
5914
5915 params = 6 + name_len;
5916
5917 /* done calculating parms using name_len of file name,
5918 now use name_len to calculate length of ea name
5919 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005920 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005921 name_len = 0;
5922 else
Steve French50c2f752007-07-13 00:33:32 +00005923 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005925 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005927 /* BB find max SMB PDU from sess */
5928 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 pSMB->MaxSetupCount = 0;
5930 pSMB->Reserved = 0;
5931 pSMB->Flags = 0;
5932 pSMB->Timeout = 0;
5933 pSMB->Reserved2 = 0;
5934 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005935 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 offset = param_offset + params;
5937 pSMB->InformationLevel =
5938 cpu_to_le16(SMB_SET_FILE_EA);
5939
5940 parm_data =
5941 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5942 offset);
5943 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5944 pSMB->DataOffset = cpu_to_le16(offset);
5945 pSMB->SetupCount = 1;
5946 pSMB->Reserved3 = 0;
5947 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5948 byte_count = 3 /* pad */ + params + count;
5949 pSMB->DataCount = cpu_to_le16(count);
5950 parm_data->list_len = cpu_to_le32(count);
5951 parm_data->list[0].EA_flags = 0;
5952 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005953 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005954 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005955 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005956 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 parm_data->list[0].name[name_len] = 0;
5958 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5959 /* caller ensures that ea_value_len is less than 64K but
5960 we need to ensure that it fits within the smb */
5961
Steve French50c2f752007-07-13 00:33:32 +00005962 /*BB add length check to see if it would fit in
5963 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005964 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5965 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005966 memcpy(parm_data->list[0].name+name_len+1,
5967 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005968
5969 pSMB->TotalDataCount = pSMB->DataCount;
5970 pSMB->ParameterCount = cpu_to_le16(params);
5971 pSMB->TotalParameterCount = pSMB->ParameterCount;
5972 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005973 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005974 pSMB->ByteCount = cpu_to_le16(byte_count);
5975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005977 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005978 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979
5980 cifs_buf_release(pSMB);
5981
5982 if (rc == -EAGAIN)
5983 goto SetEARetry;
5984
5985 return rc;
5986}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005987#endif
Steve French0eff0e22011-02-24 05:39:23 +00005988
5989#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5990/*
5991 * Years ago the kernel added a "dnotify" function for Samba server,
5992 * to allow network clients (such as Windows) to display updated
5993 * lists of files in directory listings automatically when
5994 * files are added by one user when another user has the
5995 * same directory open on their desktop. The Linux cifs kernel
5996 * client hooked into the kernel side of this interface for
5997 * the same reason, but ironically when the VFS moved from
5998 * "dnotify" to "inotify" it became harder to plug in Linux
5999 * network file system clients (the most obvious use case
6000 * for notify interfaces is when multiple users can update
6001 * the contents of the same directory - exactly what network
6002 * file systems can do) although the server (Samba) could
6003 * still use it. For the short term we leave the worker
6004 * function ifdeffed out (below) until inotify is fixed
6005 * in the VFS to make it easier to plug in network file
6006 * system clients. If inotify turns out to be permanently
6007 * incompatible for network fs clients, we could instead simply
6008 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6009 */
Steve French96daf2b2011-05-27 04:34:02 +00006010int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006011 const int notify_subdirs, const __u16 netfid,
6012 __u32 filter, struct file *pfile, int multishot,
6013 const struct nls_table *nls_codepage)
6014{
6015 int rc = 0;
6016 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6017 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6018 struct dir_notify_req *dnotify_req;
6019 int bytes_returned;
6020
6021 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6022 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6023 (void **) &pSMBr);
6024 if (rc)
6025 return rc;
6026
6027 pSMB->TotalParameterCount = 0 ;
6028 pSMB->TotalDataCount = 0;
6029 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006030 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006031 pSMB->MaxSetupCount = 4;
6032 pSMB->Reserved = 0;
6033 pSMB->ParameterOffset = 0;
6034 pSMB->DataCount = 0;
6035 pSMB->DataOffset = 0;
6036 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6037 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6038 pSMB->ParameterCount = pSMB->TotalParameterCount;
6039 if (notify_subdirs)
6040 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6041 pSMB->Reserved2 = 0;
6042 pSMB->CompletionFilter = cpu_to_le32(filter);
6043 pSMB->Fid = netfid; /* file handle always le */
6044 pSMB->ByteCount = 0;
6045
6046 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6047 (struct smb_hdr *)pSMBr, &bytes_returned,
6048 CIFS_ASYNC_OP);
6049 if (rc) {
6050 cFYI(1, "Error in Notify = %d", rc);
6051 } else {
6052 /* Add file to outstanding requests */
6053 /* BB change to kmem cache alloc */
6054 dnotify_req = kmalloc(
6055 sizeof(struct dir_notify_req),
6056 GFP_KERNEL);
6057 if (dnotify_req) {
6058 dnotify_req->Pid = pSMB->hdr.Pid;
6059 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6060 dnotify_req->Mid = pSMB->hdr.Mid;
6061 dnotify_req->Tid = pSMB->hdr.Tid;
6062 dnotify_req->Uid = pSMB->hdr.Uid;
6063 dnotify_req->netfid = netfid;
6064 dnotify_req->pfile = pfile;
6065 dnotify_req->filter = filter;
6066 dnotify_req->multishot = multishot;
6067 spin_lock(&GlobalMid_Lock);
6068 list_add_tail(&dnotify_req->lhead,
6069 &GlobalDnotifyReqList);
6070 spin_unlock(&GlobalMid_Lock);
6071 } else
6072 rc = -ENOMEM;
6073 }
6074 cifs_buf_release(pSMB);
6075 return rc;
6076}
6077#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */