blob: 1a9fe7f816d1b83dd630141412d3dd109b23a385 [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{
110 int rc = 0;
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 Frencha45443472005-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 Frencha45443472005-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 Frenchb815f1e52006-10-02 05:53:29 +0000442 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000443 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000444
Steve French790fe572007-07-07 19:25:05 +0000445 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000446 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000447 server->secType = LANMAN;
448 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000449 cERROR(1, "mount failed weak security disabled"
450 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000453 }
Steve French96daf2b2011-05-27 04:34:02 +0000454 server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
Steve French254e55e2006-06-04 05:53:15 +0000455 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
456 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000457 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000458 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000459 /* even though we do not use raw we might as well set this
460 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000461 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000462 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000463 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
464 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE;
467 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000468 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000469 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000470 /* OS/2 often does not set timezone therefore
471 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000472 * Could deviate slightly from the right zone.
473 * Smallest defined timezone difference is 15 minutes
474 * (i.e. Nepal). Rounding up/down is done to match
475 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000476 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000477 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000478 struct timespec ts, utc;
479 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400480 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
481 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000482 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000483 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000484 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000485 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000486 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000487 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000489 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000490 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000491 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000492 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000494 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000495 server->timeAdj = (int)tmp;
496 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000497 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000498 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000499
Steve French39798772006-05-31 22:40:51 +0000500
Steve French254e55e2006-06-04 05:53:15 +0000501 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000502 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000503
Steve French50c2f752007-07-13 00:33:32 +0000504 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500506 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000507 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000508 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000509 rc = -EIO; /* need cryptkey unless plain text */
510 goto neg_err_exit;
511 }
Steve French39798772006-05-31 22:40:51 +0000512
Steve Frenchf19159d2010-04-21 04:12:10 +0000513 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000514 /* we will not end up setting signing flags - as no signing
515 was in LANMAN and server did not return the flags on */
516 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000517#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000518 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000519 cERROR(1, "mount failed, cifs module not built "
520 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300521 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000522#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000523 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000524 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000525 /* unknown wct */
526 rc = -EOPNOTSUPP;
527 goto neg_err_exit;
528 }
529 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000530 server->sec_mode = pSMBr->SecurityMode;
531 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000532 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000533
Steve French96daf2b2011-05-27 04:34:02 +0000534 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000535#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000536 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000537#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000538 cERROR(1, "Server requests plain text password"
539 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000540
Steve French790fe572007-07-07 19:25:05 +0000541 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000542 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000543 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000544 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000545 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000546 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000547 else if (secFlags & CIFSSEC_MAY_KRB5)
548 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000549 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000550 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000551 else if (secFlags & CIFSSEC_MAY_LANMAN)
552 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000553 else {
554 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000555 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000556 goto neg_err_exit;
557 }
558 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000559
Steve French254e55e2006-06-04 05:53:15 +0000560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
562 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
563 /* probably no need to store and check maxvcs */
564 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000566 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000567 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000568 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000569 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
570 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000571 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500572 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000573 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000574 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
575 server->capabilities & CAP_EXTENDED_SECURITY) &&
576 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000577 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400578 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000579 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000581 goto neg_err_exit;
582 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530583 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500584 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530585 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000586 if (memcmp(server->server_GUID,
587 pSMBr->u.extended_response.
588 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000589 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000590 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000591 pSMBr->u.extended_response.GUID,
592 16);
593 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500594 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530595 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000596 memcpy(server->server_GUID,
597 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500598 }
Jeff Laytone187e442007-10-16 17:10:44 +0000599
600 if (count == 16) {
601 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000602 } else {
603 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400604 SecurityBlob, count - 16,
605 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000606 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000607 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000608 else
Steve French254e55e2006-06-04 05:53:15 +0000609 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500610 if (server->secType == Kerberos) {
611 if (!server->sec_kerberos &&
612 !server->sec_mskerberos)
613 rc = -EOPNOTSUPP;
614 } else if (server->secType == RawNTLMSSP) {
615 if (!server->sec_ntlmssp)
616 rc = -EOPNOTSUPP;
617 } else
618 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 }
Steve French96daf2b2011-05-27 04:34:02 +0000620 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000621 rc = -EIO; /* no crypt key only if plain text pwd */
622 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000623 } else
624 server->capabilities &= ~CAP_EXTENDED_SECURITY;
625
Steve French6344a422006-06-12 04:18:35 +0000626#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000627signing_check:
Steve French6344a422006-06-12 04:18:35 +0000628#endif
Steve French762e5ab2007-06-28 18:41:42 +0000629 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
630 /* MUST_SIGN already includes the MAY_SIGN FLAG
631 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000632 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000633 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000634 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000635 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000636 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000637 rc = -EOPNOTSUPP;
638 }
Steve French96daf2b2011-05-27 04:34:02 +0000639 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000640 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000641 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
642 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000643 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000644 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000645 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000646 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000647 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000648 } else
Steve French96daf2b2011-05-27 04:34:02 +0000649 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000650 } else {
651 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000652 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
653 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000654 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Steve French50c2f752007-07-13 00:33:32 +0000656
657neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700658 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000659
Joe Perchesb6b38f72010-04-21 03:50:45 +0000660 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 return rc;
662}
663
664int
Steve French96daf2b2011-05-27 04:34:02 +0000665CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
667 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
Joe Perchesb6b38f72010-04-21 03:50:45 +0000670 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500671
672 /* BB: do we need to check this? These should never be NULL. */
673 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
674 return -EIO;
675
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500677 * No need to return error on this operation if tid invalidated and
678 * closed on server already e.g. due to tcp session crashing. Also,
679 * the tcon is no longer on the list, so no need to take lock before
680 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 */
Steve French268875b2009-06-25 00:29:21 +0000682 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Steve French50c2f752007-07-13 00:33:32 +0000685 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700686 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500687 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 return rc;
Steve French133672e2007-11-13 22:41:37 +0000689
690 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000692 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
Steve French50c2f752007-07-13 00:33:32 +0000694 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500695 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (rc == -EAGAIN)
697 rc = 0;
698
699 return rc;
700}
701
Jeff Layton766fdbb2011-01-11 07:24:21 -0500702/*
703 * This is a no-op for now. We're not really interested in the reply, but
704 * rather in the fact that the server sent one and that server->lstrp
705 * gets updated.
706 *
707 * FIXME: maybe we should consider checking that the reply matches request?
708 */
709static void
710cifs_echo_callback(struct mid_q_entry *mid)
711{
712 struct TCP_Server_Info *server = mid->callback_data;
713
714 DeleteMidQEntry(mid);
715 atomic_dec(&server->inFlight);
716 wake_up(&server->request_q);
717}
718
719int
720CIFSSMBEcho(struct TCP_Server_Info *server)
721{
722 ECHO_REQ *smb;
723 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400724 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500725
726 cFYI(1, "In echo request");
727
728 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
729 if (rc)
730 return rc;
731
732 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000733 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500734 smb->hdr.WordCount = 1;
735 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400736 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500737 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000738 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400739 iov.iov_base = smb;
740 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741
Jeff Layton59ffd842011-05-19 16:22:55 -0400742 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500743 if (rc)
744 cFYI(1, "Echo request failed: %d", rc);
745
746 cifs_small_buf_release(smb);
747
748 return rc;
749}
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751int
Steve French96daf2b2011-05-27 04:34:02 +0000752CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 LOGOFF_ANDX_REQ *pSMB;
755 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Joe Perchesb6b38f72010-04-21 03:50:45 +0000757 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500758
759 /*
760 * BB: do we need to check validity of ses and server? They should
761 * always be valid since we have an active reference. If not, that
762 * should probably be a BUG()
763 */
764 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 return -EIO;
766
Steve Frenchd7b619c2010-02-25 05:36:46 +0000767 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000768 if (ses->need_reconnect)
769 goto session_already_dead; /* no need to send SMBlogoff if uid
770 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
772 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000773 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 return rc;
775 }
776
Steve French3b795212008-11-13 19:45:32 +0000777 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700778
Steve French96daf2b2011-05-27 04:34:02 +0000779 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
781 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 pSMB->hdr.Uid = ses->Suid;
784
785 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000786 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000787session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000788 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
790 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000791 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 error */
793 if (rc == -EAGAIN)
794 rc = 0;
795 return rc;
796}
797
798int
Steve French96daf2b2011-05-27 04:34:02 +0000799CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000800 __u16 type, const struct nls_table *nls_codepage, int remap)
801{
802 TRANSACTION2_SPI_REQ *pSMB = NULL;
803 TRANSACTION2_SPI_RSP *pSMBr = NULL;
804 struct unlink_psx_rq *pRqD;
805 int name_len;
806 int rc = 0;
807 int bytes_returned = 0;
808 __u16 params, param_offset, offset, byte_count;
809
Joe Perchesb6b38f72010-04-21 03:50:45 +0000810 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000811PsxDelete:
812 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
813 (void **) &pSMBr);
814 if (rc)
815 return rc;
816
817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
818 name_len =
819 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
820 PATH_MAX, nls_codepage, remap);
821 name_len++; /* trailing null */
822 name_len *= 2;
823 } else { /* BB add path length overrun check */
824 name_len = strnlen(fileName, PATH_MAX);
825 name_len++; /* trailing null */
826 strncpy(pSMB->FileName, fileName, name_len);
827 }
828
829 params = 6 + name_len;
830 pSMB->MaxParameterCount = cpu_to_le16(2);
831 pSMB->MaxDataCount = 0; /* BB double check this with jra */
832 pSMB->MaxSetupCount = 0;
833 pSMB->Reserved = 0;
834 pSMB->Flags = 0;
835 pSMB->Timeout = 0;
836 pSMB->Reserved2 = 0;
837 param_offset = offsetof(struct smb_com_transaction2_spi_req,
838 InformationLevel) - 4;
839 offset = param_offset + params;
840
841 /* Setup pointer to Request Data (inode type) */
842 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
843 pRqD->type = cpu_to_le16(type);
844 pSMB->ParameterOffset = cpu_to_le16(param_offset);
845 pSMB->DataOffset = cpu_to_le16(offset);
846 pSMB->SetupCount = 1;
847 pSMB->Reserved3 = 0;
848 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
849 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
850
851 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
852 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
853 pSMB->ParameterCount = cpu_to_le16(params);
854 pSMB->TotalParameterCount = pSMB->ParameterCount;
855 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
856 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000857 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000858 pSMB->ByteCount = cpu_to_le16(byte_count);
859 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
860 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000861 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000862 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000863 cifs_buf_release(pSMB);
864
865 cifs_stats_inc(&tcon->num_deletes);
866
867 if (rc == -EAGAIN)
868 goto PsxDelete;
869
870 return rc;
871}
872
873int
Steve French96daf2b2011-05-27 04:34:02 +0000874CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700875 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876{
877 DELETE_FILE_REQ *pSMB = NULL;
878 DELETE_FILE_RSP *pSMBr = NULL;
879 int rc = 0;
880 int bytes_returned;
881 int name_len;
882
883DelFileRetry:
884 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
885 (void **) &pSMBr);
886 if (rc)
887 return rc;
888
889 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
890 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000891 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700892 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 name_len++; /* trailing null */
894 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700895 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 name_len = strnlen(fileName, PATH_MAX);
897 name_len++; /* trailing null */
898 strncpy(pSMB->fileName, fileName, name_len);
899 }
900 pSMB->SearchAttributes =
901 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
902 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000903 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 pSMB->ByteCount = cpu_to_le16(name_len + 1);
905 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
906 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700907 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000908 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000909 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 cifs_buf_release(pSMB);
912 if (rc == -EAGAIN)
913 goto DelFileRetry;
914
915 return rc;
916}
917
918int
Steve French96daf2b2011-05-27 04:34:02 +0000919CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700920 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921{
922 DELETE_DIRECTORY_REQ *pSMB = NULL;
923 DELETE_DIRECTORY_RSP *pSMBr = NULL;
924 int rc = 0;
925 int bytes_returned;
926 int name_len;
927
Joe Perchesb6b38f72010-04-21 03:50:45 +0000928 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929RmDirRetry:
930 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
931 (void **) &pSMBr);
932 if (rc)
933 return rc;
934
935 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700936 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
937 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 name_len++; /* trailing null */
939 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700940 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 name_len = strnlen(dirName, PATH_MAX);
942 name_len++; /* trailing null */
943 strncpy(pSMB->DirName, dirName, name_len);
944 }
945
946 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000947 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 pSMB->ByteCount = cpu_to_le16(name_len + 1);
949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
950 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700951 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000952 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000953 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 cifs_buf_release(pSMB);
956 if (rc == -EAGAIN)
957 goto RmDirRetry;
958 return rc;
959}
960
961int
Steve French96daf2b2011-05-27 04:34:02 +0000962CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700963 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
965 int rc = 0;
966 CREATE_DIRECTORY_REQ *pSMB = NULL;
967 CREATE_DIRECTORY_RSP *pSMBr = NULL;
968 int bytes_returned;
969 int name_len;
970
Joe Perchesb6b38f72010-04-21 03:50:45 +0000971 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972MkDirRetry:
973 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
974 (void **) &pSMBr);
975 if (rc)
976 return rc;
977
978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000979 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700980 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 name_len++; /* trailing null */
982 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700983 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 name_len = strnlen(name, PATH_MAX);
985 name_len++; /* trailing null */
986 strncpy(pSMB->DirName, name, name_len);
987 }
988
989 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000990 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 pSMB->ByteCount = cpu_to_le16(name_len + 1);
992 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
993 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700994 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000995 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000996 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700997
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 cifs_buf_release(pSMB);
999 if (rc == -EAGAIN)
1000 goto MkDirRetry;
1001 return rc;
1002}
1003
Steve French2dd29d32007-04-23 22:07:35 +00001004int
Steve French96daf2b2011-05-27 04:34:02 +00001005CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001006 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001007 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001008 const struct nls_table *nls_codepage, int remap)
1009{
1010 TRANSACTION2_SPI_REQ *pSMB = NULL;
1011 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1012 int name_len;
1013 int rc = 0;
1014 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001015 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001016 OPEN_PSX_REQ *pdata;
1017 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001018
Joe Perchesb6b38f72010-04-21 03:50:45 +00001019 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001020PsxCreat:
1021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1022 (void **) &pSMBr);
1023 if (rc)
1024 return rc;
1025
1026 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1027 name_len =
1028 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1029 PATH_MAX, nls_codepage, remap);
1030 name_len++; /* trailing null */
1031 name_len *= 2;
1032 } else { /* BB improve the check for buffer overruns BB */
1033 name_len = strnlen(name, PATH_MAX);
1034 name_len++; /* trailing null */
1035 strncpy(pSMB->FileName, name, name_len);
1036 }
1037
1038 params = 6 + name_len;
1039 count = sizeof(OPEN_PSX_REQ);
1040 pSMB->MaxParameterCount = cpu_to_le16(2);
1041 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1042 pSMB->MaxSetupCount = 0;
1043 pSMB->Reserved = 0;
1044 pSMB->Flags = 0;
1045 pSMB->Timeout = 0;
1046 pSMB->Reserved2 = 0;
1047 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001048 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001049 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001050 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001051 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001052 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001053 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001054 pdata->OpenFlags = cpu_to_le32(*pOplock);
1055 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1056 pSMB->DataOffset = cpu_to_le16(offset);
1057 pSMB->SetupCount = 1;
1058 pSMB->Reserved3 = 0;
1059 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1060 byte_count = 3 /* pad */ + params + count;
1061
1062 pSMB->DataCount = cpu_to_le16(count);
1063 pSMB->ParameterCount = cpu_to_le16(params);
1064 pSMB->TotalDataCount = pSMB->DataCount;
1065 pSMB->TotalParameterCount = pSMB->ParameterCount;
1066 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1067 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001068 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001069 pSMB->ByteCount = cpu_to_le16(byte_count);
1070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1072 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001073 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001074 goto psx_create_err;
1075 }
1076
Joe Perchesb6b38f72010-04-21 03:50:45 +00001077 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001078 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1079
Jeff Layton820a8032011-05-04 08:05:26 -04001080 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001081 rc = -EIO; /* bad smb */
1082 goto psx_create_err;
1083 }
1084
1085 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001086 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001087 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001088
Steve French2dd29d32007-04-23 22:07:35 +00001089 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001090 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001091 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1092 /* Let caller know file was created so we can set the mode. */
1093 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001094 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001095 *pOplock |= CIFS_CREATE_ACTION;
1096 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001097 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1098 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001099 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001100 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001101 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001102 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001103 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001104 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001105 goto psx_create_err;
1106 }
Steve French50c2f752007-07-13 00:33:32 +00001107 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001108 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001109 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001110 }
Steve French2dd29d32007-04-23 22:07:35 +00001111
1112psx_create_err:
1113 cifs_buf_release(pSMB);
1114
Steve French65bc98b2009-07-10 15:27:25 +00001115 if (posix_flags & SMB_O_DIRECTORY)
1116 cifs_stats_inc(&tcon->num_posixmkdirs);
1117 else
1118 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001119
1120 if (rc == -EAGAIN)
1121 goto PsxCreat;
1122
Steve French50c2f752007-07-13 00:33:32 +00001123 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001124}
1125
Steve Frencha9d02ad2005-08-24 23:06:05 -07001126static __u16 convert_disposition(int disposition)
1127{
1128 __u16 ofun = 0;
1129
1130 switch (disposition) {
1131 case FILE_SUPERSEDE:
1132 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1133 break;
1134 case FILE_OPEN:
1135 ofun = SMBOPEN_OAPPEND;
1136 break;
1137 case FILE_CREATE:
1138 ofun = SMBOPEN_OCREATE;
1139 break;
1140 case FILE_OPEN_IF:
1141 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1142 break;
1143 case FILE_OVERWRITE:
1144 ofun = SMBOPEN_OTRUNC;
1145 break;
1146 case FILE_OVERWRITE_IF:
1147 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1148 break;
1149 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001150 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001151 ofun = SMBOPEN_OAPPEND; /* regular open */
1152 }
1153 return ofun;
1154}
1155
Jeff Layton35fc37d2008-05-14 10:22:03 -07001156static int
1157access_flags_to_smbopen_mode(const int access_flags)
1158{
1159 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1160
1161 if (masked_flags == GENERIC_READ)
1162 return SMBOPEN_READ;
1163 else if (masked_flags == GENERIC_WRITE)
1164 return SMBOPEN_WRITE;
1165
1166 /* just go for read/write */
1167 return SMBOPEN_READWRITE;
1168}
1169
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170int
Steve French96daf2b2011-05-27 04:34:02 +00001171SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001172 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001173 const int access_flags, const int create_options, __u16 *netfid,
1174 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175 const struct nls_table *nls_codepage, int remap)
1176{
1177 int rc = -EACCES;
1178 OPENX_REQ *pSMB = NULL;
1179 OPENX_RSP *pSMBr = NULL;
1180 int bytes_returned;
1181 int name_len;
1182 __u16 count;
1183
1184OldOpenRetry:
1185 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1186 (void **) &pSMBr);
1187 if (rc)
1188 return rc;
1189
1190 pSMB->AndXCommand = 0xFF; /* none */
1191
1192 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1193 count = 1; /* account for one byte pad to word boundary */
1194 name_len =
1195 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1196 fileName, PATH_MAX, nls_codepage, remap);
1197 name_len++; /* trailing null */
1198 name_len *= 2;
1199 } else { /* BB improve check for buffer overruns BB */
1200 count = 0; /* no pad */
1201 name_len = strnlen(fileName, PATH_MAX);
1202 name_len++; /* trailing null */
1203 strncpy(pSMB->fileName, fileName, name_len);
1204 }
1205 if (*pOplock & REQ_OPLOCK)
1206 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001207 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001209
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001211 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001212 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1213 /* set file as system file if special file such
1214 as fifo and server expecting SFU style and
1215 no Unix extensions */
1216
Steve French790fe572007-07-07 19:25:05 +00001217 if (create_options & CREATE_OPTION_SPECIAL)
1218 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001219 else /* BB FIXME BB */
1220 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001221
Jeff Layton67750fb2008-05-09 22:28:02 +00001222 if (create_options & CREATE_OPTION_READONLY)
1223 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001224
1225 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001226/* pSMB->CreateOptions = cpu_to_le32(create_options &
1227 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001228 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001229
1230 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001231 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001233 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001234
1235 pSMB->ByteCount = cpu_to_le16(count);
1236 /* long_op set to 1 to allow for oplock break timeouts */
1237 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001238 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239 cifs_stats_inc(&tcon->num_opens);
1240 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001241 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001242 } else {
1243 /* BB verify if wct == 15 */
1244
Steve French582d21e2008-05-13 04:54:12 +00001245/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001246
1247 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1248 /* Let caller know file was created so we can set the mode. */
1249 /* Do we care about the CreateAction in any other cases? */
1250 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001251/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001252 *pOplock |= CIFS_CREATE_ACTION; */
1253 /* BB FIXME END */
1254
Steve French790fe572007-07-07 19:25:05 +00001255 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001256 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1257 pfile_info->LastAccessTime = 0; /* BB fixme */
1258 pfile_info->LastWriteTime = 0; /* BB fixme */
1259 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001260 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001261 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001262 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001263 pfile_info->AllocationSize =
1264 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1265 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001267 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001268 }
1269 }
1270
1271 cifs_buf_release(pSMB);
1272 if (rc == -EAGAIN)
1273 goto OldOpenRetry;
1274 return rc;
1275}
1276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277int
Steve French96daf2b2011-05-27 04:34:02 +00001278CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001280 const int access_flags, const int create_options, __u16 *netfid,
1281 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001282 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283{
1284 int rc = -EACCES;
1285 OPEN_REQ *pSMB = NULL;
1286 OPEN_RSP *pSMBr = NULL;
1287 int bytes_returned;
1288 int name_len;
1289 __u16 count;
1290
1291openRetry:
1292 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1293 (void **) &pSMBr);
1294 if (rc)
1295 return rc;
1296
1297 pSMB->AndXCommand = 0xFF; /* none */
1298
1299 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1300 count = 1; /* account for one byte pad to word boundary */
1301 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001302 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001303 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 name_len++; /* trailing null */
1305 name_len *= 2;
1306 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001307 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 count = 0; /* no pad */
1309 name_len = strnlen(fileName, PATH_MAX);
1310 name_len++; /* trailing null */
1311 pSMB->NameLength = cpu_to_le16(name_len);
1312 strncpy(pSMB->fileName, fileName, name_len);
1313 }
1314 if (*pOplock & REQ_OPLOCK)
1315 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001316 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1319 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001320 /* set file as system file if special file such
1321 as fifo and server expecting SFU style and
1322 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001323 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001324 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1325 else
1326 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001327
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 /* XP does not handle ATTR_POSIX_SEMANTICS */
1329 /* but it helps speed up case sensitive checks for other
1330 servers such as Samba */
1331 if (tcon->ses->capabilities & CAP_UNIX)
1332 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1333
Jeff Layton67750fb2008-05-09 22:28:02 +00001334 if (create_options & CREATE_OPTION_READONLY)
1335 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1336
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1338 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001339 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001340 /* BB Expirement with various impersonation levels and verify */
1341 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 pSMB->SecurityFlags =
1343 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1344
1345 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001346 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
1348 pSMB->ByteCount = cpu_to_le16(count);
1349 /* long_op set to 1 to allow for oplock break timeouts */
1350 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001351 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001352 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001354 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 } else {
Steve French09d1db52005-04-28 22:41:08 -07001356 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1358 /* Let caller know file was created so we can set the mode. */
1359 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001360 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001361 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001362 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001363 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1364 36 /* CreationTime to Attributes */);
1365 /* the file_info buf is endian converted by caller */
1366 pfile_info->AllocationSize = pSMBr->AllocationSize;
1367 pfile_info->EndOfFile = pSMBr->EndOfFile;
1368 pfile_info->NumberOfLinks = cpu_to_le32(1);
1369 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001372
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 cifs_buf_release(pSMB);
1374 if (rc == -EAGAIN)
1375 goto openRetry;
1376 return rc;
1377}
1378
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001380CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001381 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382{
1383 int rc = -EACCES;
1384 READ_REQ *pSMB = NULL;
1385 READ_RSP *pSMBr = NULL;
1386 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001387 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001388 int resp_buf_type = 0;
1389 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001390 __u32 pid = io_parms->pid;
1391 __u16 netfid = io_parms->netfid;
1392 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001393 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001394 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Joe Perchesb6b38f72010-04-21 03:50:45 +00001396 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001397 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001398 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001399 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001400 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001401 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001402 /* can not handle this big offset for old */
1403 return -EIO;
1404 }
1405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
1407 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001408 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 if (rc)
1410 return rc;
1411
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001412 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1413 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1414
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 /* tcon and ses pointer are checked in smb_init */
1416 if (tcon->ses->server == NULL)
1417 return -ECONNABORTED;
1418
Steve Frenchec637e32005-12-12 20:53:18 -08001419 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001421 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001422 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001423 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 pSMB->Remaining = 0;
1426 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1427 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001428 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001429 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1430 else {
1431 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001432 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001434 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001435 }
Steve Frenchec637e32005-12-12 20:53:18 -08001436
1437 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001438 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001439 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001440 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha45443472005-08-24 13:59:35 -07001441 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001442 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001444 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 } else {
1446 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1447 data_length = data_length << 16;
1448 data_length += le16_to_cpu(pSMBr->DataLength);
1449 *nbytes = data_length;
1450
1451 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001452 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001454 cFYI(1, "bad length %d for count %d",
1455 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 rc = -EIO;
1457 *nbytes = 0;
1458 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001459 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001460 le16_to_cpu(pSMBr->DataOffset);
1461/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001462 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001463 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001464 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001465 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001466 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 }
1468 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
Steve French4b8f9302006-02-26 16:41:18 +00001470/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001471 if (*buf) {
1472 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001473 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001474 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001475 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001476 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001477 /* return buffer to caller to free */
1478 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001479 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001480 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001481 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001482 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001483 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001484
1485 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 since file handle passed in no longer valid */
1487 return rc;
1488}
1489
Steve Frenchec637e32005-12-12 20:53:18 -08001490
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001492CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1493 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001494 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495{
1496 int rc = -EACCES;
1497 WRITE_REQ *pSMB = NULL;
1498 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001499 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 __u32 bytes_sent;
1501 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001502 __u32 pid = io_parms->pid;
1503 __u16 netfid = io_parms->netfid;
1504 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001505 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001506 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
Steve Frencha24e2d72010-04-03 17:20:21 +00001508 *nbytes = 0;
1509
Joe Perchesb6b38f72010-04-21 03:50:45 +00001510 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001511 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001512 return -ECONNABORTED;
1513
Steve French790fe572007-07-07 19:25:05 +00001514 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001515 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001516 else {
Steve French1c955182005-08-30 20:58:07 -07001517 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001518 if ((offset >> 32) > 0) {
1519 /* can not handle big offset for old srv */
1520 return -EIO;
1521 }
1522 }
Steve French1c955182005-08-30 20:58:07 -07001523
1524 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 (void **) &pSMBr);
1526 if (rc)
1527 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001528
1529 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1530 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1531
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 /* tcon and ses pointer are checked in smb_init */
1533 if (tcon->ses->server == NULL)
1534 return -ECONNABORTED;
1535
1536 pSMB->AndXCommand = 0xFF; /* none */
1537 pSMB->Fid = netfid;
1538 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001539 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001540 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001541
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 pSMB->Reserved = 0xFFFFFFFF;
1543 pSMB->WriteMode = 0;
1544 pSMB->Remaining = 0;
1545
Steve French50c2f752007-07-13 00:33:32 +00001546 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 can send more if LARGE_WRITE_X capability returned by the server and if
1548 our buffer is big enough or if we convert to iovecs on socket writes
1549 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001550 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1552 } else {
1553 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1554 & ~0xFF;
1555 }
1556
1557 if (bytes_sent > count)
1558 bytes_sent = count;
1559 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001560 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001561 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001562 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001563 else if (ubuf) {
1564 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 cifs_buf_release(pSMB);
1566 return -EFAULT;
1567 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001568 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 /* No buffer */
1570 cifs_buf_release(pSMB);
1571 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001572 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001573 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001574 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001575 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001576 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001577
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1579 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001580 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001581
Steve French790fe572007-07-07 19:25:05 +00001582 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001583 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001584 else { /* old style write has byte count 4 bytes earlier
1585 so 4 bytes pad */
1586 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001587 (struct smb_com_writex_req *)pSMB;
1588 pSMBW->ByteCount = cpu_to_le16(byte_count);
1589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
1591 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1592 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001593 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001595 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 } else {
1597 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1598 *nbytes = (*nbytes) << 16;
1599 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301600
1601 /*
1602 * Mask off high 16 bits when bytes written as returned by the
1603 * server is greater than bytes requested by the client. Some
1604 * OS/2 servers are known to set incorrect CountHigh values.
1605 */
1606 if (*nbytes > count)
1607 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 }
1609
1610 cifs_buf_release(pSMB);
1611
Steve French50c2f752007-07-13 00:33:32 +00001612 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 since file handle passed in no longer valid */
1614
1615 return rc;
1616}
1617
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001618void
1619cifs_writedata_release(struct kref *refcount)
1620{
1621 struct cifs_writedata *wdata = container_of(refcount,
1622 struct cifs_writedata, refcount);
1623
1624 if (wdata->cfile)
1625 cifsFileInfo_put(wdata->cfile);
1626
1627 kfree(wdata);
1628}
1629
1630/*
1631 * Write failed with a retryable error. Resend the write request. It's also
1632 * possible that the page was redirtied so re-clean the page.
1633 */
1634static void
1635cifs_writev_requeue(struct cifs_writedata *wdata)
1636{
1637 int i, rc;
1638 struct inode *inode = wdata->cfile->dentry->d_inode;
1639
1640 for (i = 0; i < wdata->nr_pages; i++) {
1641 lock_page(wdata->pages[i]);
1642 clear_page_dirty_for_io(wdata->pages[i]);
1643 }
1644
1645 do {
1646 rc = cifs_async_writev(wdata);
1647 } while (rc == -EAGAIN);
1648
1649 for (i = 0; i < wdata->nr_pages; i++) {
1650 if (rc != 0)
1651 SetPageError(wdata->pages[i]);
1652 unlock_page(wdata->pages[i]);
1653 }
1654
1655 mapping_set_error(inode->i_mapping, rc);
1656 kref_put(&wdata->refcount, cifs_writedata_release);
1657}
1658
1659static void
1660cifs_writev_complete(struct work_struct *work)
1661{
1662 struct cifs_writedata *wdata = container_of(work,
1663 struct cifs_writedata, work);
1664 struct inode *inode = wdata->cfile->dentry->d_inode;
1665 int i = 0;
1666
1667 if (wdata->result == 0) {
1668 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1669 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1670 wdata->bytes);
1671 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1672 return cifs_writev_requeue(wdata);
1673
1674 for (i = 0; i < wdata->nr_pages; i++) {
1675 struct page *page = wdata->pages[i];
1676 if (wdata->result == -EAGAIN)
1677 __set_page_dirty_nobuffers(page);
1678 else if (wdata->result < 0)
1679 SetPageError(page);
1680 end_page_writeback(page);
1681 page_cache_release(page);
1682 }
1683 if (wdata->result != -EAGAIN)
1684 mapping_set_error(inode->i_mapping, wdata->result);
1685 kref_put(&wdata->refcount, cifs_writedata_release);
1686}
1687
1688struct cifs_writedata *
1689cifs_writedata_alloc(unsigned int nr_pages)
1690{
1691 struct cifs_writedata *wdata;
1692
1693 /* this would overflow */
1694 if (nr_pages == 0) {
1695 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1696 return NULL;
1697 }
1698
1699 /* writedata + number of page pointers */
1700 wdata = kzalloc(sizeof(*wdata) +
1701 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1702 if (wdata != NULL) {
1703 INIT_WORK(&wdata->work, cifs_writev_complete);
1704 kref_init(&wdata->refcount);
1705 }
1706 return wdata;
1707}
1708
1709/*
1710 * Check the midState and signature on received buffer (if any), and queue the
1711 * workqueue completion task.
1712 */
1713static void
1714cifs_writev_callback(struct mid_q_entry *mid)
1715{
1716 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001717 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001718 unsigned int written;
1719 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1720
1721 switch (mid->midState) {
1722 case MID_RESPONSE_RECEIVED:
1723 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1724 if (wdata->result != 0)
1725 break;
1726
1727 written = le16_to_cpu(smb->CountHigh);
1728 written <<= 16;
1729 written += le16_to_cpu(smb->Count);
1730 /*
1731 * Mask off high 16 bits when bytes written as returned
1732 * by the server is greater than bytes requested by the
1733 * client. OS/2 servers are known to set incorrect
1734 * CountHigh values.
1735 */
1736 if (written > wdata->bytes)
1737 written &= 0xFFFF;
1738
1739 if (written < wdata->bytes)
1740 wdata->result = -ENOSPC;
1741 else
1742 wdata->bytes = written;
1743 break;
1744 case MID_REQUEST_SUBMITTED:
1745 case MID_RETRY_NEEDED:
1746 wdata->result = -EAGAIN;
1747 break;
1748 default:
1749 wdata->result = -EIO;
1750 break;
1751 }
1752
1753 queue_work(system_nrt_wq, &wdata->work);
1754 DeleteMidQEntry(mid);
1755 atomic_dec(&tcon->ses->server->inFlight);
1756 wake_up(&tcon->ses->server->request_q);
1757}
1758
1759/* cifs_async_writev - send an async write, and set up mid to handle result */
1760int
1761cifs_async_writev(struct cifs_writedata *wdata)
1762{
1763 int i, rc = -EACCES;
1764 WRITE_REQ *smb = NULL;
1765 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00001766 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001767 struct inode *inode = wdata->cfile->dentry->d_inode;
1768 struct kvec *iov = NULL;
1769
1770 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1771 wct = 14;
1772 } else {
1773 wct = 12;
1774 if (wdata->offset >> 32 > 0) {
1775 /* can not handle big offset for old srv */
1776 return -EIO;
1777 }
1778 }
1779
1780 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
1781 if (rc)
1782 goto async_writev_out;
1783
1784 /* 1 iov per page + 1 for header */
1785 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
1786 if (iov == NULL) {
1787 rc = -ENOMEM;
1788 goto async_writev_out;
1789 }
1790
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001791 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
1792 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
1793
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001794 smb->AndXCommand = 0xFF; /* none */
1795 smb->Fid = wdata->cfile->netfid;
1796 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
1797 if (wct == 14)
1798 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
1799 smb->Reserved = 0xFFFFFFFF;
1800 smb->WriteMode = 0;
1801 smb->Remaining = 0;
1802
1803 smb->DataOffset =
1804 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1805
1806 /* 4 for RFC1001 length + 1 for BCC */
1807 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
1808 iov[0].iov_base = smb;
1809
1810 /* marshal up the pages into iov array */
1811 wdata->bytes = 0;
1812 for (i = 0; i < wdata->nr_pages; i++) {
1813 iov[i + 1].iov_len = min(inode->i_size -
1814 page_offset(wdata->pages[i]),
1815 (loff_t)PAGE_CACHE_SIZE);
1816 iov[i + 1].iov_base = kmap(wdata->pages[i]);
1817 wdata->bytes += iov[i + 1].iov_len;
1818 }
1819
1820 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
1821
1822 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
1823 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
1824
1825 if (wct == 14) {
1826 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
1827 put_bcc(wdata->bytes + 1, &smb->hdr);
1828 } else {
1829 /* wct == 12 */
1830 struct smb_com_writex_req *smbw =
1831 (struct smb_com_writex_req *)smb;
1832 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
1833 put_bcc(wdata->bytes + 5, &smbw->hdr);
1834 iov[0].iov_len += 4; /* pad bigger by four bytes */
1835 }
1836
1837 kref_get(&wdata->refcount);
1838 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
1839 cifs_writev_callback, wdata, false);
1840
1841 if (rc == 0)
1842 cifs_stats_inc(&tcon->num_writes);
1843 else
1844 kref_put(&wdata->refcount, cifs_writedata_release);
1845
1846 /* send is done, unmap pages */
1847 for (i = 0; i < wdata->nr_pages; i++)
1848 kunmap(wdata->pages[i]);
1849
1850async_writev_out:
1851 cifs_small_buf_release(smb);
1852 kfree(iov);
1853 return rc;
1854}
1855
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001856int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001857CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
1858 unsigned int *nbytes, struct kvec *iov, int n_vec,
1859 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860{
1861 int rc = -EACCES;
1862 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001863 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001864 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001865 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001866 __u32 pid = io_parms->pid;
1867 __u16 netfid = io_parms->netfid;
1868 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001869 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001870 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001872 *nbytes = 0;
1873
Joe Perchesb6b38f72010-04-21 03:50:45 +00001874 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001875
Steve French4c3130e2008-12-09 00:28:16 +00001876 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001877 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001878 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001879 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001880 if ((offset >> 32) > 0) {
1881 /* can not handle big offset for old srv */
1882 return -EIO;
1883 }
1884 }
Steve French8cc64c62005-10-03 13:49:43 -07001885 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 if (rc)
1887 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001888
1889 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1890 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1891
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 /* tcon and ses pointer are checked in smb_init */
1893 if (tcon->ses->server == NULL)
1894 return -ECONNABORTED;
1895
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001896 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 pSMB->Fid = netfid;
1898 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001899 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001900 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 pSMB->Reserved = 0xFFFFFFFF;
1902 pSMB->WriteMode = 0;
1903 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001904
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001906 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
Steve French3e844692005-10-03 13:37:24 -07001908 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1909 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001910 /* header + 1 byte pad */
1911 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001912 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001913 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001914 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001915 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001916 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001917 pSMB->ByteCount = cpu_to_le16(count + 1);
1918 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001919 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001920 (struct smb_com_writex_req *)pSMB;
1921 pSMBW->ByteCount = cpu_to_le16(count + 5);
1922 }
Steve French3e844692005-10-03 13:37:24 -07001923 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001924 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001925 iov[0].iov_len = smb_hdr_len + 4;
1926 else /* wct == 12 pad bigger by four bytes */
1927 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001928
Steve French3e844692005-10-03 13:37:24 -07001929
Steve Frenchec637e32005-12-12 20:53:18 -08001930 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001931 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001932 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001934 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001935 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001936 /* presumably this can not happen, but best to be safe */
1937 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001938 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001939 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001940 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1941 *nbytes = (*nbytes) << 16;
1942 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301943
1944 /*
1945 * Mask off high 16 bits when bytes written as returned by the
1946 * server is greater than bytes requested by the client. OS/2
1947 * servers are known to set incorrect CountHigh values.
1948 */
1949 if (*nbytes > count)
1950 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Steve French4b8f9302006-02-26 16:41:18 +00001953/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001954 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001955 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001956 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001957 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
Steve French50c2f752007-07-13 00:33:32 +00001959 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 since file handle passed in no longer valid */
1961
1962 return rc;
1963}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001964
1965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966int
Steve French96daf2b2011-05-27 04:34:02 +00001967CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 const __u16 smb_file_id, const __u64 len,
1969 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001970 const __u32 numLock, const __u8 lockType,
1971 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972{
1973 int rc = 0;
1974 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001975/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 int bytes_returned;
1977 int timeout = 0;
1978 __u16 count;
1979
Joe Perchesb6b38f72010-04-21 03:50:45 +00001980 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001981 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1982
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 if (rc)
1984 return rc;
1985
Steve French790fe572007-07-07 19:25:05 +00001986 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001987 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001989 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001990 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1992 } else {
1993 pSMB->Timeout = 0;
1994 }
1995
1996 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1997 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1998 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001999 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 pSMB->AndXCommand = 0xFF; /* none */
2001 pSMB->Fid = smb_file_id; /* netfid stays le */
2002
Steve French790fe572007-07-07 19:25:05 +00002003 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
2005 /* BB where to store pid high? */
2006 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2007 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2008 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2009 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2010 count = sizeof(LOCKING_ANDX_RANGE);
2011 } else {
2012 /* oplock break */
2013 count = 0;
2014 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002015 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 pSMB->ByteCount = cpu_to_le16(count);
2017
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002018 if (waitFlag) {
2019 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002020 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002021 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002022 } else {
Steve French133672e2007-11-13 22:41:37 +00002023 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2024 timeout);
2025 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002026 }
Steve Frencha45443472005-08-24 13:59:35 -07002027 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002028 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002029 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Steve French50c2f752007-07-13 00:33:32 +00002031 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 since file handle passed in no longer valid */
2033 return rc;
2034}
2035
2036int
Steve French96daf2b2011-05-27 04:34:02 +00002037CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Steve French08547b02006-02-28 22:39:25 +00002038 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00002039 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00002040 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002041{
2042 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2043 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002044 struct cifs_posix_lock *parm_data;
2045 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002046 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002047 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002048 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002049 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002050 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002051
Joe Perchesb6b38f72010-04-21 03:50:45 +00002052 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002053
Steve French790fe572007-07-07 19:25:05 +00002054 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002055 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002056
Steve French08547b02006-02-28 22:39:25 +00002057 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2058
2059 if (rc)
2060 return rc;
2061
2062 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2063
Steve French50c2f752007-07-13 00:33:32 +00002064 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002065 pSMB->MaxSetupCount = 0;
2066 pSMB->Reserved = 0;
2067 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002068 pSMB->Reserved2 = 0;
2069 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2070 offset = param_offset + params;
2071
Steve French08547b02006-02-28 22:39:25 +00002072 count = sizeof(struct cifs_posix_lock);
2073 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002074 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002075 pSMB->SetupCount = 1;
2076 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002077 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002078 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2079 else
2080 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2081 byte_count = 3 /* pad */ + params + count;
2082 pSMB->DataCount = cpu_to_le16(count);
2083 pSMB->ParameterCount = cpu_to_le16(params);
2084 pSMB->TotalDataCount = pSMB->DataCount;
2085 pSMB->TotalParameterCount = pSMB->ParameterCount;
2086 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002087 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002088 (((char *) &pSMB->hdr.Protocol) + offset);
2089
2090 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002091 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002092 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002093 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002094 pSMB->Timeout = cpu_to_le32(-1);
2095 } else
2096 pSMB->Timeout = 0;
2097
Steve French08547b02006-02-28 22:39:25 +00002098 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002099 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002100 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002101
2102 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002103 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002104 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2105 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002106 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002107 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002108 if (waitFlag) {
2109 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2110 (struct smb_hdr *) pSMBr, &bytes_returned);
2111 } else {
Steve French133672e2007-11-13 22:41:37 +00002112 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002113 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002114 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2115 &resp_buf_type, timeout);
2116 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2117 not try to free it twice below on exit */
2118 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002119 }
2120
Steve French08547b02006-02-28 22:39:25 +00002121 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002122 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002123 } else if (get_flag) {
2124 /* lock structure can be returned on get */
2125 __u16 data_offset;
2126 __u16 data_count;
2127 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002128
Jeff Layton820a8032011-05-04 08:05:26 -04002129 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002130 rc = -EIO; /* bad smb */
2131 goto plk_err_exit;
2132 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002133 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2134 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002135 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002136 rc = -EIO;
2137 goto plk_err_exit;
2138 }
2139 parm_data = (struct cifs_posix_lock *)
2140 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002141 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002142 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002143 else {
2144 if (parm_data->lock_type ==
2145 __constant_cpu_to_le16(CIFS_RDLCK))
2146 pLockData->fl_type = F_RDLCK;
2147 else if (parm_data->lock_type ==
2148 __constant_cpu_to_le16(CIFS_WRLCK))
2149 pLockData->fl_type = F_WRLCK;
2150
Steve French5443d132011-03-13 05:08:25 +00002151 pLockData->fl_start = le64_to_cpu(parm_data->start);
2152 pLockData->fl_end = pLockData->fl_start +
2153 le64_to_cpu(parm_data->length) - 1;
2154 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002155 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002156 }
Steve French50c2f752007-07-13 00:33:32 +00002157
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002158plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002159 if (pSMB)
2160 cifs_small_buf_release(pSMB);
2161
Steve French133672e2007-11-13 22:41:37 +00002162 if (resp_buf_type == CIFS_SMALL_BUFFER)
2163 cifs_small_buf_release(iov[0].iov_base);
2164 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2165 cifs_buf_release(iov[0].iov_base);
2166
Steve French08547b02006-02-28 22:39:25 +00002167 /* Note: On -EAGAIN error only caller can retry on handle based calls
2168 since file handle passed in no longer valid */
2169
2170 return rc;
2171}
2172
2173
2174int
Steve French96daf2b2011-05-27 04:34:02 +00002175CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176{
2177 int rc = 0;
2178 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002179 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180
2181/* do not retry on dead session on close */
2182 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002183 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 return 0;
2185 if (rc)
2186 return rc;
2187
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002189 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002191 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002192 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002194 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002196 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 }
2198 }
2199
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002201 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 rc = 0;
2203
2204 return rc;
2205}
2206
2207int
Steve French96daf2b2011-05-27 04:34:02 +00002208CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002209{
2210 int rc = 0;
2211 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002212 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002213
2214 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2215 if (rc)
2216 return rc;
2217
2218 pSMB->FileID = (__u16) smb_file_id;
2219 pSMB->ByteCount = 0;
2220 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2221 cifs_stats_inc(&tcon->num_flushes);
2222 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002223 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002224
2225 return rc;
2226}
2227
2228int
Steve French96daf2b2011-05-27 04:34:02 +00002229CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002231 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232{
2233 int rc = 0;
2234 RENAME_REQ *pSMB = NULL;
2235 RENAME_RSP *pSMBr = NULL;
2236 int bytes_returned;
2237 int name_len, name_len2;
2238 __u16 count;
2239
Joe Perchesb6b38f72010-04-21 03:50:45 +00002240 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241renameRetry:
2242 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2243 (void **) &pSMBr);
2244 if (rc)
2245 return rc;
2246
2247 pSMB->BufferFormat = 0x04;
2248 pSMB->SearchAttributes =
2249 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2250 ATTR_DIRECTORY);
2251
2252 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2253 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002254 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002255 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 name_len++; /* trailing null */
2257 name_len *= 2;
2258 pSMB->OldFileName[name_len] = 0x04; /* pad */
2259 /* protocol requires ASCII signature byte on Unicode string */
2260 pSMB->OldFileName[name_len + 1] = 0x00;
2261 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002262 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002263 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2265 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002266 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 name_len = strnlen(fromName, PATH_MAX);
2268 name_len++; /* trailing null */
2269 strncpy(pSMB->OldFileName, fromName, name_len);
2270 name_len2 = strnlen(toName, PATH_MAX);
2271 name_len2++; /* trailing null */
2272 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2273 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2274 name_len2++; /* trailing null */
2275 name_len2++; /* signature byte */
2276 }
2277
2278 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002279 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 pSMB->ByteCount = cpu_to_le16(count);
2281
2282 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2283 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002284 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002285 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002286 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 cifs_buf_release(pSMB);
2289
2290 if (rc == -EAGAIN)
2291 goto renameRetry;
2292
2293 return rc;
2294}
2295
Steve French96daf2b2011-05-27 04:34:02 +00002296int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002297 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002298 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299{
2300 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2301 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002302 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 char *data_offset;
2304 char dummy_string[30];
2305 int rc = 0;
2306 int bytes_returned = 0;
2307 int len_of_str;
2308 __u16 params, param_offset, offset, count, byte_count;
2309
Joe Perchesb6b38f72010-04-21 03:50:45 +00002310 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2312 (void **) &pSMBr);
2313 if (rc)
2314 return rc;
2315
2316 params = 6;
2317 pSMB->MaxSetupCount = 0;
2318 pSMB->Reserved = 0;
2319 pSMB->Flags = 0;
2320 pSMB->Timeout = 0;
2321 pSMB->Reserved2 = 0;
2322 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2323 offset = param_offset + params;
2324
2325 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2326 rename_info = (struct set_file_rename *) data_offset;
2327 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002328 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 pSMB->SetupCount = 1;
2330 pSMB->Reserved3 = 0;
2331 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2332 byte_count = 3 /* pad */ + params;
2333 pSMB->ParameterCount = cpu_to_le16(params);
2334 pSMB->TotalParameterCount = pSMB->ParameterCount;
2335 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2336 pSMB->DataOffset = cpu_to_le16(offset);
2337 /* construct random name ".cifs_tmp<inodenum><mid>" */
2338 rename_info->overwrite = cpu_to_le32(1);
2339 rename_info->root_fid = 0;
2340 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002341 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002342 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2343 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002344 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002346 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002347 target_name, PATH_MAX, nls_codepage,
2348 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 }
2350 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002351 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 byte_count += count;
2353 pSMB->DataCount = cpu_to_le16(count);
2354 pSMB->TotalDataCount = pSMB->DataCount;
2355 pSMB->Fid = netfid;
2356 pSMB->InformationLevel =
2357 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2358 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002359 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 pSMB->ByteCount = cpu_to_le16(byte_count);
2361 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002362 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002363 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002364 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002365 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002366
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 cifs_buf_release(pSMB);
2368
2369 /* Note: On -EAGAIN error only caller can retry on handle based calls
2370 since file handle passed in no longer valid */
2371
2372 return rc;
2373}
2374
2375int
Steve French96daf2b2011-05-27 04:34:02 +00002376CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002377 const __u16 target_tid, const char *toName, const int flags,
2378 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379{
2380 int rc = 0;
2381 COPY_REQ *pSMB = NULL;
2382 COPY_RSP *pSMBr = NULL;
2383 int bytes_returned;
2384 int name_len, name_len2;
2385 __u16 count;
2386
Joe Perchesb6b38f72010-04-21 03:50:45 +00002387 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388copyRetry:
2389 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2390 (void **) &pSMBr);
2391 if (rc)
2392 return rc;
2393
2394 pSMB->BufferFormat = 0x04;
2395 pSMB->Tid2 = target_tid;
2396
2397 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2398
2399 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002400 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002401 fromName, PATH_MAX, nls_codepage,
2402 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002403 name_len++; /* trailing null */
2404 name_len *= 2;
2405 pSMB->OldFileName[name_len] = 0x04; /* pad */
2406 /* protocol requires ASCII signature byte on Unicode string */
2407 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002408 name_len2 =
2409 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002410 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2412 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002413 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 name_len = strnlen(fromName, PATH_MAX);
2415 name_len++; /* trailing null */
2416 strncpy(pSMB->OldFileName, fromName, name_len);
2417 name_len2 = strnlen(toName, PATH_MAX);
2418 name_len2++; /* trailing null */
2419 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2420 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2421 name_len2++; /* trailing null */
2422 name_len2++; /* signature byte */
2423 }
2424
2425 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002426 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 pSMB->ByteCount = cpu_to_le16(count);
2428
2429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2431 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002432 cFYI(1, "Send error in copy = %d with %d files copied",
2433 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 }
Steve French0d817bc2008-05-22 02:02:03 +00002435 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436
2437 if (rc == -EAGAIN)
2438 goto copyRetry;
2439
2440 return rc;
2441}
2442
2443int
Steve French96daf2b2011-05-27 04:34:02 +00002444CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 const char *fromName, const char *toName,
2446 const struct nls_table *nls_codepage)
2447{
2448 TRANSACTION2_SPI_REQ *pSMB = NULL;
2449 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2450 char *data_offset;
2451 int name_len;
2452 int name_len_target;
2453 int rc = 0;
2454 int bytes_returned = 0;
2455 __u16 params, param_offset, offset, byte_count;
2456
Joe Perchesb6b38f72010-04-21 03:50:45 +00002457 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458createSymLinkRetry:
2459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2460 (void **) &pSMBr);
2461 if (rc)
2462 return rc;
2463
2464 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2465 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002466 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 /* find define for this maxpathcomponent */
2468 , nls_codepage);
2469 name_len++; /* trailing null */
2470 name_len *= 2;
2471
Steve French50c2f752007-07-13 00:33:32 +00002472 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 name_len = strnlen(fromName, PATH_MAX);
2474 name_len++; /* trailing null */
2475 strncpy(pSMB->FileName, fromName, name_len);
2476 }
2477 params = 6 + name_len;
2478 pSMB->MaxSetupCount = 0;
2479 pSMB->Reserved = 0;
2480 pSMB->Flags = 0;
2481 pSMB->Timeout = 0;
2482 pSMB->Reserved2 = 0;
2483 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002484 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 offset = param_offset + params;
2486
2487 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2488 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2489 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002490 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 /* find define for this maxpathcomponent */
2492 , nls_codepage);
2493 name_len_target++; /* trailing null */
2494 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002495 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 name_len_target = strnlen(toName, PATH_MAX);
2497 name_len_target++; /* trailing null */
2498 strncpy(data_offset, toName, name_len_target);
2499 }
2500
2501 pSMB->MaxParameterCount = cpu_to_le16(2);
2502 /* BB find exact max on data count below from sess */
2503 pSMB->MaxDataCount = cpu_to_le16(1000);
2504 pSMB->SetupCount = 1;
2505 pSMB->Reserved3 = 0;
2506 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2507 byte_count = 3 /* pad */ + params + name_len_target;
2508 pSMB->DataCount = cpu_to_le16(name_len_target);
2509 pSMB->ParameterCount = cpu_to_le16(params);
2510 pSMB->TotalDataCount = pSMB->DataCount;
2511 pSMB->TotalParameterCount = pSMB->ParameterCount;
2512 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2513 pSMB->DataOffset = cpu_to_le16(offset);
2514 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2515 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002516 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 pSMB->ByteCount = cpu_to_le16(byte_count);
2518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2519 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002520 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002521 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002522 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
Steve French0d817bc2008-05-22 02:02:03 +00002524 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
2526 if (rc == -EAGAIN)
2527 goto createSymLinkRetry;
2528
2529 return rc;
2530}
2531
2532int
Steve French96daf2b2011-05-27 04:34:02 +00002533CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002535 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
2537 TRANSACTION2_SPI_REQ *pSMB = NULL;
2538 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2539 char *data_offset;
2540 int name_len;
2541 int name_len_target;
2542 int rc = 0;
2543 int bytes_returned = 0;
2544 __u16 params, param_offset, offset, byte_count;
2545
Joe Perchesb6b38f72010-04-21 03:50:45 +00002546 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547createHardLinkRetry:
2548 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2549 (void **) &pSMBr);
2550 if (rc)
2551 return rc;
2552
2553 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002554 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002555 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 name_len++; /* trailing null */
2557 name_len *= 2;
2558
Steve French50c2f752007-07-13 00:33:32 +00002559 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 name_len = strnlen(toName, PATH_MAX);
2561 name_len++; /* trailing null */
2562 strncpy(pSMB->FileName, toName, name_len);
2563 }
2564 params = 6 + name_len;
2565 pSMB->MaxSetupCount = 0;
2566 pSMB->Reserved = 0;
2567 pSMB->Flags = 0;
2568 pSMB->Timeout = 0;
2569 pSMB->Reserved2 = 0;
2570 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002571 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 offset = param_offset + params;
2573
2574 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2575 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2576 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002577 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002578 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 name_len_target++; /* trailing null */
2580 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002581 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 name_len_target = strnlen(fromName, PATH_MAX);
2583 name_len_target++; /* trailing null */
2584 strncpy(data_offset, fromName, name_len_target);
2585 }
2586
2587 pSMB->MaxParameterCount = cpu_to_le16(2);
2588 /* BB find exact max on data count below from sess*/
2589 pSMB->MaxDataCount = cpu_to_le16(1000);
2590 pSMB->SetupCount = 1;
2591 pSMB->Reserved3 = 0;
2592 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2593 byte_count = 3 /* pad */ + params + name_len_target;
2594 pSMB->ParameterCount = cpu_to_le16(params);
2595 pSMB->TotalParameterCount = pSMB->ParameterCount;
2596 pSMB->DataCount = cpu_to_le16(name_len_target);
2597 pSMB->TotalDataCount = pSMB->DataCount;
2598 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2599 pSMB->DataOffset = cpu_to_le16(offset);
2600 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2601 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002602 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 pSMB->ByteCount = cpu_to_le16(byte_count);
2604 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2605 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002606 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002607 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002608 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
2610 cifs_buf_release(pSMB);
2611 if (rc == -EAGAIN)
2612 goto createHardLinkRetry;
2613
2614 return rc;
2615}
2616
2617int
Steve French96daf2b2011-05-27 04:34:02 +00002618CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002620 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621{
2622 int rc = 0;
2623 NT_RENAME_REQ *pSMB = NULL;
2624 RENAME_RSP *pSMBr = NULL;
2625 int bytes_returned;
2626 int name_len, name_len2;
2627 __u16 count;
2628
Joe Perchesb6b38f72010-04-21 03:50:45 +00002629 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630winCreateHardLinkRetry:
2631
2632 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2633 (void **) &pSMBr);
2634 if (rc)
2635 return rc;
2636
2637 pSMB->SearchAttributes =
2638 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2639 ATTR_DIRECTORY);
2640 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2641 pSMB->ClusterCount = 0;
2642
2643 pSMB->BufferFormat = 0x04;
2644
2645 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2646 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002647 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002648 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 name_len++; /* trailing null */
2650 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002651
2652 /* protocol specifies ASCII buffer format (0x04) for unicode */
2653 pSMB->OldFileName[name_len] = 0x04;
2654 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002656 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002657 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2659 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002660 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 name_len = strnlen(fromName, PATH_MAX);
2662 name_len++; /* trailing null */
2663 strncpy(pSMB->OldFileName, fromName, name_len);
2664 name_len2 = strnlen(toName, PATH_MAX);
2665 name_len2++; /* trailing null */
2666 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2667 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2668 name_len2++; /* trailing null */
2669 name_len2++; /* signature byte */
2670 }
2671
2672 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002673 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 pSMB->ByteCount = cpu_to_le16(count);
2675
2676 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002678 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002679 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002680 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 cifs_buf_release(pSMB);
2683 if (rc == -EAGAIN)
2684 goto winCreateHardLinkRetry;
2685
2686 return rc;
2687}
2688
2689int
Steve French96daf2b2011-05-27 04:34:02 +00002690CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002691 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 const struct nls_table *nls_codepage)
2693{
2694/* SMB_QUERY_FILE_UNIX_LINK */
2695 TRANSACTION2_QPI_REQ *pSMB = NULL;
2696 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2697 int rc = 0;
2698 int bytes_returned;
2699 int name_len;
2700 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002701 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Joe Perchesb6b38f72010-04-21 03:50:45 +00002703 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705querySymLinkRetry:
2706 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2707 (void **) &pSMBr);
2708 if (rc)
2709 return rc;
2710
2711 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2712 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002713 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2714 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 name_len++; /* trailing null */
2716 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002717 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 name_len = strnlen(searchName, PATH_MAX);
2719 name_len++; /* trailing null */
2720 strncpy(pSMB->FileName, searchName, name_len);
2721 }
2722
2723 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2724 pSMB->TotalDataCount = 0;
2725 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002726 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 pSMB->MaxSetupCount = 0;
2728 pSMB->Reserved = 0;
2729 pSMB->Flags = 0;
2730 pSMB->Timeout = 0;
2731 pSMB->Reserved2 = 0;
2732 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002733 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 pSMB->DataCount = 0;
2735 pSMB->DataOffset = 0;
2736 pSMB->SetupCount = 1;
2737 pSMB->Reserved3 = 0;
2738 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2739 byte_count = params + 1 /* pad */ ;
2740 pSMB->TotalParameterCount = cpu_to_le16(params);
2741 pSMB->ParameterCount = pSMB->TotalParameterCount;
2742 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2743 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002744 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 pSMB->ByteCount = cpu_to_le16(byte_count);
2746
2747 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2748 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2749 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002750 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 } else {
2752 /* decode response */
2753
2754 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002756 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002757 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002759 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002760 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761
Jeff Layton460b9692009-04-30 07:17:56 -04002762 data_start = ((char *) &pSMBr->hdr.Protocol) +
2763 le16_to_cpu(pSMBr->t2.DataOffset);
2764
Steve French0e0d2cf2009-05-01 05:27:32 +00002765 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2766 is_unicode = true;
2767 else
2768 is_unicode = false;
2769
Steve French737b7582005-04-28 22:41:06 -07002770 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002771 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002772 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002773 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002774 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 }
2776 }
2777 cifs_buf_release(pSMB);
2778 if (rc == -EAGAIN)
2779 goto querySymLinkRetry;
2780 return rc;
2781}
2782
Steve Frenchc52a95542011-02-24 06:16:22 +00002783#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2784/*
2785 * Recent Windows versions now create symlinks more frequently
2786 * and they use the "reparse point" mechanism below. We can of course
2787 * do symlinks nicely to Samba and other servers which support the
2788 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2789 * "MF" symlinks optionally, but for recent Windows we really need to
2790 * reenable the code below and fix the cifs_symlink callers to handle this.
2791 * In the interim this code has been moved to its own config option so
2792 * it is not compiled in by default until callers fixed up and more tested.
2793 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794int
Steve French96daf2b2011-05-27 04:34:02 +00002795CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002797 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 const struct nls_table *nls_codepage)
2799{
2800 int rc = 0;
2801 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002802 struct smb_com_transaction_ioctl_req *pSMB;
2803 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804
Joe Perchesb6b38f72010-04-21 03:50:45 +00002805 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2807 (void **) &pSMBr);
2808 if (rc)
2809 return rc;
2810
2811 pSMB->TotalParameterCount = 0 ;
2812 pSMB->TotalDataCount = 0;
2813 pSMB->MaxParameterCount = cpu_to_le32(2);
2814 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002815 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2816 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 pSMB->MaxSetupCount = 4;
2818 pSMB->Reserved = 0;
2819 pSMB->ParameterOffset = 0;
2820 pSMB->DataCount = 0;
2821 pSMB->DataOffset = 0;
2822 pSMB->SetupCount = 4;
2823 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2824 pSMB->ParameterCount = pSMB->TotalParameterCount;
2825 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2826 pSMB->IsFsctl = 1; /* FSCTL */
2827 pSMB->IsRootFlag = 0;
2828 pSMB->Fid = fid; /* file handle always le */
2829 pSMB->ByteCount = 0;
2830
2831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2833 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002834 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835 } else { /* decode response */
2836 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2837 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002838 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2839 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002841 goto qreparse_out;
2842 }
2843 if (data_count && (data_count < 2048)) {
2844 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002845 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846
Steve Frenchafe48c32009-05-02 05:25:46 +00002847 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002848 (struct reparse_data *)
2849 ((char *)&pSMBr->hdr.Protocol
2850 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002851 if ((char *)reparse_buf >= end_of_smb) {
2852 rc = -EIO;
2853 goto qreparse_out;
2854 }
2855 if ((reparse_buf->LinkNamesBuf +
2856 reparse_buf->TargetNameOffset +
2857 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002858 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002859 rc = -EIO;
2860 goto qreparse_out;
2861 }
Steve French50c2f752007-07-13 00:33:32 +00002862
Steve Frenchafe48c32009-05-02 05:25:46 +00002863 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2864 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002865 (reparse_buf->LinkNamesBuf +
2866 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002867 buflen,
2868 reparse_buf->TargetNameLen,
2869 nls_codepage, 0);
2870 } else { /* ASCII names */
2871 strncpy(symlinkinfo,
2872 reparse_buf->LinkNamesBuf +
2873 reparse_buf->TargetNameOffset,
2874 min_t(const int, buflen,
2875 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002877 } else {
2878 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002879 cFYI(1, "Invalid return data count on "
2880 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002882 symlinkinfo[buflen] = 0; /* just in case so the caller
2883 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002884 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 }
Steve French989c7e52009-05-02 05:32:20 +00002886
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002888 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
2890 /* Note: On -EAGAIN error only caller can retry on handle based calls
2891 since file handle passed in no longer valid */
2892
2893 return rc;
2894}
Steve Frenchc52a95542011-02-24 06:16:22 +00002895#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896
2897#ifdef CONFIG_CIFS_POSIX
2898
2899/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002900static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2901 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902{
2903 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002904 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2905 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2906 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002907 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909 return;
2910}
2911
2912/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002913static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2914 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915{
2916 int size = 0;
2917 int i;
2918 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002919 struct cifs_posix_ace *pACE;
2920 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2921 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922
2923 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2924 return -EOPNOTSUPP;
2925
Steve French790fe572007-07-07 19:25:05 +00002926 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 count = le16_to_cpu(cifs_acl->access_entry_count);
2928 pACE = &cifs_acl->ace_array[0];
2929 size = sizeof(struct cifs_posix_acl);
2930 size += sizeof(struct cifs_posix_ace) * count;
2931 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002932 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002933 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2934 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 return -EINVAL;
2936 }
Steve French790fe572007-07-07 19:25:05 +00002937 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 count = le16_to_cpu(cifs_acl->access_entry_count);
2939 size = sizeof(struct cifs_posix_acl);
2940 size += sizeof(struct cifs_posix_ace) * count;
2941/* skip past access ACEs to get to default ACEs */
2942 pACE = &cifs_acl->ace_array[count];
2943 count = le16_to_cpu(cifs_acl->default_entry_count);
2944 size += sizeof(struct cifs_posix_ace) * count;
2945 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002946 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 return -EINVAL;
2948 } else {
2949 /* illegal type */
2950 return -EINVAL;
2951 }
2952
2953 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002954 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002955 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002956 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 return -ERANGE;
2958 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002959 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002960 for (i = 0; i < count ; i++) {
2961 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2962 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963 }
2964 }
2965 return size;
2966}
2967
Steve French50c2f752007-07-13 00:33:32 +00002968static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2969 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970{
2971 __u16 rc = 0; /* 0 = ACL converted ok */
2972
Steve Frenchff7feac2005-11-15 16:45:16 -08002973 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2974 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002976 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 /* Probably no need to le convert -1 on any arch but can not hurt */
2978 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002979 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002980 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002981 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 return rc;
2983}
2984
2985/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002986static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2987 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988{
2989 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002990 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2991 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 int count;
2993 int i;
2994
Steve French790fe572007-07-07 19:25:05 +00002995 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 return 0;
2997
2998 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002999 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003000 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003001 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003002 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003003 cFYI(1, "unknown POSIX ACL version %d",
3004 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 return 0;
3006 }
3007 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003008 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003009 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003010 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003011 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003013 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 return 0;
3015 }
Steve French50c2f752007-07-13 00:33:32 +00003016 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3018 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003019 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 /* ACE not converted */
3021 break;
3022 }
3023 }
Steve French790fe572007-07-07 19:25:05 +00003024 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3026 rc += sizeof(struct cifs_posix_acl);
3027 /* BB add check to make sure ACL does not overflow SMB */
3028 }
3029 return rc;
3030}
3031
3032int
Steve French96daf2b2011-05-27 04:34:02 +00003033CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003034 const unsigned char *searchName,
3035 char *acl_inf, const int buflen, const int acl_type,
3036 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037{
3038/* SMB_QUERY_POSIX_ACL */
3039 TRANSACTION2_QPI_REQ *pSMB = NULL;
3040 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3041 int rc = 0;
3042 int bytes_returned;
3043 int name_len;
3044 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003045
Joe Perchesb6b38f72010-04-21 03:50:45 +00003046 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047
3048queryAclRetry:
3049 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3050 (void **) &pSMBr);
3051 if (rc)
3052 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003053
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3055 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003056 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003057 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 name_len++; /* trailing null */
3059 name_len *= 2;
3060 pSMB->FileName[name_len] = 0;
3061 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003062 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 name_len = strnlen(searchName, PATH_MAX);
3064 name_len++; /* trailing null */
3065 strncpy(pSMB->FileName, searchName, name_len);
3066 }
3067
3068 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3069 pSMB->TotalDataCount = 0;
3070 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003071 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 pSMB->MaxDataCount = cpu_to_le16(4000);
3073 pSMB->MaxSetupCount = 0;
3074 pSMB->Reserved = 0;
3075 pSMB->Flags = 0;
3076 pSMB->Timeout = 0;
3077 pSMB->Reserved2 = 0;
3078 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003079 offsetof(struct smb_com_transaction2_qpi_req,
3080 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 pSMB->DataCount = 0;
3082 pSMB->DataOffset = 0;
3083 pSMB->SetupCount = 1;
3084 pSMB->Reserved3 = 0;
3085 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3086 byte_count = params + 1 /* pad */ ;
3087 pSMB->TotalParameterCount = cpu_to_le16(params);
3088 pSMB->ParameterCount = pSMB->TotalParameterCount;
3089 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3090 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003091 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 pSMB->ByteCount = cpu_to_le16(byte_count);
3093
3094 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3095 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003096 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003098 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 } else {
3100 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003101
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003104 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 rc = -EIO; /* bad smb */
3106 else {
3107 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3108 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3109 rc = cifs_copy_posix_acl(acl_inf,
3110 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003111 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 }
3113 }
3114 cifs_buf_release(pSMB);
3115 if (rc == -EAGAIN)
3116 goto queryAclRetry;
3117 return rc;
3118}
3119
3120int
Steve French96daf2b2011-05-27 04:34:02 +00003121CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003122 const unsigned char *fileName,
3123 const char *local_acl, const int buflen,
3124 const int acl_type,
3125 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003126{
3127 struct smb_com_transaction2_spi_req *pSMB = NULL;
3128 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3129 char *parm_data;
3130 int name_len;
3131 int rc = 0;
3132 int bytes_returned = 0;
3133 __u16 params, byte_count, data_count, param_offset, offset;
3134
Joe Perchesb6b38f72010-04-21 03:50:45 +00003135 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136setAclRetry:
3137 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003138 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 if (rc)
3140 return rc;
3141 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3142 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003143 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003144 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 name_len++; /* trailing null */
3146 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003147 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148 name_len = strnlen(fileName, PATH_MAX);
3149 name_len++; /* trailing null */
3150 strncpy(pSMB->FileName, fileName, name_len);
3151 }
3152 params = 6 + name_len;
3153 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003154 /* BB find max SMB size from sess */
3155 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156 pSMB->MaxSetupCount = 0;
3157 pSMB->Reserved = 0;
3158 pSMB->Flags = 0;
3159 pSMB->Timeout = 0;
3160 pSMB->Reserved2 = 0;
3161 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003162 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 offset = param_offset + params;
3164 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3165 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3166
3167 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003168 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169
Steve French790fe572007-07-07 19:25:05 +00003170 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 rc = -EOPNOTSUPP;
3172 goto setACLerrorExit;
3173 }
3174 pSMB->DataOffset = cpu_to_le16(offset);
3175 pSMB->SetupCount = 1;
3176 pSMB->Reserved3 = 0;
3177 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3178 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3179 byte_count = 3 /* pad */ + params + data_count;
3180 pSMB->DataCount = cpu_to_le16(data_count);
3181 pSMB->TotalDataCount = pSMB->DataCount;
3182 pSMB->ParameterCount = cpu_to_le16(params);
3183 pSMB->TotalParameterCount = pSMB->ParameterCount;
3184 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003185 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 pSMB->ByteCount = cpu_to_le16(byte_count);
3187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003189 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003190 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191
3192setACLerrorExit:
3193 cifs_buf_release(pSMB);
3194 if (rc == -EAGAIN)
3195 goto setAclRetry;
3196 return rc;
3197}
3198
Steve Frenchf654bac2005-04-28 22:41:04 -07003199/* BB fix tabs in this function FIXME BB */
3200int
Steve French96daf2b2011-05-27 04:34:02 +00003201CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003202 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003203{
Steve French50c2f752007-07-13 00:33:32 +00003204 int rc = 0;
3205 struct smb_t2_qfi_req *pSMB = NULL;
3206 struct smb_t2_qfi_rsp *pSMBr = NULL;
3207 int bytes_returned;
3208 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003209
Joe Perchesb6b38f72010-04-21 03:50:45 +00003210 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003211 if (tcon == NULL)
3212 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003213
3214GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003215 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3216 (void **) &pSMBr);
3217 if (rc)
3218 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003219
Steve Frenchad7a2922008-02-07 23:25:02 +00003220 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003221 pSMB->t2.TotalDataCount = 0;
3222 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3223 /* BB find exact max data count below from sess structure BB */
3224 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3225 pSMB->t2.MaxSetupCount = 0;
3226 pSMB->t2.Reserved = 0;
3227 pSMB->t2.Flags = 0;
3228 pSMB->t2.Timeout = 0;
3229 pSMB->t2.Reserved2 = 0;
3230 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3231 Fid) - 4);
3232 pSMB->t2.DataCount = 0;
3233 pSMB->t2.DataOffset = 0;
3234 pSMB->t2.SetupCount = 1;
3235 pSMB->t2.Reserved3 = 0;
3236 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3237 byte_count = params + 1 /* pad */ ;
3238 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3239 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3240 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3241 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003242 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003243 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003244 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003245
Steve French790fe572007-07-07 19:25:05 +00003246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3248 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003249 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003250 } else {
3251 /* decode response */
3252 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003253 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003254 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003255 /* If rc should we check for EOPNOSUPP and
3256 disable the srvino flag? or in caller? */
3257 rc = -EIO; /* bad smb */
3258 else {
3259 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3260 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3261 struct file_chattr_info *pfinfo;
3262 /* BB Do we need a cast or hash here ? */
3263 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003264 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003265 rc = -EIO;
3266 goto GetExtAttrOut;
3267 }
3268 pfinfo = (struct file_chattr_info *)
3269 (data_offset + (char *) &pSMBr->hdr.Protocol);
3270 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003271 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003272 }
3273 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003274GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003275 cifs_buf_release(pSMB);
3276 if (rc == -EAGAIN)
3277 goto GetExtAttrRetry;
3278 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003279}
3280
Steve Frenchf654bac2005-04-28 22:41:04 -07003281#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282
Jeff Layton79df1ba2010-12-06 12:52:08 -05003283#ifdef CONFIG_CIFS_ACL
3284/*
3285 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3286 * all NT TRANSACTS that we init here have total parm and data under about 400
3287 * bytes (to fit in small cifs buffer size), which is the case so far, it
3288 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3289 * returned setup area) and MaxParameterCount (returned parms size) must be set
3290 * by caller
3291 */
3292static int
3293smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003294 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003295 void **ret_buf)
3296{
3297 int rc;
3298 __u32 temp_offset;
3299 struct smb_com_ntransact_req *pSMB;
3300
3301 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3302 (void **)&pSMB);
3303 if (rc)
3304 return rc;
3305 *ret_buf = (void *)pSMB;
3306 pSMB->Reserved = 0;
3307 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3308 pSMB->TotalDataCount = 0;
3309 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3310 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3311 pSMB->ParameterCount = pSMB->TotalParameterCount;
3312 pSMB->DataCount = pSMB->TotalDataCount;
3313 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3314 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3315 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3316 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3317 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3318 pSMB->SubCommand = cpu_to_le16(sub_command);
3319 return 0;
3320}
3321
3322static int
3323validate_ntransact(char *buf, char **ppparm, char **ppdata,
3324 __u32 *pparmlen, __u32 *pdatalen)
3325{
3326 char *end_of_smb;
3327 __u32 data_count, data_offset, parm_count, parm_offset;
3328 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003329 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003330
3331 *pdatalen = 0;
3332 *pparmlen = 0;
3333
3334 if (buf == NULL)
3335 return -EINVAL;
3336
3337 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3338
Jeff Layton820a8032011-05-04 08:05:26 -04003339 bcc = get_bcc(&pSMBr->hdr);
3340 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003341 (char *)&pSMBr->ByteCount;
3342
3343 data_offset = le32_to_cpu(pSMBr->DataOffset);
3344 data_count = le32_to_cpu(pSMBr->DataCount);
3345 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3346 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3347
3348 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3349 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3350
3351 /* should we also check that parm and data areas do not overlap? */
3352 if (*ppparm > end_of_smb) {
3353 cFYI(1, "parms start after end of smb");
3354 return -EINVAL;
3355 } else if (parm_count + *ppparm > end_of_smb) {
3356 cFYI(1, "parm end after end of smb");
3357 return -EINVAL;
3358 } else if (*ppdata > end_of_smb) {
3359 cFYI(1, "data starts after end of smb");
3360 return -EINVAL;
3361 } else if (data_count + *ppdata > end_of_smb) {
3362 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3363 *ppdata, data_count, (data_count + *ppdata),
3364 end_of_smb, pSMBr);
3365 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003366 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003367 cFYI(1, "parm count and data count larger than SMB");
3368 return -EINVAL;
3369 }
3370 *pdatalen = data_count;
3371 *pparmlen = parm_count;
3372 return 0;
3373}
3374
Steve French0a4b92c2006-01-12 15:44:21 -08003375/* Get Security Descriptor (by handle) from remote server for a file or dir */
3376int
Steve French96daf2b2011-05-27 04:34:02 +00003377CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003378 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003379{
3380 int rc = 0;
3381 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003382 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003383 struct kvec iov[1];
3384
Joe Perchesb6b38f72010-04-21 03:50:45 +00003385 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003386
Steve French630f3f0c2007-10-25 21:17:17 +00003387 *pbuflen = 0;
3388 *acl_inf = NULL;
3389
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003390 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003391 8 /* parm len */, tcon, (void **) &pSMB);
3392 if (rc)
3393 return rc;
3394
3395 pSMB->MaxParameterCount = cpu_to_le32(4);
3396 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3397 pSMB->MaxSetupCount = 0;
3398 pSMB->Fid = fid; /* file handle always le */
3399 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3400 CIFS_ACL_DACL);
3401 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003402 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003403 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003404 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003405
Steve Frencha761ac52007-10-18 21:45:27 +00003406 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003407 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003408 cifs_stats_inc(&tcon->num_acl_get);
3409 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003410 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003411 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003412 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003413 __u32 parm_len;
3414 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003415 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003416 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003417
3418/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003419 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003420 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003421 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003422 goto qsec_out;
3423 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3424
Joe Perchesb6b38f72010-04-21 03:50:45 +00003425 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003426
3427 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3428 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003429 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003430 goto qsec_out;
3431 }
3432
3433/* BB check that data area is minimum length and as big as acl_len */
3434
Steve Frenchaf6f4612007-10-16 18:40:37 +00003435 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003436 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003437 cERROR(1, "acl length %d does not match %d",
3438 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003439 if (*pbuflen > acl_len)
3440 *pbuflen = acl_len;
3441 }
Steve French0a4b92c2006-01-12 15:44:21 -08003442
Steve French630f3f0c2007-10-25 21:17:17 +00003443 /* check if buffer is big enough for the acl
3444 header followed by the smallest SID */
3445 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3446 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003447 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003448 rc = -EINVAL;
3449 *pbuflen = 0;
3450 } else {
3451 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3452 if (*acl_inf == NULL) {
3453 *pbuflen = 0;
3454 rc = -ENOMEM;
3455 }
3456 memcpy(*acl_inf, pdata, *pbuflen);
3457 }
Steve French0a4b92c2006-01-12 15:44:21 -08003458 }
3459qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003460 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003461 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003462 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003463 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003464/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003465 return rc;
3466}
Steve French97837582007-12-31 07:47:21 +00003467
3468int
Steve French96daf2b2011-05-27 04:34:02 +00003469CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French97837582007-12-31 07:47:21 +00003470 struct cifs_ntsd *pntsd, __u32 acllen)
3471{
3472 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3473 int rc = 0;
3474 int bytes_returned = 0;
3475 SET_SEC_DESC_REQ *pSMB = NULL;
3476 NTRANSACT_RSP *pSMBr = NULL;
3477
3478setCifsAclRetry:
3479 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3480 (void **) &pSMBr);
3481 if (rc)
3482 return (rc);
3483
3484 pSMB->MaxSetupCount = 0;
3485 pSMB->Reserved = 0;
3486
3487 param_count = 8;
3488 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3489 data_count = acllen;
3490 data_offset = param_offset + param_count;
3491 byte_count = 3 /* pad */ + param_count;
3492
3493 pSMB->DataCount = cpu_to_le32(data_count);
3494 pSMB->TotalDataCount = pSMB->DataCount;
3495 pSMB->MaxParameterCount = cpu_to_le32(4);
3496 pSMB->MaxDataCount = cpu_to_le32(16384);
3497 pSMB->ParameterCount = cpu_to_le32(param_count);
3498 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3499 pSMB->TotalParameterCount = pSMB->ParameterCount;
3500 pSMB->DataOffset = cpu_to_le32(data_offset);
3501 pSMB->SetupCount = 0;
3502 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3503 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3504
3505 pSMB->Fid = fid; /* file handle always le */
3506 pSMB->Reserved2 = 0;
3507 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3508
3509 if (pntsd && acllen) {
3510 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3511 (char *) pntsd,
3512 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003513 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003514 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003515 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003516
3517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3518 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3519
Joe Perchesb6b38f72010-04-21 03:50:45 +00003520 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003521 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003522 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003523 cifs_buf_release(pSMB);
3524
3525 if (rc == -EAGAIN)
3526 goto setCifsAclRetry;
3527
3528 return (rc);
3529}
3530
Jeff Layton79df1ba2010-12-06 12:52:08 -05003531#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003532
Steve French6b8edfe2005-08-23 20:26:03 -07003533/* Legacy Query Path Information call for lookup to old servers such
3534 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003535int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003536 const unsigned char *searchName,
3537 FILE_ALL_INFO *pFinfo,
3538 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003539{
Steve Frenchad7a2922008-02-07 23:25:02 +00003540 QUERY_INFORMATION_REQ *pSMB;
3541 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003542 int rc = 0;
3543 int bytes_returned;
3544 int name_len;
3545
Joe Perchesb6b38f72010-04-21 03:50:45 +00003546 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003547QInfRetry:
3548 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003549 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003550 if (rc)
3551 return rc;
3552
3553 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3554 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003555 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3556 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003557 name_len++; /* trailing null */
3558 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003559 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003560 name_len = strnlen(searchName, PATH_MAX);
3561 name_len++; /* trailing null */
3562 strncpy(pSMB->FileName, searchName, name_len);
3563 }
3564 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003565 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003566 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003567 pSMB->ByteCount = cpu_to_le16(name_len);
3568
3569 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003570 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003571 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003572 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003573 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003574 struct timespec ts;
3575 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003576
3577 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003578 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003579 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003580 ts.tv_nsec = 0;
3581 ts.tv_sec = time;
3582 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003583 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003584 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3585 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003586 pFinfo->AllocationSize =
3587 cpu_to_le64(le32_to_cpu(pSMBr->size));
3588 pFinfo->EndOfFile = pFinfo->AllocationSize;
3589 pFinfo->Attributes =
3590 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003591 } else
3592 rc = -EIO; /* bad buffer passed in */
3593
3594 cifs_buf_release(pSMB);
3595
3596 if (rc == -EAGAIN)
3597 goto QInfRetry;
3598
3599 return rc;
3600}
3601
Jeff Laytonbcd53572010-02-12 07:44:16 -05003602int
Steve French96daf2b2011-05-27 04:34:02 +00003603CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003604 u16 netfid, FILE_ALL_INFO *pFindData)
3605{
3606 struct smb_t2_qfi_req *pSMB = NULL;
3607 struct smb_t2_qfi_rsp *pSMBr = NULL;
3608 int rc = 0;
3609 int bytes_returned;
3610 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003611
Jeff Laytonbcd53572010-02-12 07:44:16 -05003612QFileInfoRetry:
3613 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3614 (void **) &pSMBr);
3615 if (rc)
3616 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003617
Jeff Laytonbcd53572010-02-12 07:44:16 -05003618 params = 2 /* level */ + 2 /* fid */;
3619 pSMB->t2.TotalDataCount = 0;
3620 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3621 /* BB find exact max data count below from sess structure BB */
3622 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3623 pSMB->t2.MaxSetupCount = 0;
3624 pSMB->t2.Reserved = 0;
3625 pSMB->t2.Flags = 0;
3626 pSMB->t2.Timeout = 0;
3627 pSMB->t2.Reserved2 = 0;
3628 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3629 Fid) - 4);
3630 pSMB->t2.DataCount = 0;
3631 pSMB->t2.DataOffset = 0;
3632 pSMB->t2.SetupCount = 1;
3633 pSMB->t2.Reserved3 = 0;
3634 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3635 byte_count = params + 1 /* pad */ ;
3636 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3637 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3638 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3639 pSMB->Pad = 0;
3640 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003641 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003642
3643 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3644 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3645 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003646 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003647 } else { /* decode response */
3648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3649
3650 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3651 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003652 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003653 rc = -EIO; /* bad smb */
3654 else if (pFindData) {
3655 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3656 memcpy((char *) pFindData,
3657 (char *) &pSMBr->hdr.Protocol +
3658 data_offset, sizeof(FILE_ALL_INFO));
3659 } else
3660 rc = -ENOMEM;
3661 }
3662 cifs_buf_release(pSMB);
3663 if (rc == -EAGAIN)
3664 goto QFileInfoRetry;
3665
3666 return rc;
3667}
Steve French6b8edfe2005-08-23 20:26:03 -07003668
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669int
Steve French96daf2b2011-05-27 04:34:02 +00003670CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003672 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003673 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003674 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675{
3676/* level 263 SMB_QUERY_FILE_ALL_INFO */
3677 TRANSACTION2_QPI_REQ *pSMB = NULL;
3678 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3679 int rc = 0;
3680 int bytes_returned;
3681 int name_len;
3682 __u16 params, byte_count;
3683
Joe Perchesb6b38f72010-04-21 03:50:45 +00003684/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685QPathInfoRetry:
3686 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3687 (void **) &pSMBr);
3688 if (rc)
3689 return rc;
3690
3691 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3692 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003693 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003694 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695 name_len++; /* trailing null */
3696 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003697 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 name_len = strnlen(searchName, PATH_MAX);
3699 name_len++; /* trailing null */
3700 strncpy(pSMB->FileName, searchName, name_len);
3701 }
3702
Steve French50c2f752007-07-13 00:33:32 +00003703 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 pSMB->TotalDataCount = 0;
3705 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003706 /* BB find exact max SMB PDU from sess structure BB */
3707 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 pSMB->MaxSetupCount = 0;
3709 pSMB->Reserved = 0;
3710 pSMB->Flags = 0;
3711 pSMB->Timeout = 0;
3712 pSMB->Reserved2 = 0;
3713 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003714 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 pSMB->DataCount = 0;
3716 pSMB->DataOffset = 0;
3717 pSMB->SetupCount = 1;
3718 pSMB->Reserved3 = 0;
3719 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3720 byte_count = params + 1 /* pad */ ;
3721 pSMB->TotalParameterCount = cpu_to_le16(params);
3722 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003723 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003724 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3725 else
3726 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003728 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 pSMB->ByteCount = cpu_to_le16(byte_count);
3730
3731 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3732 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3733 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003734 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 } else { /* decode response */
3736 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3737
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003738 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3739 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003740 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003742 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003743 rc = -EIO; /* 24 or 26 expected but we do not read
3744 last field */
3745 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003746 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003748
3749 /* On legacy responses we do not read the last field,
3750 EAsize, fortunately since it varies by subdialect and
3751 also note it differs on Set vs. Get, ie two bytes or 4
3752 bytes depending but we don't care here */
3753 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003754 size = sizeof(FILE_INFO_STANDARD);
3755 else
3756 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757 memcpy((char *) pFindData,
3758 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003759 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 } else
3761 rc = -ENOMEM;
3762 }
3763 cifs_buf_release(pSMB);
3764 if (rc == -EAGAIN)
3765 goto QPathInfoRetry;
3766
3767 return rc;
3768}
3769
3770int
Steve French96daf2b2011-05-27 04:34:02 +00003771CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003772 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3773{
3774 struct smb_t2_qfi_req *pSMB = NULL;
3775 struct smb_t2_qfi_rsp *pSMBr = NULL;
3776 int rc = 0;
3777 int bytes_returned;
3778 __u16 params, byte_count;
3779
3780UnixQFileInfoRetry:
3781 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3782 (void **) &pSMBr);
3783 if (rc)
3784 return rc;
3785
3786 params = 2 /* level */ + 2 /* fid */;
3787 pSMB->t2.TotalDataCount = 0;
3788 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3789 /* BB find exact max data count below from sess structure BB */
3790 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3791 pSMB->t2.MaxSetupCount = 0;
3792 pSMB->t2.Reserved = 0;
3793 pSMB->t2.Flags = 0;
3794 pSMB->t2.Timeout = 0;
3795 pSMB->t2.Reserved2 = 0;
3796 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3797 Fid) - 4);
3798 pSMB->t2.DataCount = 0;
3799 pSMB->t2.DataOffset = 0;
3800 pSMB->t2.SetupCount = 1;
3801 pSMB->t2.Reserved3 = 0;
3802 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3803 byte_count = params + 1 /* pad */ ;
3804 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3805 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3806 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3807 pSMB->Pad = 0;
3808 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003809 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003810
3811 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3812 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3813 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003814 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003815 } else { /* decode response */
3816 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3817
Jeff Layton820a8032011-05-04 08:05:26 -04003818 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003819 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003820 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003821 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003822 rc = -EIO; /* bad smb */
3823 } else {
3824 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3825 memcpy((char *) pFindData,
3826 (char *) &pSMBr->hdr.Protocol +
3827 data_offset,
3828 sizeof(FILE_UNIX_BASIC_INFO));
3829 }
3830 }
3831
3832 cifs_buf_release(pSMB);
3833 if (rc == -EAGAIN)
3834 goto UnixQFileInfoRetry;
3835
3836 return rc;
3837}
3838
3839int
Steve French96daf2b2011-05-27 04:34:02 +00003840CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003842 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003843 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844{
3845/* SMB_QUERY_FILE_UNIX_BASIC */
3846 TRANSACTION2_QPI_REQ *pSMB = NULL;
3847 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3848 int rc = 0;
3849 int bytes_returned = 0;
3850 int name_len;
3851 __u16 params, byte_count;
3852
Joe Perchesb6b38f72010-04-21 03:50:45 +00003853 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854UnixQPathInfoRetry:
3855 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3856 (void **) &pSMBr);
3857 if (rc)
3858 return rc;
3859
3860 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3861 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003862 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003863 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 name_len++; /* trailing null */
3865 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003866 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 name_len = strnlen(searchName, PATH_MAX);
3868 name_len++; /* trailing null */
3869 strncpy(pSMB->FileName, searchName, name_len);
3870 }
3871
Steve French50c2f752007-07-13 00:33:32 +00003872 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 pSMB->TotalDataCount = 0;
3874 pSMB->MaxParameterCount = cpu_to_le16(2);
3875 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003876 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 pSMB->MaxSetupCount = 0;
3878 pSMB->Reserved = 0;
3879 pSMB->Flags = 0;
3880 pSMB->Timeout = 0;
3881 pSMB->Reserved2 = 0;
3882 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003883 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 pSMB->DataCount = 0;
3885 pSMB->DataOffset = 0;
3886 pSMB->SetupCount = 1;
3887 pSMB->Reserved3 = 0;
3888 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3889 byte_count = params + 1 /* pad */ ;
3890 pSMB->TotalParameterCount = cpu_to_le16(params);
3891 pSMB->ParameterCount = pSMB->TotalParameterCount;
3892 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3893 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003894 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 pSMB->ByteCount = cpu_to_le16(byte_count);
3896
3897 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3898 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3899 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003900 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 } else { /* decode response */
3902 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3903
Jeff Layton820a8032011-05-04 08:05:26 -04003904 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003905 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003906 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003907 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 rc = -EIO; /* bad smb */
3909 } else {
3910 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3911 memcpy((char *) pFindData,
3912 (char *) &pSMBr->hdr.Protocol +
3913 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003914 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 }
3916 }
3917 cifs_buf_release(pSMB);
3918 if (rc == -EAGAIN)
3919 goto UnixQPathInfoRetry;
3920
3921 return rc;
3922}
3923
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924/* xid, tcon, searchName and codepage are input parms, rest are returned */
3925int
Steve French96daf2b2011-05-27 04:34:02 +00003926CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003927 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003929 __u16 *pnetfid,
3930 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003931{
3932/* level 257 SMB_ */
3933 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3934 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003935 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936 int rc = 0;
3937 int bytes_returned = 0;
3938 int name_len;
3939 __u16 params, byte_count;
3940
Joe Perchesb6b38f72010-04-21 03:50:45 +00003941 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942
3943findFirstRetry:
3944 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3945 (void **) &pSMBr);
3946 if (rc)
3947 return rc;
3948
3949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3950 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003951 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003952 PATH_MAX, nls_codepage, remap);
3953 /* We can not add the asterik earlier in case
3954 it got remapped to 0xF03A as if it were part of the
3955 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003957 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003958 pSMB->FileName[name_len+1] = 0;
3959 pSMB->FileName[name_len+2] = '*';
3960 pSMB->FileName[name_len+3] = 0;
3961 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3963 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003964 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 } else { /* BB add check for overrun of SMB buf BB */
3966 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003968 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 free buffer exit; BB */
3970 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003971 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003972 pSMB->FileName[name_len+1] = '*';
3973 pSMB->FileName[name_len+2] = 0;
3974 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 }
3976
3977 params = 12 + name_len /* includes null */ ;
3978 pSMB->TotalDataCount = 0; /* no EAs */
3979 pSMB->MaxParameterCount = cpu_to_le16(10);
3980 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3981 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3982 pSMB->MaxSetupCount = 0;
3983 pSMB->Reserved = 0;
3984 pSMB->Flags = 0;
3985 pSMB->Timeout = 0;
3986 pSMB->Reserved2 = 0;
3987 byte_count = params + 1 /* pad */ ;
3988 pSMB->TotalParameterCount = cpu_to_le16(params);
3989 pSMB->ParameterCount = pSMB->TotalParameterCount;
3990 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003991 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3992 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 pSMB->DataCount = 0;
3994 pSMB->DataOffset = 0;
3995 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3996 pSMB->Reserved3 = 0;
3997 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3998 pSMB->SearchAttributes =
3999 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4000 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004001 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4002 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 CIFS_SEARCH_RETURN_RESUME);
4004 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4005
4006 /* BB what should we set StorageType to? Does it matter? BB */
4007 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004008 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009 pSMB->ByteCount = cpu_to_le16(byte_count);
4010
4011 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4012 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07004013 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014
Steve French88274812006-03-09 22:21:45 +00004015 if (rc) {/* BB add logic to retry regular search if Unix search
4016 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004018 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004019
Steve French88274812006-03-09 22:21:45 +00004020 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
4022 /* BB eventually could optimize out free and realloc of buf */
4023 /* for this case */
4024 if (rc == -EAGAIN)
4025 goto findFirstRetry;
4026 } else { /* decode response */
4027 /* BB remember to free buffer if error BB */
4028 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004029 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004030 unsigned int lnoff;
4031
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004033 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 else
Steve French4b18f2a2008-04-29 00:06:05 +00004035 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036
4037 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004038 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004039 psrch_inf->srch_entries_start =
4040 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4043 le16_to_cpu(pSMBr->t2.ParameterOffset));
4044
Steve French790fe572007-07-07 19:25:05 +00004045 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004046 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 else
Steve French4b18f2a2008-04-29 00:06:05 +00004048 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049
Steve French50c2f752007-07-13 00:33:32 +00004050 psrch_inf->entries_in_buffer =
4051 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004052 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004054 lnoff = le16_to_cpu(parms->LastNameOffset);
4055 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4056 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004057 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004058 psrch_inf->last_entry = NULL;
4059 return rc;
4060 }
4061
Steve French0752f152008-10-07 20:03:33 +00004062 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004063 lnoff;
4064
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065 *pnetfid = parms->SearchHandle;
4066 } else {
4067 cifs_buf_release(pSMB);
4068 }
4069 }
4070
4071 return rc;
4072}
4073
Steve French96daf2b2011-05-27 04:34:02 +00004074int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004075 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076{
4077 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4078 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004079 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 char *response_data;
4081 int rc = 0;
4082 int bytes_returned, name_len;
4083 __u16 params, byte_count;
4084
Joe Perchesb6b38f72010-04-21 03:50:45 +00004085 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
Steve French4b18f2a2008-04-29 00:06:05 +00004087 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 return -ENOENT;
4089
4090 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4091 (void **) &pSMBr);
4092 if (rc)
4093 return rc;
4094
Steve French50c2f752007-07-13 00:33:32 +00004095 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 byte_count = 0;
4097 pSMB->TotalDataCount = 0; /* no EAs */
4098 pSMB->MaxParameterCount = cpu_to_le16(8);
4099 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00004100 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
4101 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 pSMB->MaxSetupCount = 0;
4103 pSMB->Reserved = 0;
4104 pSMB->Flags = 0;
4105 pSMB->Timeout = 0;
4106 pSMB->Reserved2 = 0;
4107 pSMB->ParameterOffset = cpu_to_le16(
4108 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4109 pSMB->DataCount = 0;
4110 pSMB->DataOffset = 0;
4111 pSMB->SetupCount = 1;
4112 pSMB->Reserved3 = 0;
4113 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4114 pSMB->SearchHandle = searchHandle; /* always kept as le */
4115 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004116 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4118 pSMB->ResumeKey = psrch_inf->resume_key;
4119 pSMB->SearchFlags =
4120 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4121
4122 name_len = psrch_inf->resume_name_len;
4123 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004124 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4126 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004127 /* 14 byte parm len above enough for 2 byte null terminator */
4128 pSMB->ResumeFileName[name_len] = 0;
4129 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 } else {
4131 rc = -EINVAL;
4132 goto FNext2_err_exit;
4133 }
4134 byte_count = params + 1 /* pad */ ;
4135 pSMB->TotalParameterCount = cpu_to_le16(params);
4136 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004137 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004139
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07004142 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 if (rc) {
4144 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004145 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004146 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004147 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004149 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 } else { /* decode response */
4151 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004152
Steve French790fe572007-07-07 19:25:05 +00004153 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004154 unsigned int lnoff;
4155
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 /* BB fixme add lock for file (srch_info) struct here */
4157 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004158 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 else
Steve French4b18f2a2008-04-29 00:06:05 +00004160 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 response_data = (char *) &pSMBr->hdr.Protocol +
4162 le16_to_cpu(pSMBr->t2.ParameterOffset);
4163 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4164 response_data = (char *)&pSMBr->hdr.Protocol +
4165 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004166 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004167 cifs_small_buf_release(
4168 psrch_inf->ntwrk_buf_start);
4169 else
4170 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 psrch_inf->srch_entries_start = response_data;
4172 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004173 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004174 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004175 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 else
Steve French4b18f2a2008-04-29 00:06:05 +00004177 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004178 psrch_inf->entries_in_buffer =
4179 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 psrch_inf->index_of_last_entry +=
4181 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004182 lnoff = le16_to_cpu(parms->LastNameOffset);
4183 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4184 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004185 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004186 psrch_inf->last_entry = NULL;
4187 return rc;
4188 } else
4189 psrch_inf->last_entry =
4190 psrch_inf->srch_entries_start + lnoff;
4191
Joe Perchesb6b38f72010-04-21 03:50:45 +00004192/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4193 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
4195 /* BB fixme add unlock here */
4196 }
4197
4198 }
4199
4200 /* BB On error, should we leave previous search buf (and count and
4201 last entry fields) intact or free the previous one? */
4202
4203 /* Note: On -EAGAIN error only caller can retry on handle based calls
4204 since file handle passed in no longer valid */
4205FNext2_err_exit:
4206 if (rc != 0)
4207 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208 return rc;
4209}
4210
4211int
Steve French96daf2b2011-05-27 04:34:02 +00004212CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004213 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214{
4215 int rc = 0;
4216 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217
Joe Perchesb6b38f72010-04-21 03:50:45 +00004218 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4220
4221 /* no sense returning error if session restarted
4222 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004223 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 return 0;
4225 if (rc)
4226 return rc;
4227
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 pSMB->FileID = searchHandle;
4229 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004230 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004231 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004232 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004233
Steve Frencha45443472005-08-24 13:59:35 -07004234 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235
4236 /* Since session is dead, search handle closed on server already */
4237 if (rc == -EAGAIN)
4238 rc = 0;
4239
4240 return rc;
4241}
4242
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243int
Steve French96daf2b2011-05-27 04:34:02 +00004244CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004245 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004246 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004247 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248{
4249 int rc = 0;
4250 TRANSACTION2_QPI_REQ *pSMB = NULL;
4251 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4252 int name_len, bytes_returned;
4253 __u16 params, byte_count;
4254
Joe Perchesb6b38f72010-04-21 03:50:45 +00004255 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004256 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004257 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
4259GetInodeNumberRetry:
4260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004261 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262 if (rc)
4263 return rc;
4264
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4266 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004267 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004268 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 name_len++; /* trailing null */
4270 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004271 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 name_len = strnlen(searchName, PATH_MAX);
4273 name_len++; /* trailing null */
4274 strncpy(pSMB->FileName, searchName, name_len);
4275 }
4276
4277 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4278 pSMB->TotalDataCount = 0;
4279 pSMB->MaxParameterCount = cpu_to_le16(2);
4280 /* BB find exact max data count below from sess structure BB */
4281 pSMB->MaxDataCount = cpu_to_le16(4000);
4282 pSMB->MaxSetupCount = 0;
4283 pSMB->Reserved = 0;
4284 pSMB->Flags = 0;
4285 pSMB->Timeout = 0;
4286 pSMB->Reserved2 = 0;
4287 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004288 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 pSMB->DataCount = 0;
4290 pSMB->DataOffset = 0;
4291 pSMB->SetupCount = 1;
4292 pSMB->Reserved3 = 0;
4293 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4294 byte_count = params + 1 /* pad */ ;
4295 pSMB->TotalParameterCount = cpu_to_le16(params);
4296 pSMB->ParameterCount = pSMB->TotalParameterCount;
4297 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4298 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004299 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 pSMB->ByteCount = cpu_to_le16(byte_count);
4301
4302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4304 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004305 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 } else {
4307 /* decode response */
4308 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004310 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 /* If rc should we check for EOPNOSUPP and
4312 disable the srvino flag? or in caller? */
4313 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004314 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4316 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004317 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004319 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004320 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 rc = -EIO;
4322 goto GetInodeNumOut;
4323 }
4324 pfinfo = (struct file_internal_info *)
4325 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004326 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327 }
4328 }
4329GetInodeNumOut:
4330 cifs_buf_release(pSMB);
4331 if (rc == -EAGAIN)
4332 goto GetInodeNumberRetry;
4333 return rc;
4334}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335
Igor Mammedovfec45852008-05-16 13:06:30 +04004336/* parses DFS refferal V3 structure
4337 * caller is responsible for freeing target_nodes
4338 * returns:
4339 * on success - 0
4340 * on failure - errno
4341 */
4342static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004343parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004344 unsigned int *num_of_nodes,
4345 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004346 const struct nls_table *nls_codepage, int remap,
4347 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004348{
4349 int i, rc = 0;
4350 char *data_end;
4351 bool is_unicode;
4352 struct dfs_referral_level_3 *ref;
4353
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004354 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4355 is_unicode = true;
4356 else
4357 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004358 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4359
4360 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004361 cERROR(1, "num_referrals: must be at least > 0,"
4362 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004363 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004364 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004365 }
4366
4367 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004368 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004369 cERROR(1, "Referrals of V%d version are not supported,"
4370 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004371 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004372 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004373 }
4374
4375 /* get the upper boundary of the resp buffer */
4376 data_end = (char *)(&(pSMBr->PathConsumed)) +
4377 le16_to_cpu(pSMBr->t2.DataCount);
4378
Steve Frenchf19159d2010-04-21 04:12:10 +00004379 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004380 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004381 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004382
4383 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4384 *num_of_nodes, GFP_KERNEL);
4385 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004386 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004387 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004388 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004389 }
4390
Daniel Mack3ad2f3fb2010-02-03 08:01:28 +08004391 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004392 for (i = 0; i < *num_of_nodes; i++) {
4393 char *temp;
4394 int max_len;
4395 struct dfs_info3_param *node = (*target_nodes)+i;
4396
Steve French0e0d2cf2009-05-01 05:27:32 +00004397 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004398 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004399 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4400 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004401 if (tmp == NULL) {
4402 rc = -ENOMEM;
4403 goto parse_DFS_referrals_exit;
4404 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004405 cifsConvertToUCS((__le16 *) tmp, searchName,
4406 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004407 node->path_consumed = cifs_ucs2_bytes(tmp,
4408 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004409 nls_codepage);
4410 kfree(tmp);
4411 } else
4412 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4413
Igor Mammedovfec45852008-05-16 13:06:30 +04004414 node->server_type = le16_to_cpu(ref->ServerType);
4415 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4416
4417 /* copy DfsPath */
4418 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4419 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004420 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4421 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004422 if (!node->path_name) {
4423 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004424 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004425 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004426
4427 /* copy link target UNC */
4428 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4429 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004430 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4431 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004432 if (!node->node_name)
4433 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004434 }
4435
Steve Frencha1fe78f2008-05-16 18:48:38 +00004436parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004437 if (rc) {
4438 free_dfs_info_array(*target_nodes, *num_of_nodes);
4439 *target_nodes = NULL;
4440 *num_of_nodes = 0;
4441 }
4442 return rc;
4443}
4444
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445int
Steve French96daf2b2011-05-27 04:34:02 +00004446CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004448 struct dfs_info3_param **target_nodes,
4449 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004450 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451{
4452/* TRANS2_GET_DFS_REFERRAL */
4453 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4454 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 int rc = 0;
4456 int bytes_returned;
4457 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004459 *num_of_nodes = 0;
4460 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
Joe Perchesb6b38f72010-04-21 03:50:45 +00004462 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 if (ses == NULL)
4464 return -ENODEV;
4465getDFSRetry:
4466 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4467 (void **) &pSMBr);
4468 if (rc)
4469 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004470
4471 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004472 but should never be null here anyway */
4473 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 pSMB->hdr.Tid = ses->ipc_tid;
4475 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004476 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004478 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480
4481 if (ses->capabilities & CAP_UNICODE) {
4482 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4483 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004484 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004485 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 name_len++; /* trailing null */
4487 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004488 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 name_len = strnlen(searchName, PATH_MAX);
4490 name_len++; /* trailing null */
4491 strncpy(pSMB->RequestFileName, searchName, name_len);
4492 }
4493
Steve French790fe572007-07-07 19:25:05 +00004494 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004495 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004496 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4497 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4498 }
4499
Steve French50c2f752007-07-13 00:33:32 +00004500 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004501
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 params = 2 /* level */ + name_len /*includes null */ ;
4503 pSMB->TotalDataCount = 0;
4504 pSMB->DataCount = 0;
4505 pSMB->DataOffset = 0;
4506 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004507 /* BB find exact max SMB PDU from sess structure BB */
4508 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 pSMB->MaxSetupCount = 0;
4510 pSMB->Reserved = 0;
4511 pSMB->Flags = 0;
4512 pSMB->Timeout = 0;
4513 pSMB->Reserved2 = 0;
4514 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004515 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 pSMB->SetupCount = 1;
4517 pSMB->Reserved3 = 0;
4518 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4519 byte_count = params + 3 /* pad */ ;
4520 pSMB->ParameterCount = cpu_to_le16(params);
4521 pSMB->TotalParameterCount = pSMB->ParameterCount;
4522 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004523 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 pSMB->ByteCount = cpu_to_le16(byte_count);
4525
4526 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4527 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4528 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004529 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004530 goto GetDFSRefExit;
4531 }
4532 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004534 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004535 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004536 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004537 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004539
Joe Perchesb6b38f72010-04-21 03:50:45 +00004540 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004541 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004542 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004543
4544 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004545 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004546 target_nodes, nls_codepage, remap,
4547 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004548
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004550 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
4552 if (rc == -EAGAIN)
4553 goto getDFSRetry;
4554
4555 return rc;
4556}
4557
Steve French20962432005-09-21 22:05:57 -07004558/* Query File System Info such as free space to old servers such as Win 9x */
4559int
Steve French96daf2b2011-05-27 04:34:02 +00004560SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004561{
4562/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4563 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4564 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4565 FILE_SYSTEM_ALLOC_INFO *response_data;
4566 int rc = 0;
4567 int bytes_returned = 0;
4568 __u16 params, byte_count;
4569
Joe Perchesb6b38f72010-04-21 03:50:45 +00004570 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004571oldQFSInfoRetry:
4572 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4573 (void **) &pSMBr);
4574 if (rc)
4575 return rc;
Steve French20962432005-09-21 22:05:57 -07004576
4577 params = 2; /* level */
4578 pSMB->TotalDataCount = 0;
4579 pSMB->MaxParameterCount = cpu_to_le16(2);
4580 pSMB->MaxDataCount = cpu_to_le16(1000);
4581 pSMB->MaxSetupCount = 0;
4582 pSMB->Reserved = 0;
4583 pSMB->Flags = 0;
4584 pSMB->Timeout = 0;
4585 pSMB->Reserved2 = 0;
4586 byte_count = params + 1 /* pad */ ;
4587 pSMB->TotalParameterCount = cpu_to_le16(params);
4588 pSMB->ParameterCount = pSMB->TotalParameterCount;
4589 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4590 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4591 pSMB->DataCount = 0;
4592 pSMB->DataOffset = 0;
4593 pSMB->SetupCount = 1;
4594 pSMB->Reserved3 = 0;
4595 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4596 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004597 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004598 pSMB->ByteCount = cpu_to_le16(byte_count);
4599
4600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4602 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004603 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004604 } else { /* decode response */
4605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4606
Jeff Layton820a8032011-05-04 08:05:26 -04004607 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004608 rc = -EIO; /* bad smb */
4609 else {
4610 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004611 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004612 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004613
Steve French50c2f752007-07-13 00:33:32 +00004614 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004615 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4616 FSData->f_bsize =
4617 le16_to_cpu(response_data->BytesPerSector) *
4618 le32_to_cpu(response_data->
4619 SectorsPerAllocationUnit);
4620 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004621 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004622 FSData->f_bfree = FSData->f_bavail =
4623 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004624 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4625 (unsigned long long)FSData->f_blocks,
4626 (unsigned long long)FSData->f_bfree,
4627 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004628 }
4629 }
4630 cifs_buf_release(pSMB);
4631
4632 if (rc == -EAGAIN)
4633 goto oldQFSInfoRetry;
4634
4635 return rc;
4636}
4637
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638int
Steve French96daf2b2011-05-27 04:34:02 +00004639CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640{
4641/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4642 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4643 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4644 FILE_SYSTEM_INFO *response_data;
4645 int rc = 0;
4646 int bytes_returned = 0;
4647 __u16 params, byte_count;
4648
Joe Perchesb6b38f72010-04-21 03:50:45 +00004649 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650QFSInfoRetry:
4651 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4652 (void **) &pSMBr);
4653 if (rc)
4654 return rc;
4655
4656 params = 2; /* level */
4657 pSMB->TotalDataCount = 0;
4658 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004659 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 pSMB->MaxSetupCount = 0;
4661 pSMB->Reserved = 0;
4662 pSMB->Flags = 0;
4663 pSMB->Timeout = 0;
4664 pSMB->Reserved2 = 0;
4665 byte_count = params + 1 /* pad */ ;
4666 pSMB->TotalParameterCount = cpu_to_le16(params);
4667 pSMB->ParameterCount = pSMB->TotalParameterCount;
4668 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004669 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 pSMB->DataCount = 0;
4671 pSMB->DataOffset = 0;
4672 pSMB->SetupCount = 1;
4673 pSMB->Reserved3 = 0;
4674 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4675 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004676 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 pSMB->ByteCount = cpu_to_le16(byte_count);
4678
4679 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4680 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4681 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004682 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004684 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685
Jeff Layton820a8032011-05-04 08:05:26 -04004686 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 rc = -EIO; /* bad smb */
4688 else {
4689 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
4691 response_data =
4692 (FILE_SYSTEM_INFO
4693 *) (((char *) &pSMBr->hdr.Protocol) +
4694 data_offset);
4695 FSData->f_bsize =
4696 le32_to_cpu(response_data->BytesPerSector) *
4697 le32_to_cpu(response_data->
4698 SectorsPerAllocationUnit);
4699 FSData->f_blocks =
4700 le64_to_cpu(response_data->TotalAllocationUnits);
4701 FSData->f_bfree = FSData->f_bavail =
4702 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004703 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4704 (unsigned long long)FSData->f_blocks,
4705 (unsigned long long)FSData->f_bfree,
4706 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 }
4708 }
4709 cifs_buf_release(pSMB);
4710
4711 if (rc == -EAGAIN)
4712 goto QFSInfoRetry;
4713
4714 return rc;
4715}
4716
4717int
Steve French96daf2b2011-05-27 04:34:02 +00004718CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719{
4720/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4721 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4722 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4723 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4724 int rc = 0;
4725 int bytes_returned = 0;
4726 __u16 params, byte_count;
4727
Joe Perchesb6b38f72010-04-21 03:50:45 +00004728 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729QFSAttributeRetry:
4730 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4731 (void **) &pSMBr);
4732 if (rc)
4733 return rc;
4734
4735 params = 2; /* level */
4736 pSMB->TotalDataCount = 0;
4737 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004738 /* BB find exact max SMB PDU from sess structure BB */
4739 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 pSMB->MaxSetupCount = 0;
4741 pSMB->Reserved = 0;
4742 pSMB->Flags = 0;
4743 pSMB->Timeout = 0;
4744 pSMB->Reserved2 = 0;
4745 byte_count = params + 1 /* pad */ ;
4746 pSMB->TotalParameterCount = cpu_to_le16(params);
4747 pSMB->ParameterCount = pSMB->TotalParameterCount;
4748 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004749 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750 pSMB->DataCount = 0;
4751 pSMB->DataOffset = 0;
4752 pSMB->SetupCount = 1;
4753 pSMB->Reserved3 = 0;
4754 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4755 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004756 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757 pSMB->ByteCount = cpu_to_le16(byte_count);
4758
4759 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4760 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4761 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004762 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 } else { /* decode response */
4764 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4765
Jeff Layton820a8032011-05-04 08:05:26 -04004766 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004767 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 rc = -EIO; /* bad smb */
4769 } else {
4770 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4771 response_data =
4772 (FILE_SYSTEM_ATTRIBUTE_INFO
4773 *) (((char *) &pSMBr->hdr.Protocol) +
4774 data_offset);
4775 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004776 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777 }
4778 }
4779 cifs_buf_release(pSMB);
4780
4781 if (rc == -EAGAIN)
4782 goto QFSAttributeRetry;
4783
4784 return rc;
4785}
4786
4787int
Steve French96daf2b2011-05-27 04:34:02 +00004788CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789{
4790/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4791 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4792 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4793 FILE_SYSTEM_DEVICE_INFO *response_data;
4794 int rc = 0;
4795 int bytes_returned = 0;
4796 __u16 params, byte_count;
4797
Joe Perchesb6b38f72010-04-21 03:50:45 +00004798 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799QFSDeviceRetry:
4800 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4801 (void **) &pSMBr);
4802 if (rc)
4803 return rc;
4804
4805 params = 2; /* level */
4806 pSMB->TotalDataCount = 0;
4807 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004808 /* BB find exact max SMB PDU from sess structure BB */
4809 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 pSMB->MaxSetupCount = 0;
4811 pSMB->Reserved = 0;
4812 pSMB->Flags = 0;
4813 pSMB->Timeout = 0;
4814 pSMB->Reserved2 = 0;
4815 byte_count = params + 1 /* pad */ ;
4816 pSMB->TotalParameterCount = cpu_to_le16(params);
4817 pSMB->ParameterCount = pSMB->TotalParameterCount;
4818 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004819 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820
4821 pSMB->DataCount = 0;
4822 pSMB->DataOffset = 0;
4823 pSMB->SetupCount = 1;
4824 pSMB->Reserved3 = 0;
4825 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4826 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004827 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004828 pSMB->ByteCount = cpu_to_le16(byte_count);
4829
4830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4832 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004833 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 } else { /* decode response */
4835 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4836
Jeff Layton820a8032011-05-04 08:05:26 -04004837 if (rc || get_bcc(&pSMBr->hdr) <
4838 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 rc = -EIO; /* bad smb */
4840 else {
4841 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4842 response_data =
Steve French737b7582005-04-28 22:41:06 -07004843 (FILE_SYSTEM_DEVICE_INFO *)
4844 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845 data_offset);
4846 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004847 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 }
4849 }
4850 cifs_buf_release(pSMB);
4851
4852 if (rc == -EAGAIN)
4853 goto QFSDeviceRetry;
4854
4855 return rc;
4856}
4857
4858int
Steve French96daf2b2011-05-27 04:34:02 +00004859CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004860{
4861/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4862 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4863 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4864 FILE_SYSTEM_UNIX_INFO *response_data;
4865 int rc = 0;
4866 int bytes_returned = 0;
4867 __u16 params, byte_count;
4868
Joe Perchesb6b38f72010-04-21 03:50:45 +00004869 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004871 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4872 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 if (rc)
4874 return rc;
4875
4876 params = 2; /* level */
4877 pSMB->TotalDataCount = 0;
4878 pSMB->DataCount = 0;
4879 pSMB->DataOffset = 0;
4880 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004881 /* BB find exact max SMB PDU from sess structure BB */
4882 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 pSMB->MaxSetupCount = 0;
4884 pSMB->Reserved = 0;
4885 pSMB->Flags = 0;
4886 pSMB->Timeout = 0;
4887 pSMB->Reserved2 = 0;
4888 byte_count = params + 1 /* pad */ ;
4889 pSMB->ParameterCount = cpu_to_le16(params);
4890 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004891 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4892 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004893 pSMB->SetupCount = 1;
4894 pSMB->Reserved3 = 0;
4895 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4896 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004897 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 pSMB->ByteCount = cpu_to_le16(byte_count);
4899
4900 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4901 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4902 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004903 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 } else { /* decode response */
4905 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4906
Jeff Layton820a8032011-05-04 08:05:26 -04004907 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 rc = -EIO; /* bad smb */
4909 } else {
4910 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4911 response_data =
4912 (FILE_SYSTEM_UNIX_INFO
4913 *) (((char *) &pSMBr->hdr.Protocol) +
4914 data_offset);
4915 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004916 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 }
4918 }
4919 cifs_buf_release(pSMB);
4920
4921 if (rc == -EAGAIN)
4922 goto QFSUnixRetry;
4923
4924
4925 return rc;
4926}
4927
Jeremy Allisonac670552005-06-22 17:26:35 -07004928int
Steve French96daf2b2011-05-27 04:34:02 +00004929CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004930{
4931/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4932 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4933 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4934 int rc = 0;
4935 int bytes_returned = 0;
4936 __u16 params, param_offset, offset, byte_count;
4937
Joe Perchesb6b38f72010-04-21 03:50:45 +00004938 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004939SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004940 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004941 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4942 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004943 if (rc)
4944 return rc;
4945
4946 params = 4; /* 2 bytes zero followed by info level. */
4947 pSMB->MaxSetupCount = 0;
4948 pSMB->Reserved = 0;
4949 pSMB->Flags = 0;
4950 pSMB->Timeout = 0;
4951 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004952 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4953 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004954 offset = param_offset + params;
4955
4956 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004957 /* BB find exact max SMB PDU from sess structure BB */
4958 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004959 pSMB->SetupCount = 1;
4960 pSMB->Reserved3 = 0;
4961 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4962 byte_count = 1 /* pad */ + params + 12;
4963
4964 pSMB->DataCount = cpu_to_le16(12);
4965 pSMB->ParameterCount = cpu_to_le16(params);
4966 pSMB->TotalDataCount = pSMB->DataCount;
4967 pSMB->TotalParameterCount = pSMB->ParameterCount;
4968 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4969 pSMB->DataOffset = cpu_to_le16(offset);
4970
4971 /* Params. */
4972 pSMB->FileNum = 0;
4973 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4974
4975 /* Data. */
4976 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4977 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4978 pSMB->ClientUnixCap = cpu_to_le64(cap);
4979
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004980 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004981 pSMB->ByteCount = cpu_to_le16(byte_count);
4982
4983 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4984 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4985 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004986 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004987 } else { /* decode response */
4988 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004989 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004990 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004991 }
4992 cifs_buf_release(pSMB);
4993
4994 if (rc == -EAGAIN)
4995 goto SETFSUnixRetry;
4996
4997 return rc;
4998}
4999
5000
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001
5002int
Steve French96daf2b2011-05-27 04:34:02 +00005003CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07005004 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005{
5006/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5007 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5008 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5009 FILE_SYSTEM_POSIX_INFO *response_data;
5010 int rc = 0;
5011 int bytes_returned = 0;
5012 __u16 params, byte_count;
5013
Joe Perchesb6b38f72010-04-21 03:50:45 +00005014 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015QFSPosixRetry:
5016 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5017 (void **) &pSMBr);
5018 if (rc)
5019 return rc;
5020
5021 params = 2; /* level */
5022 pSMB->TotalDataCount = 0;
5023 pSMB->DataCount = 0;
5024 pSMB->DataOffset = 0;
5025 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005026 /* BB find exact max SMB PDU from sess structure BB */
5027 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 pSMB->MaxSetupCount = 0;
5029 pSMB->Reserved = 0;
5030 pSMB->Flags = 0;
5031 pSMB->Timeout = 0;
5032 pSMB->Reserved2 = 0;
5033 byte_count = params + 1 /* pad */ ;
5034 pSMB->ParameterCount = cpu_to_le16(params);
5035 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005036 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5037 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 pSMB->SetupCount = 1;
5039 pSMB->Reserved3 = 0;
5040 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5041 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005042 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 pSMB->ByteCount = cpu_to_le16(byte_count);
5044
5045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5046 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5047 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005048 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005049 } else { /* decode response */
5050 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5051
Jeff Layton820a8032011-05-04 08:05:26 -04005052 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005053 rc = -EIO; /* bad smb */
5054 } else {
5055 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5056 response_data =
5057 (FILE_SYSTEM_POSIX_INFO
5058 *) (((char *) &pSMBr->hdr.Protocol) +
5059 data_offset);
5060 FSData->f_bsize =
5061 le32_to_cpu(response_data->BlockSize);
5062 FSData->f_blocks =
5063 le64_to_cpu(response_data->TotalBlocks);
5064 FSData->f_bfree =
5065 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005066 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005067 FSData->f_bavail = FSData->f_bfree;
5068 } else {
5069 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005070 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 }
Steve French790fe572007-07-07 19:25:05 +00005072 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005073 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005074 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005075 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005077 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 }
5079 }
5080 cifs_buf_release(pSMB);
5081
5082 if (rc == -EAGAIN)
5083 goto QFSPosixRetry;
5084
5085 return rc;
5086}
5087
5088
Steve French50c2f752007-07-13 00:33:32 +00005089/* We can not use write of zero bytes trick to
5090 set file size due to need for large file support. Also note that
5091 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005092 routine which is only needed to work around a sharing violation bug
5093 in Samba which this routine can run into */
5094
5095int
Steve French96daf2b2011-05-27 04:34:02 +00005096CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005097 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005098 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099{
5100 struct smb_com_transaction2_spi_req *pSMB = NULL;
5101 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5102 struct file_end_of_file_info *parm_data;
5103 int name_len;
5104 int rc = 0;
5105 int bytes_returned = 0;
5106 __u16 params, byte_count, data_count, param_offset, offset;
5107
Joe Perchesb6b38f72010-04-21 03:50:45 +00005108 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109SetEOFRetry:
5110 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5111 (void **) &pSMBr);
5112 if (rc)
5113 return rc;
5114
5115 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5116 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005117 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005118 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005119 name_len++; /* trailing null */
5120 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005121 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 name_len = strnlen(fileName, PATH_MAX);
5123 name_len++; /* trailing null */
5124 strncpy(pSMB->FileName, fileName, name_len);
5125 }
5126 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005127 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005129 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005130 pSMB->MaxSetupCount = 0;
5131 pSMB->Reserved = 0;
5132 pSMB->Flags = 0;
5133 pSMB->Timeout = 0;
5134 pSMB->Reserved2 = 0;
5135 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005136 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005138 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005139 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5140 pSMB->InformationLevel =
5141 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5142 else
5143 pSMB->InformationLevel =
5144 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5145 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5147 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005148 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 else
5150 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005151 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 }
5153
5154 parm_data =
5155 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5156 offset);
5157 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5158 pSMB->DataOffset = cpu_to_le16(offset);
5159 pSMB->SetupCount = 1;
5160 pSMB->Reserved3 = 0;
5161 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5162 byte_count = 3 /* pad */ + params + data_count;
5163 pSMB->DataCount = cpu_to_le16(data_count);
5164 pSMB->TotalDataCount = pSMB->DataCount;
5165 pSMB->ParameterCount = cpu_to_le16(params);
5166 pSMB->TotalParameterCount = pSMB->ParameterCount;
5167 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005168 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005169 parm_data->FileSize = cpu_to_le64(size);
5170 pSMB->ByteCount = cpu_to_le16(byte_count);
5171 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5172 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005173 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005174 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175
5176 cifs_buf_release(pSMB);
5177
5178 if (rc == -EAGAIN)
5179 goto SetEOFRetry;
5180
5181 return rc;
5182}
5183
5184int
Steve French96daf2b2011-05-27 04:34:02 +00005185CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005186 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187{
5188 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 struct file_end_of_file_info *parm_data;
5190 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 __u16 params, param_offset, offset, byte_count, count;
5192
Joe Perchesb6b38f72010-04-21 03:50:45 +00005193 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5194 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005195 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5196
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 if (rc)
5198 return rc;
5199
5200 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5201 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005202
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 params = 6;
5204 pSMB->MaxSetupCount = 0;
5205 pSMB->Reserved = 0;
5206 pSMB->Flags = 0;
5207 pSMB->Timeout = 0;
5208 pSMB->Reserved2 = 0;
5209 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5210 offset = param_offset + params;
5211
Linus Torvalds1da177e2005-04-16 15:20:36 -07005212 count = sizeof(struct file_end_of_file_info);
5213 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005214 /* BB find exact max SMB PDU from sess structure BB */
5215 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005216 pSMB->SetupCount = 1;
5217 pSMB->Reserved3 = 0;
5218 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5219 byte_count = 3 /* pad */ + params + count;
5220 pSMB->DataCount = cpu_to_le16(count);
5221 pSMB->ParameterCount = cpu_to_le16(params);
5222 pSMB->TotalDataCount = pSMB->DataCount;
5223 pSMB->TotalParameterCount = pSMB->ParameterCount;
5224 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5225 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005226 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5227 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228 pSMB->DataOffset = cpu_to_le16(offset);
5229 parm_data->FileSize = cpu_to_le64(size);
5230 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005231 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5233 pSMB->InformationLevel =
5234 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5235 else
5236 pSMB->InformationLevel =
5237 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005238 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5240 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005241 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 else
5243 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005244 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 }
5246 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005247 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005249 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005251 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 }
5253
Steve French50c2f752007-07-13 00:33:32 +00005254 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 since file handle passed in no longer valid */
5256
5257 return rc;
5258}
5259
Steve French50c2f752007-07-13 00:33:32 +00005260/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 an open handle, rather than by pathname - this is awkward due to
5262 potential access conflicts on the open, but it is unavoidable for these
5263 old servers since the only other choice is to go from 100 nanosecond DCE
5264 time and resort to the original setpathinfo level which takes the ancient
5265 DOS time format with 2 second granularity */
5266int
Steve French96daf2b2011-05-27 04:34:02 +00005267CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005268 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269{
5270 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 char *data_offset;
5272 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 __u16 params, param_offset, offset, byte_count, count;
5274
Joe Perchesb6b38f72010-04-21 03:50:45 +00005275 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005276 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5277
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 if (rc)
5279 return rc;
5280
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005281 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5282 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005283
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284 params = 6;
5285 pSMB->MaxSetupCount = 0;
5286 pSMB->Reserved = 0;
5287 pSMB->Flags = 0;
5288 pSMB->Timeout = 0;
5289 pSMB->Reserved2 = 0;
5290 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5291 offset = param_offset + params;
5292
Steve French50c2f752007-07-13 00:33:32 +00005293 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294
Steve French26f57362007-08-30 22:09:15 +00005295 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005296 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005297 /* BB find max SMB PDU from sess */
5298 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 pSMB->SetupCount = 1;
5300 pSMB->Reserved3 = 0;
5301 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5302 byte_count = 3 /* pad */ + params + count;
5303 pSMB->DataCount = cpu_to_le16(count);
5304 pSMB->ParameterCount = cpu_to_le16(params);
5305 pSMB->TotalDataCount = pSMB->DataCount;
5306 pSMB->TotalParameterCount = pSMB->ParameterCount;
5307 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5308 pSMB->DataOffset = cpu_to_le16(offset);
5309 pSMB->Fid = fid;
5310 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5311 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5312 else
5313 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5314 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005315 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005316 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005317 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005318 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005319 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005320 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321
Steve French50c2f752007-07-13 00:33:32 +00005322 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 since file handle passed in no longer valid */
5324
5325 return rc;
5326}
5327
Jeff Layton6d22f092008-09-23 11:48:35 -04005328int
Steve French96daf2b2011-05-27 04:34:02 +00005329CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005330 bool delete_file, __u16 fid, __u32 pid_of_opener)
5331{
5332 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5333 char *data_offset;
5334 int rc = 0;
5335 __u16 params, param_offset, offset, byte_count, count;
5336
Joe Perchesb6b38f72010-04-21 03:50:45 +00005337 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005338 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5339
5340 if (rc)
5341 return rc;
5342
5343 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5344 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5345
5346 params = 6;
5347 pSMB->MaxSetupCount = 0;
5348 pSMB->Reserved = 0;
5349 pSMB->Flags = 0;
5350 pSMB->Timeout = 0;
5351 pSMB->Reserved2 = 0;
5352 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5353 offset = param_offset + params;
5354
5355 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5356
5357 count = 1;
5358 pSMB->MaxParameterCount = cpu_to_le16(2);
5359 /* BB find max SMB PDU from sess */
5360 pSMB->MaxDataCount = cpu_to_le16(1000);
5361 pSMB->SetupCount = 1;
5362 pSMB->Reserved3 = 0;
5363 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5364 byte_count = 3 /* pad */ + params + count;
5365 pSMB->DataCount = cpu_to_le16(count);
5366 pSMB->ParameterCount = cpu_to_le16(params);
5367 pSMB->TotalDataCount = pSMB->DataCount;
5368 pSMB->TotalParameterCount = pSMB->ParameterCount;
5369 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5370 pSMB->DataOffset = cpu_to_le16(offset);
5371 pSMB->Fid = fid;
5372 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5373 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005374 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005375 pSMB->ByteCount = cpu_to_le16(byte_count);
5376 *data_offset = delete_file ? 1 : 0;
5377 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5378 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005379 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005380
5381 return rc;
5382}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005383
5384int
Steve French96daf2b2011-05-27 04:34:02 +00005385CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005386 const char *fileName, const FILE_BASIC_INFO *data,
5387 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388{
5389 TRANSACTION2_SPI_REQ *pSMB = NULL;
5390 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5391 int name_len;
5392 int rc = 0;
5393 int bytes_returned = 0;
5394 char *data_offset;
5395 __u16 params, param_offset, offset, byte_count, count;
5396
Joe Perchesb6b38f72010-04-21 03:50:45 +00005397 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398
5399SetTimesRetry:
5400 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5401 (void **) &pSMBr);
5402 if (rc)
5403 return rc;
5404
5405 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5406 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005407 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005408 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 name_len++; /* trailing null */
5410 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005411 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005412 name_len = strnlen(fileName, PATH_MAX);
5413 name_len++; /* trailing null */
5414 strncpy(pSMB->FileName, fileName, name_len);
5415 }
5416
5417 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005418 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005420 /* BB find max SMB PDU from sess structure BB */
5421 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 pSMB->MaxSetupCount = 0;
5423 pSMB->Reserved = 0;
5424 pSMB->Flags = 0;
5425 pSMB->Timeout = 0;
5426 pSMB->Reserved2 = 0;
5427 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005428 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 offset = param_offset + params;
5430 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5431 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5432 pSMB->DataOffset = cpu_to_le16(offset);
5433 pSMB->SetupCount = 1;
5434 pSMB->Reserved3 = 0;
5435 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5436 byte_count = 3 /* pad */ + params + count;
5437
5438 pSMB->DataCount = cpu_to_le16(count);
5439 pSMB->ParameterCount = cpu_to_le16(params);
5440 pSMB->TotalDataCount = pSMB->DataCount;
5441 pSMB->TotalParameterCount = pSMB->ParameterCount;
5442 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5443 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5444 else
5445 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5446 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005447 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005448 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 pSMB->ByteCount = cpu_to_le16(byte_count);
5450 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5451 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005452 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005453 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454
5455 cifs_buf_release(pSMB);
5456
5457 if (rc == -EAGAIN)
5458 goto SetTimesRetry;
5459
5460 return rc;
5461}
5462
5463/* Can not be used to set time stamps yet (due to old DOS time format) */
5464/* Can be used to set attributes */
5465#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5466 handling it anyway and NT4 was what we thought it would be needed for
5467 Do not delete it until we prove whether needed for Win9x though */
5468int
Steve French96daf2b2011-05-27 04:34:02 +00005469CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470 __u16 dos_attrs, const struct nls_table *nls_codepage)
5471{
5472 SETATTR_REQ *pSMB = NULL;
5473 SETATTR_RSP *pSMBr = NULL;
5474 int rc = 0;
5475 int bytes_returned;
5476 int name_len;
5477
Joe Perchesb6b38f72010-04-21 03:50:45 +00005478 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479
5480SetAttrLgcyRetry:
5481 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5482 (void **) &pSMBr);
5483 if (rc)
5484 return rc;
5485
5486 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5487 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005488 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 PATH_MAX, nls_codepage);
5490 name_len++; /* trailing null */
5491 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005492 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005493 name_len = strnlen(fileName, PATH_MAX);
5494 name_len++; /* trailing null */
5495 strncpy(pSMB->fileName, fileName, name_len);
5496 }
5497 pSMB->attr = cpu_to_le16(dos_attrs);
5498 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005499 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5501 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5502 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005503 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005504 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505
5506 cifs_buf_release(pSMB);
5507
5508 if (rc == -EAGAIN)
5509 goto SetAttrLgcyRetry;
5510
5511 return rc;
5512}
5513#endif /* temporarily unneeded SetAttr legacy function */
5514
Jeff Layton654cf142009-07-09 20:02:49 -04005515static void
5516cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5517 const struct cifs_unix_set_info_args *args)
5518{
5519 u64 mode = args->mode;
5520
5521 /*
5522 * Samba server ignores set of file size to zero due to bugs in some
5523 * older clients, but we should be precise - we use SetFileSize to
5524 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005525 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005526 * zero instead of -1 here
5527 */
5528 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5529 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5530 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5531 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5532 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5533 data_offset->Uid = cpu_to_le64(args->uid);
5534 data_offset->Gid = cpu_to_le64(args->gid);
5535 /* better to leave device as zero when it is */
5536 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5537 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5538 data_offset->Permissions = cpu_to_le64(mode);
5539
5540 if (S_ISREG(mode))
5541 data_offset->Type = cpu_to_le32(UNIX_FILE);
5542 else if (S_ISDIR(mode))
5543 data_offset->Type = cpu_to_le32(UNIX_DIR);
5544 else if (S_ISLNK(mode))
5545 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5546 else if (S_ISCHR(mode))
5547 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5548 else if (S_ISBLK(mode))
5549 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5550 else if (S_ISFIFO(mode))
5551 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5552 else if (S_ISSOCK(mode))
5553 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5554}
5555
Linus Torvalds1da177e2005-04-16 15:20:36 -07005556int
Steve French96daf2b2011-05-27 04:34:02 +00005557CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005558 const struct cifs_unix_set_info_args *args,
5559 u16 fid, u32 pid_of_opener)
5560{
5561 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5562 FILE_UNIX_BASIC_INFO *data_offset;
5563 int rc = 0;
5564 u16 params, param_offset, offset, byte_count, count;
5565
Joe Perchesb6b38f72010-04-21 03:50:45 +00005566 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005567 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5568
5569 if (rc)
5570 return rc;
5571
5572 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5573 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5574
5575 params = 6;
5576 pSMB->MaxSetupCount = 0;
5577 pSMB->Reserved = 0;
5578 pSMB->Flags = 0;
5579 pSMB->Timeout = 0;
5580 pSMB->Reserved2 = 0;
5581 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5582 offset = param_offset + params;
5583
5584 data_offset = (FILE_UNIX_BASIC_INFO *)
5585 ((char *)(&pSMB->hdr.Protocol) + offset);
5586 count = sizeof(FILE_UNIX_BASIC_INFO);
5587
5588 pSMB->MaxParameterCount = cpu_to_le16(2);
5589 /* BB find max SMB PDU from sess */
5590 pSMB->MaxDataCount = cpu_to_le16(1000);
5591 pSMB->SetupCount = 1;
5592 pSMB->Reserved3 = 0;
5593 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5594 byte_count = 3 /* pad */ + params + count;
5595 pSMB->DataCount = cpu_to_le16(count);
5596 pSMB->ParameterCount = cpu_to_le16(params);
5597 pSMB->TotalDataCount = pSMB->DataCount;
5598 pSMB->TotalParameterCount = pSMB->ParameterCount;
5599 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5600 pSMB->DataOffset = cpu_to_le16(offset);
5601 pSMB->Fid = fid;
5602 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5603 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005604 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005605 pSMB->ByteCount = cpu_to_le16(byte_count);
5606
5607 cifs_fill_unix_set_info(data_offset, args);
5608
5609 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5610 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005611 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005612
5613 /* Note: On -EAGAIN error only caller can retry on handle based calls
5614 since file handle passed in no longer valid */
5615
5616 return rc;
5617}
5618
5619int
Steve French96daf2b2011-05-27 04:34:02 +00005620CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005621 const struct cifs_unix_set_info_args *args,
5622 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005623{
5624 TRANSACTION2_SPI_REQ *pSMB = NULL;
5625 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5626 int name_len;
5627 int rc = 0;
5628 int bytes_returned = 0;
5629 FILE_UNIX_BASIC_INFO *data_offset;
5630 __u16 params, param_offset, offset, count, byte_count;
5631
Joe Perchesb6b38f72010-04-21 03:50:45 +00005632 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633setPermsRetry:
5634 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5635 (void **) &pSMBr);
5636 if (rc)
5637 return rc;
5638
5639 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5640 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005641 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005642 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 name_len++; /* trailing null */
5644 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005645 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 name_len = strnlen(fileName, PATH_MAX);
5647 name_len++; /* trailing null */
5648 strncpy(pSMB->FileName, fileName, name_len);
5649 }
5650
5651 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005652 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005653 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005654 /* BB find max SMB PDU from sess structure BB */
5655 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005656 pSMB->MaxSetupCount = 0;
5657 pSMB->Reserved = 0;
5658 pSMB->Flags = 0;
5659 pSMB->Timeout = 0;
5660 pSMB->Reserved2 = 0;
5661 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005662 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005663 offset = param_offset + params;
5664 data_offset =
5665 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5666 offset);
5667 memset(data_offset, 0, count);
5668 pSMB->DataOffset = cpu_to_le16(offset);
5669 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5670 pSMB->SetupCount = 1;
5671 pSMB->Reserved3 = 0;
5672 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5673 byte_count = 3 /* pad */ + params + count;
5674 pSMB->ParameterCount = cpu_to_le16(params);
5675 pSMB->DataCount = cpu_to_le16(count);
5676 pSMB->TotalParameterCount = pSMB->ParameterCount;
5677 pSMB->TotalDataCount = pSMB->DataCount;
5678 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5679 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005680 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005681
Jeff Layton654cf142009-07-09 20:02:49 -04005682 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683
5684 pSMB->ByteCount = cpu_to_le16(byte_count);
5685 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5686 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005687 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005688 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689
Steve French0d817bc2008-05-22 02:02:03 +00005690 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005691 if (rc == -EAGAIN)
5692 goto setPermsRetry;
5693 return rc;
5694}
5695
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005697/*
5698 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5699 * function used by listxattr and getxattr type calls. When ea_name is set,
5700 * it looks for that attribute name and stuffs that value into the EAData
5701 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5702 * buffer. In both cases, the return value is either the length of the
5703 * resulting data or a negative error code. If EAData is a NULL pointer then
5704 * the data isn't copied to it, but the length is returned.
5705 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005706ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00005707CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005708 const unsigned char *searchName, const unsigned char *ea_name,
5709 char *EAData, size_t buf_size,
5710 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711{
5712 /* BB assumes one setup word */
5713 TRANSACTION2_QPI_REQ *pSMB = NULL;
5714 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5715 int rc = 0;
5716 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005717 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005718 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005719 struct fea *temp_fea;
5720 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005721 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005722 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723
Joe Perchesb6b38f72010-04-21 03:50:45 +00005724 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005725QAllEAsRetry:
5726 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5727 (void **) &pSMBr);
5728 if (rc)
5729 return rc;
5730
5731 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005732 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005733 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005734 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005735 list_len++; /* trailing null */
5736 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005738 list_len = strnlen(searchName, PATH_MAX);
5739 list_len++; /* trailing null */
5740 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 }
5742
Jeff Layton6e462b92010-02-10 16:18:26 -05005743 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005744 pSMB->TotalDataCount = 0;
5745 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005746 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005747 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 pSMB->MaxSetupCount = 0;
5749 pSMB->Reserved = 0;
5750 pSMB->Flags = 0;
5751 pSMB->Timeout = 0;
5752 pSMB->Reserved2 = 0;
5753 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005754 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005755 pSMB->DataCount = 0;
5756 pSMB->DataOffset = 0;
5757 pSMB->SetupCount = 1;
5758 pSMB->Reserved3 = 0;
5759 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5760 byte_count = params + 1 /* pad */ ;
5761 pSMB->TotalParameterCount = cpu_to_le16(params);
5762 pSMB->ParameterCount = pSMB->TotalParameterCount;
5763 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5764 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005765 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 pSMB->ByteCount = cpu_to_le16(byte_count);
5767
5768 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5769 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5770 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005771 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005772 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005774
5775
5776 /* BB also check enough total bytes returned */
5777 /* BB we need to improve the validity checking
5778 of these trans2 responses */
5779
5780 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005781 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005782 rc = -EIO; /* bad smb */
5783 goto QAllEAsOut;
5784 }
5785
5786 /* check that length of list is not more than bcc */
5787 /* check that each entry does not go beyond length
5788 of list */
5789 /* check that each element of each entry does not
5790 go beyond end of list */
5791 /* validate_trans2_offsets() */
5792 /* BB check if start of smb + data_offset > &bcc+ bcc */
5793
5794 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5795 ea_response_data = (struct fealist *)
5796 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5797
Jeff Layton6e462b92010-02-10 16:18:26 -05005798 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005799 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005800 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005801 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005802 goto QAllEAsOut;
5803 }
5804
Jeff Layton0cd126b2010-02-10 16:18:26 -05005805 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005806 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005807 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005808 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005809 rc = -EIO;
5810 goto QAllEAsOut;
5811 }
5812
Jeff Laytonf0d38682010-02-10 16:18:26 -05005813 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005814 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005815 temp_fea = ea_response_data->list;
5816 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005817 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005818 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005819 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005820
Jeff Layton6e462b92010-02-10 16:18:26 -05005821 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005822 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005823 /* make sure we can read name_len and value_len */
5824 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005825 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005826 rc = -EIO;
5827 goto QAllEAsOut;
5828 }
5829
5830 name_len = temp_fea->name_len;
5831 value_len = le16_to_cpu(temp_fea->value_len);
5832 list_len -= name_len + 1 + value_len;
5833 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005834 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005835 rc = -EIO;
5836 goto QAllEAsOut;
5837 }
5838
Jeff Layton31c05192010-02-10 16:18:26 -05005839 if (ea_name) {
5840 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5841 temp_ptr += name_len + 1;
5842 rc = value_len;
5843 if (buf_size == 0)
5844 goto QAllEAsOut;
5845 if ((size_t)value_len > buf_size) {
5846 rc = -ERANGE;
5847 goto QAllEAsOut;
5848 }
5849 memcpy(EAData, temp_ptr, value_len);
5850 goto QAllEAsOut;
5851 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005852 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005853 /* account for prefix user. and trailing null */
5854 rc += (5 + 1 + name_len);
5855 if (rc < (int) buf_size) {
5856 memcpy(EAData, "user.", 5);
5857 EAData += 5;
5858 memcpy(EAData, temp_ptr, name_len);
5859 EAData += name_len;
5860 /* null terminate name */
5861 *EAData = 0;
5862 ++EAData;
5863 } else if (buf_size == 0) {
5864 /* skip copy - calc size only */
5865 } else {
5866 /* stop before overrun buffer */
5867 rc = -ERANGE;
5868 break;
5869 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005870 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005871 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005872 temp_fea = (struct fea *)temp_ptr;
5873 }
5874
Jeff Layton31c05192010-02-10 16:18:26 -05005875 /* didn't find the named attribute */
5876 if (ea_name)
5877 rc = -ENODATA;
5878
Jeff Laytonf0d38682010-02-10 16:18:26 -05005879QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005880 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881 if (rc == -EAGAIN)
5882 goto QAllEAsRetry;
5883
5884 return (ssize_t)rc;
5885}
5886
Linus Torvalds1da177e2005-04-16 15:20:36 -07005887int
Steve French96daf2b2011-05-27 04:34:02 +00005888CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005889 const char *ea_name, const void *ea_value,
5890 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5891 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892{
5893 struct smb_com_transaction2_spi_req *pSMB = NULL;
5894 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5895 struct fealist *parm_data;
5896 int name_len;
5897 int rc = 0;
5898 int bytes_returned = 0;
5899 __u16 params, param_offset, byte_count, offset, count;
5900
Joe Perchesb6b38f72010-04-21 03:50:45 +00005901 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005902SetEARetry:
5903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5904 (void **) &pSMBr);
5905 if (rc)
5906 return rc;
5907
5908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5909 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005910 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005911 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005912 name_len++; /* trailing null */
5913 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005914 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915 name_len = strnlen(fileName, PATH_MAX);
5916 name_len++; /* trailing null */
5917 strncpy(pSMB->FileName, fileName, name_len);
5918 }
5919
5920 params = 6 + name_len;
5921
5922 /* done calculating parms using name_len of file name,
5923 now use name_len to calculate length of ea name
5924 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005925 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005926 name_len = 0;
5927 else
Steve French50c2f752007-07-13 00:33:32 +00005928 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005930 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005932 /* BB find max SMB PDU from sess */
5933 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934 pSMB->MaxSetupCount = 0;
5935 pSMB->Reserved = 0;
5936 pSMB->Flags = 0;
5937 pSMB->Timeout = 0;
5938 pSMB->Reserved2 = 0;
5939 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005940 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941 offset = param_offset + params;
5942 pSMB->InformationLevel =
5943 cpu_to_le16(SMB_SET_FILE_EA);
5944
5945 parm_data =
5946 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5947 offset);
5948 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5949 pSMB->DataOffset = cpu_to_le16(offset);
5950 pSMB->SetupCount = 1;
5951 pSMB->Reserved3 = 0;
5952 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5953 byte_count = 3 /* pad */ + params + count;
5954 pSMB->DataCount = cpu_to_le16(count);
5955 parm_data->list_len = cpu_to_le32(count);
5956 parm_data->list[0].EA_flags = 0;
5957 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005958 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005959 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005960 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005961 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005962 parm_data->list[0].name[name_len] = 0;
5963 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5964 /* caller ensures that ea_value_len is less than 64K but
5965 we need to ensure that it fits within the smb */
5966
Steve French50c2f752007-07-13 00:33:32 +00005967 /*BB add length check to see if it would fit in
5968 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005969 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5970 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005971 memcpy(parm_data->list[0].name+name_len+1,
5972 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973
5974 pSMB->TotalDataCount = pSMB->DataCount;
5975 pSMB->ParameterCount = cpu_to_le16(params);
5976 pSMB->TotalParameterCount = pSMB->ParameterCount;
5977 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005978 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005979 pSMB->ByteCount = cpu_to_le16(byte_count);
5980 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5981 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005982 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005983 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984
5985 cifs_buf_release(pSMB);
5986
5987 if (rc == -EAGAIN)
5988 goto SetEARetry;
5989
5990 return rc;
5991}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005992#endif
Steve French0eff0e22011-02-24 05:39:23 +00005993
5994#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5995/*
5996 * Years ago the kernel added a "dnotify" function for Samba server,
5997 * to allow network clients (such as Windows) to display updated
5998 * lists of files in directory listings automatically when
5999 * files are added by one user when another user has the
6000 * same directory open on their desktop. The Linux cifs kernel
6001 * client hooked into the kernel side of this interface for
6002 * the same reason, but ironically when the VFS moved from
6003 * "dnotify" to "inotify" it became harder to plug in Linux
6004 * network file system clients (the most obvious use case
6005 * for notify interfaces is when multiple users can update
6006 * the contents of the same directory - exactly what network
6007 * file systems can do) although the server (Samba) could
6008 * still use it. For the short term we leave the worker
6009 * function ifdeffed out (below) until inotify is fixed
6010 * in the VFS to make it easier to plug in network file
6011 * system clients. If inotify turns out to be permanently
6012 * incompatible for network fs clients, we could instead simply
6013 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6014 */
Steve French96daf2b2011-05-27 04:34:02 +00006015int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006016 const int notify_subdirs, const __u16 netfid,
6017 __u32 filter, struct file *pfile, int multishot,
6018 const struct nls_table *nls_codepage)
6019{
6020 int rc = 0;
6021 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6022 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6023 struct dir_notify_req *dnotify_req;
6024 int bytes_returned;
6025
6026 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6027 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6028 (void **) &pSMBr);
6029 if (rc)
6030 return rc;
6031
6032 pSMB->TotalParameterCount = 0 ;
6033 pSMB->TotalDataCount = 0;
6034 pSMB->MaxParameterCount = cpu_to_le32(2);
6035 /* BB find exact data count max from sess structure BB */
6036 pSMB->MaxDataCount = 0; /* same in little endian or be */
6037/* BB VERIFY verify which is correct for above BB */
6038 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
6039 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
6040
6041 pSMB->MaxSetupCount = 4;
6042 pSMB->Reserved = 0;
6043 pSMB->ParameterOffset = 0;
6044 pSMB->DataCount = 0;
6045 pSMB->DataOffset = 0;
6046 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6047 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6048 pSMB->ParameterCount = pSMB->TotalParameterCount;
6049 if (notify_subdirs)
6050 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6051 pSMB->Reserved2 = 0;
6052 pSMB->CompletionFilter = cpu_to_le32(filter);
6053 pSMB->Fid = netfid; /* file handle always le */
6054 pSMB->ByteCount = 0;
6055
6056 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6057 (struct smb_hdr *)pSMBr, &bytes_returned,
6058 CIFS_ASYNC_OP);
6059 if (rc) {
6060 cFYI(1, "Error in Notify = %d", rc);
6061 } else {
6062 /* Add file to outstanding requests */
6063 /* BB change to kmem cache alloc */
6064 dnotify_req = kmalloc(
6065 sizeof(struct dir_notify_req),
6066 GFP_KERNEL);
6067 if (dnotify_req) {
6068 dnotify_req->Pid = pSMB->hdr.Pid;
6069 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6070 dnotify_req->Mid = pSMB->hdr.Mid;
6071 dnotify_req->Tid = pSMB->hdr.Tid;
6072 dnotify_req->Uid = pSMB->hdr.Uid;
6073 dnotify_req->netfid = netfid;
6074 dnotify_req->pfile = pfile;
6075 dnotify_req->filter = filter;
6076 dnotify_req->multishot = multishot;
6077 spin_lock(&GlobalMid_Lock);
6078 list_add_tail(&dnotify_req->lhead,
6079 &GlobalDnotifyReqList);
6080 spin_unlock(&GlobalMid_Lock);
6081 } else
6082 rc = -ENOMEM;
6083 }
6084 cifs_buf_release(pSMB);
6085 return rc;
6086}
6087#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */