blob: 602326fa4a4f5b3e35d6225be0f10387277a1638 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include "cifspdu.h"
38#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000039#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "cifsproto.h"
41#include "cifs_unicode.h"
42#include "cifs_debug.h"
43
44#ifdef CONFIG_CIFS_POSIX
45static struct {
46 int index;
47 char *name;
48} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000049#ifdef CONFIG_CIFS_WEAK_PW_HASH
50 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000051 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000052#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000053 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000054 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 {BAD_PROT, "\2"}
56};
57#else
58static struct {
59 int index;
60 char *name;
61} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000062#ifdef CONFIG_CIFS_WEAK_PW_HASH
63 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000064 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000065#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000066 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 {BAD_PROT, "\2"}
68};
69#endif
70
Steve French39798772006-05-31 22:40:51 +000071/* define the number of elements in the cifs dialect array */
72#ifdef CONFIG_CIFS_POSIX
73#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000074#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000075#else
76#define CIFS_NUM_PROT 2
77#endif /* CIFS_WEAK_PW_HASH */
78#else /* not posix */
79#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000080#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000081#else
82#define CIFS_NUM_PROT 1
83#endif /* CONFIG_CIFS_WEAK_PW_HASH */
84#endif /* CIFS_POSIX */
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086/* Mark as invalid, all open files on tree connections since they
87 were closed when session to server was lost */
Steve French96daf2b2011-05-27 04:34:02 +000088static void mark_open_files_invalid(struct cifs_tcon *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
90 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000091 struct list_head *tmp;
92 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -040095 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000097 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000098 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040099 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 }
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
Jeff Layton9162ab22009-09-03 12:07:17 -0400106/* reconnect the socket, tcon, and smb session if needed */
107static int
Steve French96daf2b2011-05-27 04:34:02 +0000108cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
Jeff Layton9162ab22009-09-03 12:07:17 -0400109{
Jeff Laytonc4a55342011-07-28 12:40:36 -0400110 int rc;
Steve French96daf2b2011-05-27 04:34:02 +0000111 struct cifs_ses *ses;
Jeff Layton9162ab22009-09-03 12:07:17 -0400112 struct TCP_Server_Info *server;
113 struct nls_table *nls_codepage;
114
115 /*
116 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
117 * tcp and smb session status done differently for those three - in the
118 * calling routine
119 */
120 if (!tcon)
121 return 0;
122
123 ses = tcon->ses;
124 server = ses->server;
125
126 /*
127 * only tree disconnect, open, and write, (and ulogoff which does not
128 * have tcon) are allowed as we start force umount
129 */
130 if (tcon->tidStatus == CifsExiting) {
131 if (smb_command != SMB_COM_WRITE_ANDX &&
132 smb_command != SMB_COM_OPEN_ANDX &&
133 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000134 cFYI(1, "can not send cmd %d while umounting",
135 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400136 return -ENODEV;
137 }
138 }
139
Jeff Layton9162ab22009-09-03 12:07:17 -0400140 /*
141 * Give demultiplex thread up to 10 seconds to reconnect, should be
142 * greater than cifs socket timeout which is 7 seconds
143 */
144 while (server->tcpStatus == CifsNeedReconnect) {
145 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000146 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400147
Steve Frenchfd88ce92011-04-12 01:01:14 +0000148 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400149 if (server->tcpStatus != CifsNeedReconnect)
150 break;
151
152 /*
153 * on "soft" mounts we wait once. Hard mounts keep
154 * retrying until process is killed or server comes
155 * back on-line
156 */
Jeff Laytond4025392011-02-07 08:54:35 -0500157 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000158 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400159 return -EHOSTDOWN;
160 }
161 }
162
163 if (!ses->need_reconnect && !tcon->need_reconnect)
164 return 0;
165
166 nls_codepage = load_nls_default();
167
168 /*
169 * need to prevent multiple threads trying to simultaneously
170 * reconnect the same SMB session
171 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000172 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400173 rc = cifs_negotiate_protocol(0, ses);
174 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400175 rc = cifs_setup_session(0, ses, nls_codepage);
176
177 /* do we need to reconnect tcon? */
178 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000179 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400180 goto out;
181 }
182
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000185 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000186 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400187
188 if (rc)
189 goto out;
190
191 /*
192 * FIXME: check if wsize needs updated due to negotiated smb buffer
193 * size shrinking
194 */
195 atomic_inc(&tconInfoReconnectCount);
196
197 /* tell server Unix caps we support */
198 if (ses->capabilities & CAP_UNIX)
199 reset_cifs_unix_caps(0, tcon, NULL, NULL);
200
201 /*
202 * Removed call to reopen open files here. It is safer (and faster) to
203 * reopen files one at a time as needed in read and write.
204 *
205 * FIXME: what about file locks? don't we need to reclaim them ASAP?
206 */
207
208out:
209 /*
210 * Check if handle based operation so we know whether we can continue
211 * or not without returning to caller to reset file handle
212 */
213 switch (smb_command) {
214 case SMB_COM_READ_ANDX:
215 case SMB_COM_WRITE_ANDX:
216 case SMB_COM_CLOSE:
217 case SMB_COM_FIND_CLOSE2:
218 case SMB_COM_LOCKING_ANDX:
219 rc = -EAGAIN;
220 }
221
222 unload_nls(nls_codepage);
223 return rc;
224}
225
Steve Frenchad7a2922008-02-07 23:25:02 +0000226/* Allocate and return pointer to an SMB request buffer, and set basic
227 SMB information in the SMB header. If the return code is zero, this
228 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229static int
Steve French96daf2b2011-05-27 04:34:02 +0000230small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000231 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
Jeff Laytonf5695992010-09-29 15:27:08 -0400233 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Jeff Layton9162ab22009-09-03 12:07:17 -0400235 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000236 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return rc;
238
239 *request_buf = cifs_small_buf_get();
240 if (*request_buf == NULL) {
241 /* BB should we add a retry in here if not a writepage? */
242 return -ENOMEM;
243 }
244
Steve French63135e02007-07-17 17:34:02 +0000245 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000246 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Steve French790fe572007-07-07 19:25:05 +0000248 if (tcon != NULL)
249 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700250
Jeff Laytonf5695992010-09-29 15:27:08 -0400251 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000252}
253
Steve French12b3b8f2006-02-09 21:12:47 +0000254int
Steve French50c2f752007-07-13 00:33:32 +0000255small_smb_init_no_tc(const int smb_command, const int wct,
Steve French96daf2b2011-05-27 04:34:02 +0000256 struct cifs_ses *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000257{
258 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000259 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000260
Steve French5815449d2006-02-14 01:36:20 +0000261 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000262 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000263 return rc;
264
Steve French04fdabe2006-02-10 05:52:50 +0000265 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000266 buffer->Mid = GetNextMid(ses->server);
267 if (ses->capabilities & CAP_UNICODE)
268 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000269 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000270 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
271
272 /* uid, tid can stay at zero as set in header assemble */
273
Steve French50c2f752007-07-13 00:33:32 +0000274 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000275 this function is used after 1st of session setup requests */
276
277 return rc;
278}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280/* If the return code is zero, this function must fill in request_buf pointer */
281static int
Steve French96daf2b2011-05-27 04:34:02 +0000282__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400283 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 *request_buf = cifs_buf_get();
286 if (*request_buf == NULL) {
287 /* BB should we add a retry in here if not a writepage? */
288 return -ENOMEM;
289 }
290 /* Although the original thought was we needed the response buf for */
291 /* potential retries of smb operations it turns out we can determine */
292 /* from the mid flags when the request buffer can be resent without */
293 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000294 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000295 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000298 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Steve French790fe572007-07-07 19:25:05 +0000300 if (tcon != NULL)
301 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700302
Jeff Laytonf5695992010-09-29 15:27:08 -0400303 return 0;
304}
305
306/* If the return code is zero, this function must fill in request_buf pointer */
307static int
Steve French96daf2b2011-05-27 04:34:02 +0000308smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400309 void **request_buf, void **response_buf)
310{
311 int rc;
312
313 rc = cifs_reconnect_tcon(tcon, smb_command);
314 if (rc)
315 return rc;
316
317 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
318}
319
320static int
Steve French96daf2b2011-05-27 04:34:02 +0000321smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
Jeff Laytonf5695992010-09-29 15:27:08 -0400322 void **request_buf, void **response_buf)
323{
324 if (tcon->ses->need_reconnect || tcon->need_reconnect)
325 return -EHOSTDOWN;
326
327 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328}
329
Steve French50c2f752007-07-13 00:33:32 +0000330static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
Jeff Layton12df83c2011-01-20 13:36:51 -0500332 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jeff Layton12df83c2011-01-20 13:36:51 -0500334 /* check for plausible wct */
335 if (pSMB->hdr.WordCount < 10)
336 goto vt2_err;
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500339 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
340 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
341 goto vt2_err;
342
Jeff Layton12df83c2011-01-20 13:36:51 -0500343 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
344 if (total_size >= 512)
345 goto vt2_err;
346
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400347 /* check that bcc is at least as big as parms + data, and that it is
348 * less than negotiated smb buffer
349 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500350 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
351 if (total_size > get_bcc(&pSMB->hdr) ||
352 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
353 goto vt2_err;
354
355 return 0;
356vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000357 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500359 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
Jeff Layton690c5222011-01-20 13:36:51 -0500361
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000362static inline void inc_rfc1001_len(void *pSMB, int count)
363{
364 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
365
366 be32_add_cpu(&hdr->smb_buf_length, count);
367}
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369int
Steve French96daf2b2011-05-27 04:34:02 +0000370CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
372 NEGOTIATE_REQ *pSMB;
373 NEGOTIATE_RSP *pSMBr;
374 int rc = 0;
375 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000376 int i;
Steve French50c2f752007-07-13 00:33:32 +0000377 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000379 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Steve French790fe572007-07-07 19:25:05 +0000381 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 server = ses->server;
383 else {
384 rc = -EIO;
385 return rc;
386 }
387 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
388 (void **) &pSMB, (void **) &pSMBr);
389 if (rc)
390 return rc;
Steve French750d1152006-06-27 06:28:30 +0000391
392 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000393 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000394 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000395 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400396 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000397
Joe Perchesb6b38f72010-04-21 03:50:45 +0000398 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000399
Steve French1982c342005-08-17 12:38:22 -0700400 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000401 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000402
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000403 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000404 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000405 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000406 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000407 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500408 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000409 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
410 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000411 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000412 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
413 }
Steve French50c2f752007-07-13 00:33:32 +0000414
Steve French39798772006-05-31 22:40:51 +0000415 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000416 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000417 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
418 count += strlen(protocols[i].name) + 1;
419 /* null at end of source and target buffers anyway */
420 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000421 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 pSMB->ByteCount = cpu_to_le16(count);
423
424 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000426 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000427 goto neg_err_exit;
428
Jeff Layton9bf67e52010-04-24 07:57:46 -0400429 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
430 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000431 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400432 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000433 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000434 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000435 could not negotiate a common dialect */
436 rc = -EOPNOTSUPP;
437 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000438#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000439 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400440 && ((server->dialect == LANMAN_PROT)
441 || (server->dialect == LANMAN2_PROT))) {
Steve 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);
Jeff Laytonc974bef2011-10-11 06:41:32 -0400456 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000457 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000458 /* even though we do not use raw we might as well set this
459 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000460 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000461 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000462 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
463 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000464 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000465 server->capabilities = CAP_MPX_MODE;
466 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000467 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000468 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000469 /* OS/2 often does not set timezone therefore
470 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 * Could deviate slightly from the right zone.
472 * Smallest defined timezone difference is 15 minutes
473 * (i.e. Nepal). Rounding up/down is done to match
474 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000475 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000477 struct timespec ts, utc;
478 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400479 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
480 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000481 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000482 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000483 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000484 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000485 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000486 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000487 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000488 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000489 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000490 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000491 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000492 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000493 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000494 server->timeAdj = (int)tmp;
495 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000496 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000497 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000498
Steve French39798772006-05-31 22:40:51 +0000499
Steve French254e55e2006-06-04 05:53:15 +0000500 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000501 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000502
Steve French50c2f752007-07-13 00:33:32 +0000503 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000504 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500505 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000506 CIFS_CRYPTO_KEY_SIZE);
Steve French96daf2b2011-05-27 04:34:02 +0000507 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French254e55e2006-06-04 05:53:15 +0000508 rc = -EIO; /* need cryptkey unless plain text */
509 goto neg_err_exit;
510 }
Steve French39798772006-05-31 22:40:51 +0000511
Steve Frenchf19159d2010-04-21 04:12:10 +0000512 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000513 /* we will not end up setting signing flags - as no signing
514 was in LANMAN and server did not return the flags on */
515 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000516#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000517 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000518 cERROR(1, "mount failed, cifs module not built "
519 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300520 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000521#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000522 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000523 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000524 /* unknown wct */
525 rc = -EOPNOTSUPP;
526 goto neg_err_exit;
527 }
528 /* else wct == 17 NTLM */
Steve French96daf2b2011-05-27 04:34:02 +0000529 server->sec_mode = pSMBr->SecurityMode;
530 if ((server->sec_mode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000531 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000532
Steve French96daf2b2011-05-27 04:34:02 +0000533 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000534#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000535 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000536#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000537 cERROR(1, "Server requests plain text password"
538 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000539
Steve French790fe572007-07-07 19:25:05 +0000540 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000541 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000542 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000543 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000544 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000545 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000546 else if (secFlags & CIFSSEC_MAY_KRB5)
547 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000548 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000549 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000550 else if (secFlags & CIFSSEC_MAY_LANMAN)
551 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000552 else {
553 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000554 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000555 goto neg_err_exit;
556 }
557 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000558
Steve French254e55e2006-06-04 05:53:15 +0000559 /* one byte, so no need to convert this or EncryptionKeyLen from
560 little endian */
561 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
562 /* probably no need to store and check maxvcs */
Jeff Laytonc974bef2011-10-11 06:41:32 -0400563 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
Steve Frencheca6acf2009-02-20 05:43:09 +0000564 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000565 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000566 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000567 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
568 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000569 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500570 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000571 CIFS_CRYPTO_KEY_SIZE);
Steve French07cc6cf2011-05-27 04:12:29 +0000572 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
573 server->capabilities & CAP_EXTENDED_SECURITY) &&
574 (pSMBr->EncryptionKeyLength == 0)) {
Steve French254e55e2006-06-04 05:53:15 +0000575 /* decode security blob */
Jeff Layton820a8032011-05-04 08:05:26 -0400576 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000577 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000579 goto neg_err_exit;
580 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530581 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500582 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530583 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000584 if (memcmp(server->server_GUID,
585 pSMBr->u.extended_response.
586 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000587 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000588 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000589 pSMBr->u.extended_response.GUID,
590 16);
591 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500592 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530593 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000594 memcpy(server->server_GUID,
595 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500596 }
Jeff Laytone187e442007-10-16 17:10:44 +0000597
598 if (count == 16) {
599 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000600 } else {
601 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400602 SecurityBlob, count - 16,
603 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000604 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000605 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000606 else
Steve French254e55e2006-06-04 05:53:15 +0000607 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500608 if (server->secType == Kerberos) {
609 if (!server->sec_kerberos &&
610 !server->sec_mskerberos)
611 rc = -EOPNOTSUPP;
612 } else if (server->secType == RawNTLMSSP) {
613 if (!server->sec_ntlmssp)
614 rc = -EOPNOTSUPP;
615 } else
616 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
Steve French96daf2b2011-05-27 04:34:02 +0000618 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
Steve French07cc6cf2011-05-27 04:12:29 +0000619 rc = -EIO; /* no crypt key only if plain text pwd */
620 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000621 } else
622 server->capabilities &= ~CAP_EXTENDED_SECURITY;
623
Steve French6344a422006-06-12 04:18:35 +0000624#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000625signing_check:
Steve French6344a422006-06-12 04:18:35 +0000626#endif
Steve French762e5ab2007-06-28 18:41:42 +0000627 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
628 /* MUST_SIGN already includes the MAY_SIGN FLAG
629 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000630 cFYI(1, "Signing disabled");
Steve French96daf2b2011-05-27 04:34:02 +0000631 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000632 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000633 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000634 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000635 rc = -EOPNOTSUPP;
636 }
Steve French96daf2b2011-05-27 04:34:02 +0000637 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000638 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000639 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
640 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French96daf2b2011-05-27 04:34:02 +0000642 if ((server->sec_mode &
Steve French762e5ab2007-06-28 18:41:42 +0000643 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000644 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000645 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else
Steve French96daf2b2011-05-27 04:34:02 +0000647 server->sec_mode |= SECMODE_SIGN_REQUIRED;
Steve French762e5ab2007-06-28 18:41:42 +0000648 } else {
649 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French96daf2b2011-05-27 04:34:02 +0000650 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
651 server->sec_mode &=
Steve French254e55e2006-06-04 05:53:15 +0000652 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Steve French50c2f752007-07-13 00:33:32 +0000654
655neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700656 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000657
Joe Perchesb6b38f72010-04-21 03:50:45 +0000658 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 return rc;
660}
661
662int
Steve French96daf2b2011-05-27 04:34:02 +0000663CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
665 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Joe Perchesb6b38f72010-04-21 03:50:45 +0000668 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500669
670 /* BB: do we need to check this? These should never be NULL. */
671 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
672 return -EIO;
673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500675 * No need to return error on this operation if tid invalidated and
676 * closed on server already e.g. due to tcp session crashing. Also,
677 * the tcon is no longer on the list, so no need to take lock before
678 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 */
Steve French268875b2009-06-25 00:29:21 +0000680 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Steve French50c2f752007-07-13 00:33:32 +0000683 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700684 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500685 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 return rc;
Steve French133672e2007-11-13 22:41:37 +0000687
688 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000690 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Steve French50c2f752007-07-13 00:33:32 +0000692 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500693 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (rc == -EAGAIN)
695 rc = 0;
696
697 return rc;
698}
699
Jeff Layton766fdbb2011-01-11 07:24:21 -0500700/*
701 * This is a no-op for now. We're not really interested in the reply, but
702 * rather in the fact that the server sent one and that server->lstrp
703 * gets updated.
704 *
705 * FIXME: maybe we should consider checking that the reply matches request?
706 */
707static void
708cifs_echo_callback(struct mid_q_entry *mid)
709{
710 struct TCP_Server_Info *server = mid->callback_data;
711
712 DeleteMidQEntry(mid);
713 atomic_dec(&server->inFlight);
714 wake_up(&server->request_q);
715}
716
717int
718CIFSSMBEcho(struct TCP_Server_Info *server)
719{
720 ECHO_REQ *smb;
721 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400722 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500723
724 cFYI(1, "In echo request");
725
726 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
727 if (rc)
728 return rc;
729
730 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000731 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500732 smb->hdr.WordCount = 1;
733 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400734 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500735 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000736 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400737 iov.iov_base = smb;
738 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500739
Jeff Layton59ffd842011-05-19 16:22:55 -0400740 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500741 if (rc)
742 cFYI(1, "Echo request failed: %d", rc);
743
744 cifs_small_buf_release(smb);
745
746 return rc;
747}
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749int
Steve French96daf2b2011-05-27 04:34:02 +0000750CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 LOGOFF_ANDX_REQ *pSMB;
753 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Joe Perchesb6b38f72010-04-21 03:50:45 +0000755 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500756
757 /*
758 * BB: do we need to check validity of ses and server? They should
759 * always be valid since we have an active reference. If not, that
760 * should probably be a BUG()
761 */
762 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 return -EIO;
764
Steve Frenchd7b619c2010-02-25 05:36:46 +0000765 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000766 if (ses->need_reconnect)
767 goto session_already_dead; /* no need to send SMBlogoff if uid
768 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
770 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000771 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 return rc;
773 }
774
Steve French3b795212008-11-13 19:45:32 +0000775 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700776
Steve French96daf2b2011-05-27 04:34:02 +0000777 if (ses->server->sec_mode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
779 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 pSMB->hdr.Uid = ses->Suid;
782
783 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000784 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000785session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000786 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000789 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 error */
791 if (rc == -EAGAIN)
792 rc = 0;
793 return rc;
794}
795
796int
Steve French96daf2b2011-05-27 04:34:02 +0000797CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French2d785a52007-07-15 01:48:57 +0000798 __u16 type, const struct nls_table *nls_codepage, int remap)
799{
800 TRANSACTION2_SPI_REQ *pSMB = NULL;
801 TRANSACTION2_SPI_RSP *pSMBr = NULL;
802 struct unlink_psx_rq *pRqD;
803 int name_len;
804 int rc = 0;
805 int bytes_returned = 0;
806 __u16 params, param_offset, offset, byte_count;
807
Joe Perchesb6b38f72010-04-21 03:50:45 +0000808 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000809PsxDelete:
810 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
811 (void **) &pSMBr);
812 if (rc)
813 return rc;
814
815 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
816 name_len =
817 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
818 PATH_MAX, nls_codepage, remap);
819 name_len++; /* trailing null */
820 name_len *= 2;
821 } else { /* BB add path length overrun check */
822 name_len = strnlen(fileName, PATH_MAX);
823 name_len++; /* trailing null */
824 strncpy(pSMB->FileName, fileName, name_len);
825 }
826
827 params = 6 + name_len;
828 pSMB->MaxParameterCount = cpu_to_le16(2);
829 pSMB->MaxDataCount = 0; /* BB double check this with jra */
830 pSMB->MaxSetupCount = 0;
831 pSMB->Reserved = 0;
832 pSMB->Flags = 0;
833 pSMB->Timeout = 0;
834 pSMB->Reserved2 = 0;
835 param_offset = offsetof(struct smb_com_transaction2_spi_req,
836 InformationLevel) - 4;
837 offset = param_offset + params;
838
839 /* Setup pointer to Request Data (inode type) */
840 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
841 pRqD->type = cpu_to_le16(type);
842 pSMB->ParameterOffset = cpu_to_le16(param_offset);
843 pSMB->DataOffset = cpu_to_le16(offset);
844 pSMB->SetupCount = 1;
845 pSMB->Reserved3 = 0;
846 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
847 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
848
849 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
850 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
851 pSMB->ParameterCount = cpu_to_le16(params);
852 pSMB->TotalParameterCount = pSMB->ParameterCount;
853 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
854 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000855 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000856 pSMB->ByteCount = cpu_to_le16(byte_count);
857 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
858 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000859 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000860 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000861 cifs_buf_release(pSMB);
862
863 cifs_stats_inc(&tcon->num_deletes);
864
865 if (rc == -EAGAIN)
866 goto PsxDelete;
867
868 return rc;
869}
870
871int
Steve French96daf2b2011-05-27 04:34:02 +0000872CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -0700873 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874{
875 DELETE_FILE_REQ *pSMB = NULL;
876 DELETE_FILE_RSP *pSMBr = NULL;
877 int rc = 0;
878 int bytes_returned;
879 int name_len;
880
881DelFileRetry:
882 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
883 (void **) &pSMBr);
884 if (rc)
885 return rc;
886
887 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
888 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000889 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700890 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 name_len++; /* trailing null */
892 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700893 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 name_len = strnlen(fileName, PATH_MAX);
895 name_len++; /* trailing null */
896 strncpy(pSMB->fileName, fileName, name_len);
897 }
898 pSMB->SearchAttributes =
899 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
900 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000901 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 pSMB->ByteCount = cpu_to_le16(name_len + 1);
903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700905 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000906 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000907 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909 cifs_buf_release(pSMB);
910 if (rc == -EAGAIN)
911 goto DelFileRetry;
912
913 return rc;
914}
915
916int
Steve French96daf2b2011-05-27 04:34:02 +0000917CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700918 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919{
920 DELETE_DIRECTORY_REQ *pSMB = NULL;
921 DELETE_DIRECTORY_RSP *pSMBr = NULL;
922 int rc = 0;
923 int bytes_returned;
924 int name_len;
925
Joe Perchesb6b38f72010-04-21 03:50:45 +0000926 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927RmDirRetry:
928 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
929 (void **) &pSMBr);
930 if (rc)
931 return rc;
932
933 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700934 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
935 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 name_len++; /* trailing null */
937 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700938 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939 name_len = strnlen(dirName, PATH_MAX);
940 name_len++; /* trailing null */
941 strncpy(pSMB->DirName, dirName, name_len);
942 }
943
944 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000945 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 pSMB->ByteCount = cpu_to_le16(name_len + 1);
947 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700949 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000950 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000951 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952
953 cifs_buf_release(pSMB);
954 if (rc == -EAGAIN)
955 goto RmDirRetry;
956 return rc;
957}
958
959int
Steve French96daf2b2011-05-27 04:34:02 +0000960CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -0700961 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
963 int rc = 0;
964 CREATE_DIRECTORY_REQ *pSMB = NULL;
965 CREATE_DIRECTORY_RSP *pSMBr = NULL;
966 int bytes_returned;
967 int name_len;
968
Joe Perchesb6b38f72010-04-21 03:50:45 +0000969 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970MkDirRetry:
971 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
972 (void **) &pSMBr);
973 if (rc)
974 return rc;
975
976 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000977 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700978 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 name_len++; /* trailing null */
980 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700981 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 name_len = strnlen(name, PATH_MAX);
983 name_len++; /* trailing null */
984 strncpy(pSMB->DirName, name, name_len);
985 }
986
987 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000988 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 pSMB->ByteCount = cpu_to_le16(name_len + 1);
990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700992 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000993 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000994 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700995
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 cifs_buf_release(pSMB);
997 if (rc == -EAGAIN)
998 goto MkDirRetry;
999 return rc;
1000}
1001
Steve French2dd29d32007-04-23 22:07:35 +00001002int
Steve French96daf2b2011-05-27 04:34:02 +00001003CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001004 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001005 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001006 const struct nls_table *nls_codepage, int remap)
1007{
1008 TRANSACTION2_SPI_REQ *pSMB = NULL;
1009 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1010 int name_len;
1011 int rc = 0;
1012 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001013 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001014 OPEN_PSX_REQ *pdata;
1015 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001016
Joe Perchesb6b38f72010-04-21 03:50:45 +00001017 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001018PsxCreat:
1019 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1020 (void **) &pSMBr);
1021 if (rc)
1022 return rc;
1023
1024 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1025 name_len =
1026 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1027 PATH_MAX, nls_codepage, remap);
1028 name_len++; /* trailing null */
1029 name_len *= 2;
1030 } else { /* BB improve the check for buffer overruns BB */
1031 name_len = strnlen(name, PATH_MAX);
1032 name_len++; /* trailing null */
1033 strncpy(pSMB->FileName, name, name_len);
1034 }
1035
1036 params = 6 + name_len;
1037 count = sizeof(OPEN_PSX_REQ);
1038 pSMB->MaxParameterCount = cpu_to_le16(2);
1039 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1040 pSMB->MaxSetupCount = 0;
1041 pSMB->Reserved = 0;
1042 pSMB->Flags = 0;
1043 pSMB->Timeout = 0;
1044 pSMB->Reserved2 = 0;
1045 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001046 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001047 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001048 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001049 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001050 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001051 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001052 pdata->OpenFlags = cpu_to_le32(*pOplock);
1053 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1054 pSMB->DataOffset = cpu_to_le16(offset);
1055 pSMB->SetupCount = 1;
1056 pSMB->Reserved3 = 0;
1057 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1058 byte_count = 3 /* pad */ + params + count;
1059
1060 pSMB->DataCount = cpu_to_le16(count);
1061 pSMB->ParameterCount = cpu_to_le16(params);
1062 pSMB->TotalDataCount = pSMB->DataCount;
1063 pSMB->TotalParameterCount = pSMB->ParameterCount;
1064 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1065 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001066 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001067 pSMB->ByteCount = cpu_to_le16(byte_count);
1068 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1069 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1070 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001071 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001072 goto psx_create_err;
1073 }
1074
Joe Perchesb6b38f72010-04-21 03:50:45 +00001075 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1077
Jeff Layton820a8032011-05-04 08:05:26 -04001078 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001079 rc = -EIO; /* bad smb */
1080 goto psx_create_err;
1081 }
1082
1083 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001084 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001085 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001086
Steve French2dd29d32007-04-23 22:07:35 +00001087 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001088 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001089 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1090 /* Let caller know file was created so we can set the mode. */
1091 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001092 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001093 *pOplock |= CIFS_CREATE_ACTION;
1094 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001095 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1096 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001097 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001098 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001099 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001100 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001101 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001103 goto psx_create_err;
1104 }
Steve French50c2f752007-07-13 00:33:32 +00001105 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001106 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001107 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001108 }
Steve French2dd29d32007-04-23 22:07:35 +00001109
1110psx_create_err:
1111 cifs_buf_release(pSMB);
1112
Steve French65bc98b2009-07-10 15:27:25 +00001113 if (posix_flags & SMB_O_DIRECTORY)
1114 cifs_stats_inc(&tcon->num_posixmkdirs);
1115 else
1116 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001117
1118 if (rc == -EAGAIN)
1119 goto PsxCreat;
1120
Steve French50c2f752007-07-13 00:33:32 +00001121 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001122}
1123
Steve Frencha9d02ad2005-08-24 23:06:05 -07001124static __u16 convert_disposition(int disposition)
1125{
1126 __u16 ofun = 0;
1127
1128 switch (disposition) {
1129 case FILE_SUPERSEDE:
1130 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1131 break;
1132 case FILE_OPEN:
1133 ofun = SMBOPEN_OAPPEND;
1134 break;
1135 case FILE_CREATE:
1136 ofun = SMBOPEN_OCREATE;
1137 break;
1138 case FILE_OPEN_IF:
1139 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1140 break;
1141 case FILE_OVERWRITE:
1142 ofun = SMBOPEN_OTRUNC;
1143 break;
1144 case FILE_OVERWRITE_IF:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001148 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001149 ofun = SMBOPEN_OAPPEND; /* regular open */
1150 }
1151 return ofun;
1152}
1153
Jeff Layton35fc37d2008-05-14 10:22:03 -07001154static int
1155access_flags_to_smbopen_mode(const int access_flags)
1156{
1157 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1158
1159 if (masked_flags == GENERIC_READ)
1160 return SMBOPEN_READ;
1161 else if (masked_flags == GENERIC_WRITE)
1162 return SMBOPEN_WRITE;
1163
1164 /* just go for read/write */
1165 return SMBOPEN_READWRITE;
1166}
1167
Steve Frencha9d02ad2005-08-24 23:06:05 -07001168int
Steve French96daf2b2011-05-27 04:34:02 +00001169SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001170 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001171 const int access_flags, const int create_options, __u16 *netfid,
1172 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001173 const struct nls_table *nls_codepage, int remap)
1174{
1175 int rc = -EACCES;
1176 OPENX_REQ *pSMB = NULL;
1177 OPENX_RSP *pSMBr = NULL;
1178 int bytes_returned;
1179 int name_len;
1180 __u16 count;
1181
1182OldOpenRetry:
1183 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1184 (void **) &pSMBr);
1185 if (rc)
1186 return rc;
1187
1188 pSMB->AndXCommand = 0xFF; /* none */
1189
1190 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1191 count = 1; /* account for one byte pad to word boundary */
1192 name_len =
1193 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1194 fileName, PATH_MAX, nls_codepage, remap);
1195 name_len++; /* trailing null */
1196 name_len *= 2;
1197 } else { /* BB improve check for buffer overruns BB */
1198 count = 0; /* no pad */
1199 name_len = strnlen(fileName, PATH_MAX);
1200 name_len++; /* trailing null */
1201 strncpy(pSMB->fileName, fileName, name_len);
1202 }
1203 if (*pOplock & REQ_OPLOCK)
1204 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001205 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001206 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001207
Steve Frencha9d02ad2005-08-24 23:06:05 -07001208 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001209 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001210 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1211 /* set file as system file if special file such
1212 as fifo and server expecting SFU style and
1213 no Unix extensions */
1214
Steve French790fe572007-07-07 19:25:05 +00001215 if (create_options & CREATE_OPTION_SPECIAL)
1216 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001217 else /* BB FIXME BB */
1218 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001219
Jeff Layton67750fb2008-05-09 22:28:02 +00001220 if (create_options & CREATE_OPTION_READONLY)
1221 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222
1223 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001224/* pSMB->CreateOptions = cpu_to_le32(create_options &
1225 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001227
1228 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001229 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001230 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001231 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001232
1233 pSMB->ByteCount = cpu_to_le16(count);
1234 /* long_op set to 1 to allow for oplock break timeouts */
1235 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001236 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 cifs_stats_inc(&tcon->num_opens);
1238 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001239 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 } else {
1241 /* BB verify if wct == 15 */
1242
Steve French582d21e2008-05-13 04:54:12 +00001243/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244
1245 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1246 /* Let caller know file was created so we can set the mode. */
1247 /* Do we care about the CreateAction in any other cases? */
1248 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001249/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001250 *pOplock |= CIFS_CREATE_ACTION; */
1251 /* BB FIXME END */
1252
Steve French790fe572007-07-07 19:25:05 +00001253 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1255 pfile_info->LastAccessTime = 0; /* BB fixme */
1256 pfile_info->LastWriteTime = 0; /* BB fixme */
1257 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001258 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001259 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001261 pfile_info->AllocationSize =
1262 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1263 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001265 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001266 }
1267 }
1268
1269 cifs_buf_release(pSMB);
1270 if (rc == -EAGAIN)
1271 goto OldOpenRetry;
1272 return rc;
1273}
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275int
Steve French96daf2b2011-05-27 04:34:02 +00001276CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001278 const int access_flags, const int create_options, __u16 *netfid,
1279 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001280 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281{
1282 int rc = -EACCES;
1283 OPEN_REQ *pSMB = NULL;
1284 OPEN_RSP *pSMBr = NULL;
1285 int bytes_returned;
1286 int name_len;
1287 __u16 count;
1288
1289openRetry:
1290 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1291 (void **) &pSMBr);
1292 if (rc)
1293 return rc;
1294
1295 pSMB->AndXCommand = 0xFF; /* none */
1296
1297 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1298 count = 1; /* account for one byte pad to word boundary */
1299 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001300 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001301 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 name_len++; /* trailing null */
1303 name_len *= 2;
1304 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001305 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 count = 0; /* no pad */
1307 name_len = strnlen(fileName, PATH_MAX);
1308 name_len++; /* trailing null */
1309 pSMB->NameLength = cpu_to_le16(name_len);
1310 strncpy(pSMB->fileName, fileName, name_len);
1311 }
1312 if (*pOplock & REQ_OPLOCK)
1313 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001314 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1317 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001318 /* set file as system file if special file such
1319 as fifo and server expecting SFU style and
1320 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001321 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001322 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1323 else
1324 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 /* XP does not handle ATTR_POSIX_SEMANTICS */
1327 /* but it helps speed up case sensitive checks for other
1328 servers such as Samba */
1329 if (tcon->ses->capabilities & CAP_UNIX)
1330 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1331
Jeff Layton67750fb2008-05-09 22:28:02 +00001332 if (create_options & CREATE_OPTION_READONLY)
1333 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1336 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001337 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001338 /* BB Expirement with various impersonation levels and verify */
1339 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 pSMB->SecurityFlags =
1341 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1342
1343 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001344 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
1346 pSMB->ByteCount = cpu_to_le16(count);
1347 /* long_op set to 1 to allow for oplock break timeouts */
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001349 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001350 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001352 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 } else {
Steve French09d1db52005-04-28 22:41:08 -07001354 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1356 /* Let caller know file was created so we can set the mode. */
1357 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001358 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001359 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001360 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001361 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1362 36 /* CreationTime to Attributes */);
1363 /* the file_info buf is endian converted by caller */
1364 pfile_info->AllocationSize = pSMBr->AllocationSize;
1365 pfile_info->EndOfFile = pSMBr->EndOfFile;
1366 pfile_info->NumberOfLinks = cpu_to_le32(1);
1367 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001370
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 cifs_buf_release(pSMB);
1372 if (rc == -EAGAIN)
1373 goto openRetry;
1374 return rc;
1375}
1376
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001378CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001379 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
1381 int rc = -EACCES;
1382 READ_REQ *pSMB = NULL;
1383 READ_RSP *pSMBr = NULL;
1384 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001385 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001386 int resp_buf_type = 0;
1387 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001388 __u32 pid = io_parms->pid;
1389 __u16 netfid = io_parms->netfid;
1390 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001391 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001392 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
Joe Perchesb6b38f72010-04-21 03:50:45 +00001394 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001395 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001396 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001397 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001398 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001399 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001400 /* can not handle this big offset for old */
1401 return -EIO;
1402 }
1403 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001406 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (rc)
1408 return rc;
1409
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001410 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1411 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1412
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 /* tcon and ses pointer are checked in smb_init */
1414 if (tcon->ses->server == NULL)
1415 return -ECONNABORTED;
1416
Steve Frenchec637e32005-12-12 20:53:18 -08001417 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001419 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001420 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001421 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001422
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 pSMB->Remaining = 0;
1424 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1425 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001426 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001427 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1428 else {
1429 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001430 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001431 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001432 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433 }
Steve Frenchec637e32005-12-12 20:53:18 -08001434
1435 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001436 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001437 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001438 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001439 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001440 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001442 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 } else {
1444 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1445 data_length = data_length << 16;
1446 data_length += le16_to_cpu(pSMBr->DataLength);
1447 *nbytes = data_length;
1448
1449 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001450 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001452 cFYI(1, "bad length %d for count %d",
1453 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 rc = -EIO;
1455 *nbytes = 0;
1456 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001457 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001458 le16_to_cpu(pSMBr->DataOffset);
1459/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001460 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001461 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001462 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001463 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001464 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 }
1466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467
Steve French4b8f9302006-02-26 16:41:18 +00001468/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001469 if (*buf) {
1470 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001471 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001472 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001473 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001474 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001475 /* return buffer to caller to free */
1476 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001477 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001478 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001479 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001480 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001481 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001482
1483 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 since file handle passed in no longer valid */
1485 return rc;
1486}
1487
Steve Frenchec637e32005-12-12 20:53:18 -08001488
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001490CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1491 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001492 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001497 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 __u32 bytes_sent;
1499 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001500 __u32 pid = io_parms->pid;
1501 __u16 netfid = io_parms->netfid;
1502 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001503 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001504 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
Steve Frencha24e2d72010-04-03 17:20:21 +00001506 *nbytes = 0;
1507
Joe Perchesb6b38f72010-04-21 03:50:45 +00001508 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001509 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001510 return -ECONNABORTED;
1511
Steve French790fe572007-07-07 19:25:05 +00001512 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001513 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001514 else {
Steve French1c955182005-08-30 20:58:07 -07001515 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001516 if ((offset >> 32) > 0) {
1517 /* can not handle big offset for old srv */
1518 return -EIO;
1519 }
1520 }
Steve French1c955182005-08-30 20:58:07 -07001521
1522 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 (void **) &pSMBr);
1524 if (rc)
1525 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001526
1527 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1528 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 /* tcon and ses pointer are checked in smb_init */
1531 if (tcon->ses->server == NULL)
1532 return -ECONNABORTED;
1533
1534 pSMB->AndXCommand = 0xFF; /* none */
1535 pSMB->Fid = netfid;
1536 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001537 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001538 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 pSMB->Reserved = 0xFFFFFFFF;
1541 pSMB->WriteMode = 0;
1542 pSMB->Remaining = 0;
1543
Steve French50c2f752007-07-13 00:33:32 +00001544 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 can send more if LARGE_WRITE_X capability returned by the server and if
1546 our buffer is big enough or if we convert to iovecs on socket writes
1547 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001548 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1550 } else {
1551 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1552 & ~0xFF;
1553 }
1554
1555 if (bytes_sent > count)
1556 bytes_sent = count;
1557 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001558 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001559 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001560 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001561 else if (ubuf) {
1562 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 cifs_buf_release(pSMB);
1564 return -EFAULT;
1565 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001566 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 /* No buffer */
1568 cifs_buf_release(pSMB);
1569 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001570 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001571 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001572 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001573 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001574 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1577 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001578 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001579
Steve French790fe572007-07-07 19:25:05 +00001580 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001581 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001582 else { /* old style write has byte count 4 bytes earlier
1583 so 4 bytes pad */
1584 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001585 (struct smb_com_writex_req *)pSMB;
1586 pSMBW->ByteCount = cpu_to_le16(byte_count);
1587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1590 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001591 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001593 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 } else {
1595 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1596 *nbytes = (*nbytes) << 16;
1597 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301598
1599 /*
1600 * Mask off high 16 bits when bytes written as returned by the
1601 * server is greater than bytes requested by the client. Some
1602 * OS/2 servers are known to set incorrect CountHigh values.
1603 */
1604 if (*nbytes > count)
1605 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 }
1607
1608 cifs_buf_release(pSMB);
1609
Steve French50c2f752007-07-13 00:33:32 +00001610 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 since file handle passed in no longer valid */
1612
1613 return rc;
1614}
1615
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001616void
1617cifs_writedata_release(struct kref *refcount)
1618{
1619 struct cifs_writedata *wdata = container_of(refcount,
1620 struct cifs_writedata, refcount);
1621
1622 if (wdata->cfile)
1623 cifsFileInfo_put(wdata->cfile);
1624
1625 kfree(wdata);
1626}
1627
1628/*
1629 * Write failed with a retryable error. Resend the write request. It's also
1630 * possible that the page was redirtied so re-clean the page.
1631 */
1632static void
1633cifs_writev_requeue(struct cifs_writedata *wdata)
1634{
1635 int i, rc;
1636 struct inode *inode = wdata->cfile->dentry->d_inode;
1637
1638 for (i = 0; i < wdata->nr_pages; i++) {
1639 lock_page(wdata->pages[i]);
1640 clear_page_dirty_for_io(wdata->pages[i]);
1641 }
1642
1643 do {
1644 rc = cifs_async_writev(wdata);
1645 } while (rc == -EAGAIN);
1646
1647 for (i = 0; i < wdata->nr_pages; i++) {
1648 if (rc != 0)
1649 SetPageError(wdata->pages[i]);
1650 unlock_page(wdata->pages[i]);
1651 }
1652
1653 mapping_set_error(inode->i_mapping, rc);
1654 kref_put(&wdata->refcount, cifs_writedata_release);
1655}
1656
1657static void
1658cifs_writev_complete(struct work_struct *work)
1659{
1660 struct cifs_writedata *wdata = container_of(work,
1661 struct cifs_writedata, work);
1662 struct inode *inode = wdata->cfile->dentry->d_inode;
1663 int i = 0;
1664
1665 if (wdata->result == 0) {
1666 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1667 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1668 wdata->bytes);
1669 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1670 return cifs_writev_requeue(wdata);
1671
1672 for (i = 0; i < wdata->nr_pages; i++) {
1673 struct page *page = wdata->pages[i];
1674 if (wdata->result == -EAGAIN)
1675 __set_page_dirty_nobuffers(page);
1676 else if (wdata->result < 0)
1677 SetPageError(page);
1678 end_page_writeback(page);
1679 page_cache_release(page);
1680 }
1681 if (wdata->result != -EAGAIN)
1682 mapping_set_error(inode->i_mapping, wdata->result);
1683 kref_put(&wdata->refcount, cifs_writedata_release);
1684}
1685
1686struct cifs_writedata *
1687cifs_writedata_alloc(unsigned int nr_pages)
1688{
1689 struct cifs_writedata *wdata;
1690
1691 /* this would overflow */
1692 if (nr_pages == 0) {
1693 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1694 return NULL;
1695 }
1696
1697 /* writedata + number of page pointers */
1698 wdata = kzalloc(sizeof(*wdata) +
1699 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1700 if (wdata != NULL) {
1701 INIT_WORK(&wdata->work, cifs_writev_complete);
1702 kref_init(&wdata->refcount);
1703 }
1704 return wdata;
1705}
1706
1707/*
1708 * Check the midState and signature on received buffer (if any), and queue the
1709 * workqueue completion task.
1710 */
1711static void
1712cifs_writev_callback(struct mid_q_entry *mid)
1713{
1714 struct cifs_writedata *wdata = mid->callback_data;
Steve French96daf2b2011-05-27 04:34:02 +00001715 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001716 unsigned int written;
1717 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1718
1719 switch (mid->midState) {
1720 case MID_RESPONSE_RECEIVED:
1721 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1722 if (wdata->result != 0)
1723 break;
1724
1725 written = le16_to_cpu(smb->CountHigh);
1726 written <<= 16;
1727 written += le16_to_cpu(smb->Count);
1728 /*
1729 * Mask off high 16 bits when bytes written as returned
1730 * by the server is greater than bytes requested by the
1731 * client. OS/2 servers are known to set incorrect
1732 * CountHigh values.
1733 */
1734 if (written > wdata->bytes)
1735 written &= 0xFFFF;
1736
1737 if (written < wdata->bytes)
1738 wdata->result = -ENOSPC;
1739 else
1740 wdata->bytes = written;
1741 break;
1742 case MID_REQUEST_SUBMITTED:
1743 case MID_RETRY_NEEDED:
1744 wdata->result = -EAGAIN;
1745 break;
1746 default:
1747 wdata->result = -EIO;
1748 break;
1749 }
1750
1751 queue_work(system_nrt_wq, &wdata->work);
1752 DeleteMidQEntry(mid);
1753 atomic_dec(&tcon->ses->server->inFlight);
1754 wake_up(&tcon->ses->server->request_q);
1755}
1756
1757/* cifs_async_writev - send an async write, and set up mid to handle result */
1758int
1759cifs_async_writev(struct cifs_writedata *wdata)
1760{
1761 int i, rc = -EACCES;
1762 WRITE_REQ *smb = NULL;
1763 int wct;
Steve French96daf2b2011-05-27 04:34:02 +00001764 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001765 struct inode *inode = wdata->cfile->dentry->d_inode;
1766 struct kvec *iov = NULL;
1767
1768 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1769 wct = 14;
1770 } else {
1771 wct = 12;
1772 if (wdata->offset >> 32 > 0) {
1773 /* can not handle big offset for old srv */
1774 return -EIO;
1775 }
1776 }
1777
1778 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
1779 if (rc)
1780 goto async_writev_out;
1781
1782 /* 1 iov per page + 1 for header */
1783 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
1784 if (iov == NULL) {
1785 rc = -ENOMEM;
1786 goto async_writev_out;
1787 }
1788
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001789 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
1790 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
1791
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001792 smb->AndXCommand = 0xFF; /* none */
1793 smb->Fid = wdata->cfile->netfid;
1794 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
1795 if (wct == 14)
1796 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
1797 smb->Reserved = 0xFFFFFFFF;
1798 smb->WriteMode = 0;
1799 smb->Remaining = 0;
1800
1801 smb->DataOffset =
1802 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1803
1804 /* 4 for RFC1001 length + 1 for BCC */
1805 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
1806 iov[0].iov_base = smb;
1807
1808 /* marshal up the pages into iov array */
1809 wdata->bytes = 0;
1810 for (i = 0; i < wdata->nr_pages; i++) {
1811 iov[i + 1].iov_len = min(inode->i_size -
1812 page_offset(wdata->pages[i]),
1813 (loff_t)PAGE_CACHE_SIZE);
1814 iov[i + 1].iov_base = kmap(wdata->pages[i]);
1815 wdata->bytes += iov[i + 1].iov_len;
1816 }
1817
1818 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
1819
1820 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
1821 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
1822
1823 if (wct == 14) {
1824 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
1825 put_bcc(wdata->bytes + 1, &smb->hdr);
1826 } else {
1827 /* wct == 12 */
1828 struct smb_com_writex_req *smbw =
1829 (struct smb_com_writex_req *)smb;
1830 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
1831 put_bcc(wdata->bytes + 5, &smbw->hdr);
1832 iov[0].iov_len += 4; /* pad bigger by four bytes */
1833 }
1834
1835 kref_get(&wdata->refcount);
1836 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
1837 cifs_writev_callback, wdata, false);
1838
1839 if (rc == 0)
1840 cifs_stats_inc(&tcon->num_writes);
1841 else
1842 kref_put(&wdata->refcount, cifs_writedata_release);
1843
1844 /* send is done, unmap pages */
1845 for (i = 0; i < wdata->nr_pages; i++)
1846 kunmap(wdata->pages[i]);
1847
1848async_writev_out:
1849 cifs_small_buf_release(smb);
1850 kfree(iov);
1851 return rc;
1852}
1853
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001854int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001855CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
1856 unsigned int *nbytes, struct kvec *iov, int n_vec,
1857 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858{
1859 int rc = -EACCES;
1860 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001861 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001862 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001863 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001864 __u32 pid = io_parms->pid;
1865 __u16 netfid = io_parms->netfid;
1866 __u64 offset = io_parms->offset;
Steve French96daf2b2011-05-27 04:34:02 +00001867 struct cifs_tcon *tcon = io_parms->tcon;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001868 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001870 *nbytes = 0;
1871
Joe Perchesb6b38f72010-04-21 03:50:45 +00001872 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001873
Steve French4c3130e2008-12-09 00:28:16 +00001874 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001875 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001876 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001877 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001878 if ((offset >> 32) > 0) {
1879 /* can not handle big offset for old srv */
1880 return -EIO;
1881 }
1882 }
Steve French8cc64c62005-10-03 13:49:43 -07001883 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (rc)
1885 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001886
1887 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1888 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 /* tcon and ses pointer are checked in smb_init */
1891 if (tcon->ses->server == NULL)
1892 return -ECONNABORTED;
1893
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001894 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 pSMB->Fid = netfid;
1896 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001897 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001898 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 pSMB->Reserved = 0xFFFFFFFF;
1900 pSMB->WriteMode = 0;
1901 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001904 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Steve French3e844692005-10-03 13:37:24 -07001906 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1907 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001908 /* header + 1 byte pad */
1909 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001910 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001911 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001912 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001913 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001914 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001915 pSMB->ByteCount = cpu_to_le16(count + 1);
1916 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001917 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001918 (struct smb_com_writex_req *)pSMB;
1919 pSMBW->ByteCount = cpu_to_le16(count + 5);
1920 }
Steve French3e844692005-10-03 13:37:24 -07001921 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001922 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001923 iov[0].iov_len = smb_hdr_len + 4;
1924 else /* wct == 12 pad bigger by four bytes */
1925 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001926
Steve French3e844692005-10-03 13:37:24 -07001927
Steve Frenchec637e32005-12-12 20:53:18 -08001928 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001929 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001930 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001932 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001933 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001934 /* presumably this can not happen, but best to be safe */
1935 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001936 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001937 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001938 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1939 *nbytes = (*nbytes) << 16;
1940 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301941
1942 /*
1943 * Mask off high 16 bits when bytes written as returned by the
1944 * server is greater than bytes requested by the client. OS/2
1945 * servers are known to set incorrect CountHigh values.
1946 */
1947 if (*nbytes > count)
1948 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
Steve French4b8f9302006-02-26 16:41:18 +00001951/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001952 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001953 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001954 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001955 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Steve French50c2f752007-07-13 00:33:32 +00001957 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 since file handle passed in no longer valid */
1959
1960 return rc;
1961}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001962
1963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964int
Steve French96daf2b2011-05-27 04:34:02 +00001965CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966 const __u16 smb_file_id, const __u64 len,
1967 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001968 const __u32 numLock, const __u8 lockType,
1969 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{
1971 int rc = 0;
1972 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001973/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 int bytes_returned;
1975 int timeout = 0;
1976 __u16 count;
1977
Joe Perchesb6b38f72010-04-21 03:50:45 +00001978 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001979 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if (rc)
1982 return rc;
1983
Steve French790fe572007-07-07 19:25:05 +00001984 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001985 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001987 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001988 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1990 } else {
1991 pSMB->Timeout = 0;
1992 }
1993
1994 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1995 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1996 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001997 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 pSMB->AndXCommand = 0xFF; /* none */
1999 pSMB->Fid = smb_file_id; /* netfid stays le */
2000
Steve French790fe572007-07-07 19:25:05 +00002001 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
2003 /* BB where to store pid high? */
2004 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2005 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2006 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2007 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2008 count = sizeof(LOCKING_ANDX_RANGE);
2009 } else {
2010 /* oplock break */
2011 count = 0;
2012 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002013 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 pSMB->ByteCount = cpu_to_le16(count);
2015
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002016 if (waitFlag) {
2017 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002018 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002019 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002020 } else {
Steve French133672e2007-11-13 22:41:37 +00002021 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2022 timeout);
2023 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002024 }
Steve Frencha4544342005-08-24 13:59:35 -07002025 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002026 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002027 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Steve French50c2f752007-07-13 00:33:32 +00002029 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 since file handle passed in no longer valid */
2031 return rc;
2032}
2033
2034int
Steve French96daf2b2011-05-27 04:34:02 +00002035CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
Steve French08547b02006-02-28 22:39:25 +00002036 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00002037 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00002038 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002039{
2040 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2041 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002042 struct cifs_posix_lock *parm_data;
2043 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002044 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002045 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002046 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002047 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002048 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002049
Joe Perchesb6b38f72010-04-21 03:50:45 +00002050 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002051
Steve French790fe572007-07-07 19:25:05 +00002052 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002053 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002054
Steve French08547b02006-02-28 22:39:25 +00002055 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2056
2057 if (rc)
2058 return rc;
2059
2060 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2061
Steve French50c2f752007-07-13 00:33:32 +00002062 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002063 pSMB->MaxSetupCount = 0;
2064 pSMB->Reserved = 0;
2065 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002066 pSMB->Reserved2 = 0;
2067 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2068 offset = param_offset + params;
2069
Steve French08547b02006-02-28 22:39:25 +00002070 count = sizeof(struct cifs_posix_lock);
2071 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002072 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002073 pSMB->SetupCount = 1;
2074 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002075 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002076 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2077 else
2078 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2079 byte_count = 3 /* pad */ + params + count;
2080 pSMB->DataCount = cpu_to_le16(count);
2081 pSMB->ParameterCount = cpu_to_le16(params);
2082 pSMB->TotalDataCount = pSMB->DataCount;
2083 pSMB->TotalParameterCount = pSMB->ParameterCount;
2084 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002085 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002086 (((char *) &pSMB->hdr.Protocol) + offset);
2087
2088 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002089 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002090 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002091 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002092 pSMB->Timeout = cpu_to_le32(-1);
2093 } else
2094 pSMB->Timeout = 0;
2095
Steve French08547b02006-02-28 22:39:25 +00002096 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002097 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002098 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002099
2100 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002101 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002102 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2103 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002104 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002105 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002106 if (waitFlag) {
2107 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2108 (struct smb_hdr *) pSMBr, &bytes_returned);
2109 } else {
Steve French133672e2007-11-13 22:41:37 +00002110 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002111 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002112 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2113 &resp_buf_type, timeout);
2114 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2115 not try to free it twice below on exit */
2116 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002117 }
2118
Steve French08547b02006-02-28 22:39:25 +00002119 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002120 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002121 } else if (get_flag) {
2122 /* lock structure can be returned on get */
2123 __u16 data_offset;
2124 __u16 data_count;
2125 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002126
Jeff Layton820a8032011-05-04 08:05:26 -04002127 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002128 rc = -EIO; /* bad smb */
2129 goto plk_err_exit;
2130 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002131 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2132 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002133 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002134 rc = -EIO;
2135 goto plk_err_exit;
2136 }
2137 parm_data = (struct cifs_posix_lock *)
2138 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002139 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002140 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002141 else {
2142 if (parm_data->lock_type ==
2143 __constant_cpu_to_le16(CIFS_RDLCK))
2144 pLockData->fl_type = F_RDLCK;
2145 else if (parm_data->lock_type ==
2146 __constant_cpu_to_le16(CIFS_WRLCK))
2147 pLockData->fl_type = F_WRLCK;
2148
Steve French5443d132011-03-13 05:08:25 +00002149 pLockData->fl_start = le64_to_cpu(parm_data->start);
2150 pLockData->fl_end = pLockData->fl_start +
2151 le64_to_cpu(parm_data->length) - 1;
2152 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002153 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002154 }
Steve French50c2f752007-07-13 00:33:32 +00002155
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002156plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002157 if (pSMB)
2158 cifs_small_buf_release(pSMB);
2159
Steve French133672e2007-11-13 22:41:37 +00002160 if (resp_buf_type == CIFS_SMALL_BUFFER)
2161 cifs_small_buf_release(iov[0].iov_base);
2162 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2163 cifs_buf_release(iov[0].iov_base);
2164
Steve French08547b02006-02-28 22:39:25 +00002165 /* Note: On -EAGAIN error only caller can retry on handle based calls
2166 since file handle passed in no longer valid */
2167
2168 return rc;
2169}
2170
2171
2172int
Steve French96daf2b2011-05-27 04:34:02 +00002173CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174{
2175 int rc = 0;
2176 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002177 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
2179/* do not retry on dead session on close */
2180 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002181 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return 0;
2183 if (rc)
2184 return rc;
2185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002187 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002189 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002190 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002192 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002194 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 }
2196 }
2197
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002199 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 rc = 0;
2201
2202 return rc;
2203}
2204
2205int
Steve French96daf2b2011-05-27 04:34:02 +00002206CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
Steve Frenchb298f222009-02-21 21:17:43 +00002207{
2208 int rc = 0;
2209 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002210 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002211
2212 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2213 if (rc)
2214 return rc;
2215
2216 pSMB->FileID = (__u16) smb_file_id;
2217 pSMB->ByteCount = 0;
2218 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2219 cifs_stats_inc(&tcon->num_flushes);
2220 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002221 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002222
2223 return rc;
2224}
2225
2226int
Steve French96daf2b2011-05-27 04:34:02 +00002227CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002229 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230{
2231 int rc = 0;
2232 RENAME_REQ *pSMB = NULL;
2233 RENAME_RSP *pSMBr = NULL;
2234 int bytes_returned;
2235 int name_len, name_len2;
2236 __u16 count;
2237
Joe Perchesb6b38f72010-04-21 03:50:45 +00002238 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239renameRetry:
2240 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2241 (void **) &pSMBr);
2242 if (rc)
2243 return rc;
2244
2245 pSMB->BufferFormat = 0x04;
2246 pSMB->SearchAttributes =
2247 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2248 ATTR_DIRECTORY);
2249
2250 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2251 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002252 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002253 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 name_len++; /* trailing null */
2255 name_len *= 2;
2256 pSMB->OldFileName[name_len] = 0x04; /* pad */
2257 /* protocol requires ASCII signature byte on Unicode string */
2258 pSMB->OldFileName[name_len + 1] = 0x00;
2259 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002260 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002261 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2263 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002264 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 name_len = strnlen(fromName, PATH_MAX);
2266 name_len++; /* trailing null */
2267 strncpy(pSMB->OldFileName, fromName, name_len);
2268 name_len2 = strnlen(toName, PATH_MAX);
2269 name_len2++; /* trailing null */
2270 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2271 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2272 name_len2++; /* trailing null */
2273 name_len2++; /* signature byte */
2274 }
2275
2276 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002277 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 pSMB->ByteCount = cpu_to_le16(count);
2279
2280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2281 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002282 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002283 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002284 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 cifs_buf_release(pSMB);
2287
2288 if (rc == -EAGAIN)
2289 goto renameRetry;
2290
2291 return rc;
2292}
2293
Steve French96daf2b2011-05-27 04:34:02 +00002294int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002295 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002296 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
2298 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2299 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002300 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 char *data_offset;
2302 char dummy_string[30];
2303 int rc = 0;
2304 int bytes_returned = 0;
2305 int len_of_str;
2306 __u16 params, param_offset, offset, count, byte_count;
2307
Joe Perchesb6b38f72010-04-21 03:50:45 +00002308 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2310 (void **) &pSMBr);
2311 if (rc)
2312 return rc;
2313
2314 params = 6;
2315 pSMB->MaxSetupCount = 0;
2316 pSMB->Reserved = 0;
2317 pSMB->Flags = 0;
2318 pSMB->Timeout = 0;
2319 pSMB->Reserved2 = 0;
2320 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2321 offset = param_offset + params;
2322
2323 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2324 rename_info = (struct set_file_rename *) data_offset;
2325 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002326 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 pSMB->SetupCount = 1;
2328 pSMB->Reserved3 = 0;
2329 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2330 byte_count = 3 /* pad */ + params;
2331 pSMB->ParameterCount = cpu_to_le16(params);
2332 pSMB->TotalParameterCount = pSMB->ParameterCount;
2333 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2334 pSMB->DataOffset = cpu_to_le16(offset);
2335 /* construct random name ".cifs_tmp<inodenum><mid>" */
2336 rename_info->overwrite = cpu_to_le32(1);
2337 rename_info->root_fid = 0;
2338 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002339 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002340 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2341 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002342 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002344 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002345 target_name, PATH_MAX, nls_codepage,
2346 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 }
2348 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002349 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 byte_count += count;
2351 pSMB->DataCount = cpu_to_le16(count);
2352 pSMB->TotalDataCount = pSMB->DataCount;
2353 pSMB->Fid = netfid;
2354 pSMB->InformationLevel =
2355 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2356 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002357 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 pSMB->ByteCount = cpu_to_le16(byte_count);
2359 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002361 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002362 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002363 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002364
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 cifs_buf_release(pSMB);
2366
2367 /* Note: On -EAGAIN error only caller can retry on handle based calls
2368 since file handle passed in no longer valid */
2369
2370 return rc;
2371}
2372
2373int
Steve French96daf2b2011-05-27 04:34:02 +00002374CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
Steve French50c2f752007-07-13 00:33:32 +00002375 const __u16 target_tid, const char *toName, const int flags,
2376 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377{
2378 int rc = 0;
2379 COPY_REQ *pSMB = NULL;
2380 COPY_RSP *pSMBr = NULL;
2381 int bytes_returned;
2382 int name_len, name_len2;
2383 __u16 count;
2384
Joe Perchesb6b38f72010-04-21 03:50:45 +00002385 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386copyRetry:
2387 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2388 (void **) &pSMBr);
2389 if (rc)
2390 return rc;
2391
2392 pSMB->BufferFormat = 0x04;
2393 pSMB->Tid2 = target_tid;
2394
2395 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2396
2397 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002398 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002399 fromName, PATH_MAX, nls_codepage,
2400 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 name_len++; /* trailing null */
2402 name_len *= 2;
2403 pSMB->OldFileName[name_len] = 0x04; /* pad */
2404 /* protocol requires ASCII signature byte on Unicode string */
2405 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002406 name_len2 =
2407 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002408 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2410 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002411 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 name_len = strnlen(fromName, PATH_MAX);
2413 name_len++; /* trailing null */
2414 strncpy(pSMB->OldFileName, fromName, name_len);
2415 name_len2 = strnlen(toName, PATH_MAX);
2416 name_len2++; /* trailing null */
2417 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2418 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2419 name_len2++; /* trailing null */
2420 name_len2++; /* signature byte */
2421 }
2422
2423 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002424 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 pSMB->ByteCount = cpu_to_le16(count);
2426
2427 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2428 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2429 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002430 cFYI(1, "Send error in copy = %d with %d files copied",
2431 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 }
Steve French0d817bc2008-05-22 02:02:03 +00002433 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
2435 if (rc == -EAGAIN)
2436 goto copyRetry;
2437
2438 return rc;
2439}
2440
2441int
Steve French96daf2b2011-05-27 04:34:02 +00002442CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 const char *fromName, const char *toName,
2444 const struct nls_table *nls_codepage)
2445{
2446 TRANSACTION2_SPI_REQ *pSMB = NULL;
2447 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2448 char *data_offset;
2449 int name_len;
2450 int name_len_target;
2451 int rc = 0;
2452 int bytes_returned = 0;
2453 __u16 params, param_offset, offset, byte_count;
2454
Joe Perchesb6b38f72010-04-21 03:50:45 +00002455 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456createSymLinkRetry:
2457 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2458 (void **) &pSMBr);
2459 if (rc)
2460 return rc;
2461
2462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2463 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002464 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 /* find define for this maxpathcomponent */
2466 , nls_codepage);
2467 name_len++; /* trailing null */
2468 name_len *= 2;
2469
Steve French50c2f752007-07-13 00:33:32 +00002470 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 name_len = strnlen(fromName, PATH_MAX);
2472 name_len++; /* trailing null */
2473 strncpy(pSMB->FileName, fromName, name_len);
2474 }
2475 params = 6 + name_len;
2476 pSMB->MaxSetupCount = 0;
2477 pSMB->Reserved = 0;
2478 pSMB->Flags = 0;
2479 pSMB->Timeout = 0;
2480 pSMB->Reserved2 = 0;
2481 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002482 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 offset = param_offset + params;
2484
2485 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2486 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2487 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002488 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 /* find define for this maxpathcomponent */
2490 , nls_codepage);
2491 name_len_target++; /* trailing null */
2492 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002493 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 name_len_target = strnlen(toName, PATH_MAX);
2495 name_len_target++; /* trailing null */
2496 strncpy(data_offset, toName, name_len_target);
2497 }
2498
2499 pSMB->MaxParameterCount = cpu_to_le16(2);
2500 /* BB find exact max on data count below from sess */
2501 pSMB->MaxDataCount = cpu_to_le16(1000);
2502 pSMB->SetupCount = 1;
2503 pSMB->Reserved3 = 0;
2504 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2505 byte_count = 3 /* pad */ + params + name_len_target;
2506 pSMB->DataCount = cpu_to_le16(name_len_target);
2507 pSMB->ParameterCount = cpu_to_le16(params);
2508 pSMB->TotalDataCount = pSMB->DataCount;
2509 pSMB->TotalParameterCount = pSMB->ParameterCount;
2510 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2511 pSMB->DataOffset = cpu_to_le16(offset);
2512 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2513 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002514 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 pSMB->ByteCount = cpu_to_le16(byte_count);
2516 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2517 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002518 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002519 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002520 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Steve French0d817bc2008-05-22 02:02:03 +00002522 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
2524 if (rc == -EAGAIN)
2525 goto createSymLinkRetry;
2526
2527 return rc;
2528}
2529
2530int
Steve French96daf2b2011-05-27 04:34:02 +00002531CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002533 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534{
2535 TRANSACTION2_SPI_REQ *pSMB = NULL;
2536 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2537 char *data_offset;
2538 int name_len;
2539 int name_len_target;
2540 int rc = 0;
2541 int bytes_returned = 0;
2542 __u16 params, param_offset, offset, byte_count;
2543
Joe Perchesb6b38f72010-04-21 03:50:45 +00002544 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545createHardLinkRetry:
2546 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2547 (void **) &pSMBr);
2548 if (rc)
2549 return rc;
2550
2551 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002552 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002553 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 name_len++; /* trailing null */
2555 name_len *= 2;
2556
Steve French50c2f752007-07-13 00:33:32 +00002557 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 name_len = strnlen(toName, PATH_MAX);
2559 name_len++; /* trailing null */
2560 strncpy(pSMB->FileName, toName, name_len);
2561 }
2562 params = 6 + name_len;
2563 pSMB->MaxSetupCount = 0;
2564 pSMB->Reserved = 0;
2565 pSMB->Flags = 0;
2566 pSMB->Timeout = 0;
2567 pSMB->Reserved2 = 0;
2568 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002569 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 offset = param_offset + params;
2571
2572 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2573 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2574 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002575 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002576 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 name_len_target++; /* trailing null */
2578 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002579 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 name_len_target = strnlen(fromName, PATH_MAX);
2581 name_len_target++; /* trailing null */
2582 strncpy(data_offset, fromName, name_len_target);
2583 }
2584
2585 pSMB->MaxParameterCount = cpu_to_le16(2);
2586 /* BB find exact max on data count below from sess*/
2587 pSMB->MaxDataCount = cpu_to_le16(1000);
2588 pSMB->SetupCount = 1;
2589 pSMB->Reserved3 = 0;
2590 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2591 byte_count = 3 /* pad */ + params + name_len_target;
2592 pSMB->ParameterCount = cpu_to_le16(params);
2593 pSMB->TotalParameterCount = pSMB->ParameterCount;
2594 pSMB->DataCount = cpu_to_le16(name_len_target);
2595 pSMB->TotalDataCount = pSMB->DataCount;
2596 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2597 pSMB->DataOffset = cpu_to_le16(offset);
2598 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2599 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002600 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 pSMB->ByteCount = cpu_to_le16(byte_count);
2602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002604 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002605 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002606 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 cifs_buf_release(pSMB);
2609 if (rc == -EAGAIN)
2610 goto createHardLinkRetry;
2611
2612 return rc;
2613}
2614
2615int
Steve French96daf2b2011-05-27 04:34:02 +00002616CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002618 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619{
2620 int rc = 0;
2621 NT_RENAME_REQ *pSMB = NULL;
2622 RENAME_RSP *pSMBr = NULL;
2623 int bytes_returned;
2624 int name_len, name_len2;
2625 __u16 count;
2626
Joe Perchesb6b38f72010-04-21 03:50:45 +00002627 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628winCreateHardLinkRetry:
2629
2630 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2631 (void **) &pSMBr);
2632 if (rc)
2633 return rc;
2634
2635 pSMB->SearchAttributes =
2636 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2637 ATTR_DIRECTORY);
2638 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2639 pSMB->ClusterCount = 0;
2640
2641 pSMB->BufferFormat = 0x04;
2642
2643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2644 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002645 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002646 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 name_len++; /* trailing null */
2648 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002649
2650 /* protocol specifies ASCII buffer format (0x04) for unicode */
2651 pSMB->OldFileName[name_len] = 0x04;
2652 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002654 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002655 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2657 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002658 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 name_len = strnlen(fromName, PATH_MAX);
2660 name_len++; /* trailing null */
2661 strncpy(pSMB->OldFileName, fromName, name_len);
2662 name_len2 = strnlen(toName, PATH_MAX);
2663 name_len2++; /* trailing null */
2664 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2665 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2666 name_len2++; /* trailing null */
2667 name_len2++; /* signature byte */
2668 }
2669
2670 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002671 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 pSMB->ByteCount = cpu_to_le16(count);
2673
2674 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2675 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002676 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002677 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002678 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002679
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 cifs_buf_release(pSMB);
2681 if (rc == -EAGAIN)
2682 goto winCreateHardLinkRetry;
2683
2684 return rc;
2685}
2686
2687int
Steve French96daf2b2011-05-27 04:34:02 +00002688CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002689 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 const struct nls_table *nls_codepage)
2691{
2692/* SMB_QUERY_FILE_UNIX_LINK */
2693 TRANSACTION2_QPI_REQ *pSMB = NULL;
2694 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2695 int rc = 0;
2696 int bytes_returned;
2697 int name_len;
2698 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002699 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Joe Perchesb6b38f72010-04-21 03:50:45 +00002701 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
2703querySymLinkRetry:
2704 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2705 (void **) &pSMBr);
2706 if (rc)
2707 return rc;
2708
2709 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2710 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002711 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2712 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 name_len++; /* trailing null */
2714 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002715 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 name_len = strnlen(searchName, PATH_MAX);
2717 name_len++; /* trailing null */
2718 strncpy(pSMB->FileName, searchName, name_len);
2719 }
2720
2721 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2722 pSMB->TotalDataCount = 0;
2723 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002724 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 pSMB->MaxSetupCount = 0;
2726 pSMB->Reserved = 0;
2727 pSMB->Flags = 0;
2728 pSMB->Timeout = 0;
2729 pSMB->Reserved2 = 0;
2730 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002731 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 pSMB->DataCount = 0;
2733 pSMB->DataOffset = 0;
2734 pSMB->SetupCount = 1;
2735 pSMB->Reserved3 = 0;
2736 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2737 byte_count = params + 1 /* pad */ ;
2738 pSMB->TotalParameterCount = cpu_to_le16(params);
2739 pSMB->ParameterCount = pSMB->TotalParameterCount;
2740 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2741 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002742 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 pSMB->ByteCount = cpu_to_le16(byte_count);
2744
2745 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2746 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2747 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002748 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 } else {
2750 /* decode response */
2751
2752 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002754 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002755 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002757 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002758 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Jeff Layton460b9692009-04-30 07:17:56 -04002760 data_start = ((char *) &pSMBr->hdr.Protocol) +
2761 le16_to_cpu(pSMBr->t2.DataOffset);
2762
Steve French0e0d2cf2009-05-01 05:27:32 +00002763 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2764 is_unicode = true;
2765 else
2766 is_unicode = false;
2767
Steve French737b7582005-04-28 22:41:06 -07002768 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002769 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002770 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002771 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002772 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 }
2774 }
2775 cifs_buf_release(pSMB);
2776 if (rc == -EAGAIN)
2777 goto querySymLinkRetry;
2778 return rc;
2779}
2780
Steve Frenchc52a9552011-02-24 06:16:22 +00002781#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2782/*
2783 * Recent Windows versions now create symlinks more frequently
2784 * and they use the "reparse point" mechanism below. We can of course
2785 * do symlinks nicely to Samba and other servers which support the
2786 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2787 * "MF" symlinks optionally, but for recent Windows we really need to
2788 * reenable the code below and fix the cifs_symlink callers to handle this.
2789 * In the interim this code has been moved to its own config option so
2790 * it is not compiled in by default until callers fixed up and more tested.
2791 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792int
Steve French96daf2b2011-05-27 04:34:02 +00002793CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002795 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 const struct nls_table *nls_codepage)
2797{
2798 int rc = 0;
2799 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002800 struct smb_com_transaction_ioctl_req *pSMB;
2801 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
Joe Perchesb6b38f72010-04-21 03:50:45 +00002803 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2805 (void **) &pSMBr);
2806 if (rc)
2807 return rc;
2808
2809 pSMB->TotalParameterCount = 0 ;
2810 pSMB->TotalDataCount = 0;
2811 pSMB->MaxParameterCount = cpu_to_le32(2);
2812 /* BB find exact data count max from sess structure BB */
Jeff Laytonc974bef2011-10-11 06:41:32 -04002813 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 pSMB->MaxSetupCount = 4;
2815 pSMB->Reserved = 0;
2816 pSMB->ParameterOffset = 0;
2817 pSMB->DataCount = 0;
2818 pSMB->DataOffset = 0;
2819 pSMB->SetupCount = 4;
2820 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2821 pSMB->ParameterCount = pSMB->TotalParameterCount;
2822 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2823 pSMB->IsFsctl = 1; /* FSCTL */
2824 pSMB->IsRootFlag = 0;
2825 pSMB->Fid = fid; /* file handle always le */
2826 pSMB->ByteCount = 0;
2827
2828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2830 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002831 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 } else { /* decode response */
2833 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2834 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002835 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2836 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002838 goto qreparse_out;
2839 }
2840 if (data_count && (data_count < 2048)) {
2841 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002842 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
Steve Frenchafe48c32009-05-02 05:25:46 +00002844 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002845 (struct reparse_data *)
2846 ((char *)&pSMBr->hdr.Protocol
2847 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002848 if ((char *)reparse_buf >= end_of_smb) {
2849 rc = -EIO;
2850 goto qreparse_out;
2851 }
2852 if ((reparse_buf->LinkNamesBuf +
2853 reparse_buf->TargetNameOffset +
2854 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002855 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002856 rc = -EIO;
2857 goto qreparse_out;
2858 }
Steve French50c2f752007-07-13 00:33:32 +00002859
Steve Frenchafe48c32009-05-02 05:25:46 +00002860 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2861 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002862 (reparse_buf->LinkNamesBuf +
2863 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002864 buflen,
2865 reparse_buf->TargetNameLen,
2866 nls_codepage, 0);
2867 } else { /* ASCII names */
2868 strncpy(symlinkinfo,
2869 reparse_buf->LinkNamesBuf +
2870 reparse_buf->TargetNameOffset,
2871 min_t(const int, buflen,
2872 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002874 } else {
2875 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002876 cFYI(1, "Invalid return data count on "
2877 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002879 symlinkinfo[buflen] = 0; /* just in case so the caller
2880 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002881 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 }
Steve French989c7e52009-05-02 05:32:20 +00002883
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002885 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 /* Note: On -EAGAIN error only caller can retry on handle based calls
2888 since file handle passed in no longer valid */
2889
2890 return rc;
2891}
Steve Frenchc52a9552011-02-24 06:16:22 +00002892#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893
2894#ifdef CONFIG_CIFS_POSIX
2895
2896/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002897static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2898 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899{
2900 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002901 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2902 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2903 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002904 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905
2906 return;
2907}
2908
2909/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002910static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2911 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912{
2913 int size = 0;
2914 int i;
2915 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002916 struct cifs_posix_ace *pACE;
2917 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2918 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2921 return -EOPNOTSUPP;
2922
Steve French790fe572007-07-07 19:25:05 +00002923 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 count = le16_to_cpu(cifs_acl->access_entry_count);
2925 pACE = &cifs_acl->ace_array[0];
2926 size = sizeof(struct cifs_posix_acl);
2927 size += sizeof(struct cifs_posix_ace) * count;
2928 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002929 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002930 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2931 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 return -EINVAL;
2933 }
Steve French790fe572007-07-07 19:25:05 +00002934 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 count = le16_to_cpu(cifs_acl->access_entry_count);
2936 size = sizeof(struct cifs_posix_acl);
2937 size += sizeof(struct cifs_posix_ace) * count;
2938/* skip past access ACEs to get to default ACEs */
2939 pACE = &cifs_acl->ace_array[count];
2940 count = le16_to_cpu(cifs_acl->default_entry_count);
2941 size += sizeof(struct cifs_posix_ace) * count;
2942 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002943 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 return -EINVAL;
2945 } else {
2946 /* illegal type */
2947 return -EINVAL;
2948 }
2949
2950 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002951 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002952 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002953 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 return -ERANGE;
2955 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002956 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002957 for (i = 0; i < count ; i++) {
2958 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2959 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 }
2961 }
2962 return size;
2963}
2964
Steve French50c2f752007-07-13 00:33:32 +00002965static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2966 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967{
2968 __u16 rc = 0; /* 0 = ACL converted ok */
2969
Steve Frenchff7feac2005-11-15 16:45:16 -08002970 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2971 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002973 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 /* Probably no need to le convert -1 on any arch but can not hurt */
2975 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002976 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002977 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002978 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 return rc;
2980}
2981
2982/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002983static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2984 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985{
2986 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002987 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2988 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 int count;
2990 int i;
2991
Steve French790fe572007-07-07 19:25:05 +00002992 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 return 0;
2994
2995 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002996 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002997 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002998 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002999 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003000 cFYI(1, "unknown POSIX ACL version %d",
3001 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 return 0;
3003 }
3004 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003005 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003006 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003007 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003008 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003010 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 return 0;
3012 }
Steve French50c2f752007-07-13 00:33:32 +00003013 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3015 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003016 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 /* ACE not converted */
3018 break;
3019 }
3020 }
Steve French790fe572007-07-07 19:25:05 +00003021 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3023 rc += sizeof(struct cifs_posix_acl);
3024 /* BB add check to make sure ACL does not overflow SMB */
3025 }
3026 return rc;
3027}
3028
3029int
Steve French96daf2b2011-05-27 04:34:02 +00003030CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003031 const unsigned char *searchName,
3032 char *acl_inf, const int buflen, const int acl_type,
3033 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034{
3035/* SMB_QUERY_POSIX_ACL */
3036 TRANSACTION2_QPI_REQ *pSMB = NULL;
3037 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3038 int rc = 0;
3039 int bytes_returned;
3040 int name_len;
3041 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003042
Joe Perchesb6b38f72010-04-21 03:50:45 +00003043 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
3045queryAclRetry:
3046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3047 (void **) &pSMBr);
3048 if (rc)
3049 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003050
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3052 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003053 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003054 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 name_len++; /* trailing null */
3056 name_len *= 2;
3057 pSMB->FileName[name_len] = 0;
3058 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003059 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 name_len = strnlen(searchName, PATH_MAX);
3061 name_len++; /* trailing null */
3062 strncpy(pSMB->FileName, searchName, name_len);
3063 }
3064
3065 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3066 pSMB->TotalDataCount = 0;
3067 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003068 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 pSMB->MaxDataCount = cpu_to_le16(4000);
3070 pSMB->MaxSetupCount = 0;
3071 pSMB->Reserved = 0;
3072 pSMB->Flags = 0;
3073 pSMB->Timeout = 0;
3074 pSMB->Reserved2 = 0;
3075 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003076 offsetof(struct smb_com_transaction2_qpi_req,
3077 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 pSMB->DataCount = 0;
3079 pSMB->DataOffset = 0;
3080 pSMB->SetupCount = 1;
3081 pSMB->Reserved3 = 0;
3082 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3083 byte_count = params + 1 /* pad */ ;
3084 pSMB->TotalParameterCount = cpu_to_le16(params);
3085 pSMB->ParameterCount = pSMB->TotalParameterCount;
3086 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3087 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003088 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 pSMB->ByteCount = cpu_to_le16(byte_count);
3090
3091 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3092 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003093 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003095 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 } else {
3097 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003098
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003101 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 rc = -EIO; /* bad smb */
3103 else {
3104 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3105 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3106 rc = cifs_copy_posix_acl(acl_inf,
3107 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003108 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109 }
3110 }
3111 cifs_buf_release(pSMB);
3112 if (rc == -EAGAIN)
3113 goto queryAclRetry;
3114 return rc;
3115}
3116
3117int
Steve French96daf2b2011-05-27 04:34:02 +00003118CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003119 const unsigned char *fileName,
3120 const char *local_acl, const int buflen,
3121 const int acl_type,
3122 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123{
3124 struct smb_com_transaction2_spi_req *pSMB = NULL;
3125 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3126 char *parm_data;
3127 int name_len;
3128 int rc = 0;
3129 int bytes_returned = 0;
3130 __u16 params, byte_count, data_count, param_offset, offset;
3131
Joe Perchesb6b38f72010-04-21 03:50:45 +00003132 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133setAclRetry:
3134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003135 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 if (rc)
3137 return rc;
3138 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3139 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003140 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003141 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 name_len++; /* trailing null */
3143 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003144 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 name_len = strnlen(fileName, PATH_MAX);
3146 name_len++; /* trailing null */
3147 strncpy(pSMB->FileName, fileName, name_len);
3148 }
3149 params = 6 + name_len;
3150 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003151 /* BB find max SMB size from sess */
3152 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 pSMB->MaxSetupCount = 0;
3154 pSMB->Reserved = 0;
3155 pSMB->Flags = 0;
3156 pSMB->Timeout = 0;
3157 pSMB->Reserved2 = 0;
3158 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003159 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 offset = param_offset + params;
3161 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3162 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3163
3164 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003165 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Steve French790fe572007-07-07 19:25:05 +00003167 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 rc = -EOPNOTSUPP;
3169 goto setACLerrorExit;
3170 }
3171 pSMB->DataOffset = cpu_to_le16(offset);
3172 pSMB->SetupCount = 1;
3173 pSMB->Reserved3 = 0;
3174 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3175 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3176 byte_count = 3 /* pad */ + params + data_count;
3177 pSMB->DataCount = cpu_to_le16(data_count);
3178 pSMB->TotalDataCount = pSMB->DataCount;
3179 pSMB->ParameterCount = cpu_to_le16(params);
3180 pSMB->TotalParameterCount = pSMB->ParameterCount;
3181 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003182 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003183 pSMB->ByteCount = cpu_to_le16(byte_count);
3184 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003185 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003186 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003187 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188
3189setACLerrorExit:
3190 cifs_buf_release(pSMB);
3191 if (rc == -EAGAIN)
3192 goto setAclRetry;
3193 return rc;
3194}
3195
Steve Frenchf654bac2005-04-28 22:41:04 -07003196/* BB fix tabs in this function FIXME BB */
3197int
Steve French96daf2b2011-05-27 04:34:02 +00003198CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003199 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003200{
Steve French50c2f752007-07-13 00:33:32 +00003201 int rc = 0;
3202 struct smb_t2_qfi_req *pSMB = NULL;
3203 struct smb_t2_qfi_rsp *pSMBr = NULL;
3204 int bytes_returned;
3205 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003206
Joe Perchesb6b38f72010-04-21 03:50:45 +00003207 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003208 if (tcon == NULL)
3209 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003210
3211GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003212 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3213 (void **) &pSMBr);
3214 if (rc)
3215 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003216
Steve Frenchad7a2922008-02-07 23:25:02 +00003217 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003218 pSMB->t2.TotalDataCount = 0;
3219 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3220 /* BB find exact max data count below from sess structure BB */
3221 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3222 pSMB->t2.MaxSetupCount = 0;
3223 pSMB->t2.Reserved = 0;
3224 pSMB->t2.Flags = 0;
3225 pSMB->t2.Timeout = 0;
3226 pSMB->t2.Reserved2 = 0;
3227 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3228 Fid) - 4);
3229 pSMB->t2.DataCount = 0;
3230 pSMB->t2.DataOffset = 0;
3231 pSMB->t2.SetupCount = 1;
3232 pSMB->t2.Reserved3 = 0;
3233 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3234 byte_count = params + 1 /* pad */ ;
3235 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3236 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3237 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3238 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003239 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003240 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003241 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003242
Steve French790fe572007-07-07 19:25:05 +00003243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3245 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003246 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003247 } else {
3248 /* decode response */
3249 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003250 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003251 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003252 /* If rc should we check for EOPNOSUPP and
3253 disable the srvino flag? or in caller? */
3254 rc = -EIO; /* bad smb */
3255 else {
3256 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3257 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3258 struct file_chattr_info *pfinfo;
3259 /* BB Do we need a cast or hash here ? */
3260 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003261 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003262 rc = -EIO;
3263 goto GetExtAttrOut;
3264 }
3265 pfinfo = (struct file_chattr_info *)
3266 (data_offset + (char *) &pSMBr->hdr.Protocol);
3267 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003268 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003269 }
3270 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003271GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003272 cifs_buf_release(pSMB);
3273 if (rc == -EAGAIN)
3274 goto GetExtAttrRetry;
3275 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003276}
3277
Steve Frenchf654bac2005-04-28 22:41:04 -07003278#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
Jeff Layton79df1ba2010-12-06 12:52:08 -05003280#ifdef CONFIG_CIFS_ACL
3281/*
3282 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3283 * all NT TRANSACTS that we init here have total parm and data under about 400
3284 * bytes (to fit in small cifs buffer size), which is the case so far, it
3285 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3286 * returned setup area) and MaxParameterCount (returned parms size) must be set
3287 * by caller
3288 */
3289static int
3290smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French96daf2b2011-05-27 04:34:02 +00003291 const int parm_len, struct cifs_tcon *tcon,
Jeff Layton79df1ba2010-12-06 12:52:08 -05003292 void **ret_buf)
3293{
3294 int rc;
3295 __u32 temp_offset;
3296 struct smb_com_ntransact_req *pSMB;
3297
3298 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3299 (void **)&pSMB);
3300 if (rc)
3301 return rc;
3302 *ret_buf = (void *)pSMB;
3303 pSMB->Reserved = 0;
3304 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3305 pSMB->TotalDataCount = 0;
Jeff Laytonc974bef2011-10-11 06:41:32 -04003306 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Jeff Layton79df1ba2010-12-06 12:52:08 -05003307 pSMB->ParameterCount = pSMB->TotalParameterCount;
3308 pSMB->DataCount = pSMB->TotalDataCount;
3309 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3310 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3311 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3312 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3313 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3314 pSMB->SubCommand = cpu_to_le16(sub_command);
3315 return 0;
3316}
3317
3318static int
3319validate_ntransact(char *buf, char **ppparm, char **ppdata,
3320 __u32 *pparmlen, __u32 *pdatalen)
3321{
3322 char *end_of_smb;
3323 __u32 data_count, data_offset, parm_count, parm_offset;
3324 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003325 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003326
3327 *pdatalen = 0;
3328 *pparmlen = 0;
3329
3330 if (buf == NULL)
3331 return -EINVAL;
3332
3333 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3334
Jeff Layton820a8032011-05-04 08:05:26 -04003335 bcc = get_bcc(&pSMBr->hdr);
3336 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003337 (char *)&pSMBr->ByteCount;
3338
3339 data_offset = le32_to_cpu(pSMBr->DataOffset);
3340 data_count = le32_to_cpu(pSMBr->DataCount);
3341 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3342 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3343
3344 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3345 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3346
3347 /* should we also check that parm and data areas do not overlap? */
3348 if (*ppparm > end_of_smb) {
3349 cFYI(1, "parms start after end of smb");
3350 return -EINVAL;
3351 } else if (parm_count + *ppparm > end_of_smb) {
3352 cFYI(1, "parm end after end of smb");
3353 return -EINVAL;
3354 } else if (*ppdata > end_of_smb) {
3355 cFYI(1, "data starts after end of smb");
3356 return -EINVAL;
3357 } else if (data_count + *ppdata > end_of_smb) {
3358 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3359 *ppdata, data_count, (data_count + *ppdata),
3360 end_of_smb, pSMBr);
3361 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003362 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003363 cFYI(1, "parm count and data count larger than SMB");
3364 return -EINVAL;
3365 }
3366 *pdatalen = data_count;
3367 *pparmlen = parm_count;
3368 return 0;
3369}
3370
Steve French0a4b92c2006-01-12 15:44:21 -08003371/* Get Security Descriptor (by handle) from remote server for a file or dir */
3372int
Steve French96daf2b2011-05-27 04:34:02 +00003373CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003374 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003375{
3376 int rc = 0;
3377 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003378 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003379 struct kvec iov[1];
3380
Joe Perchesb6b38f72010-04-21 03:50:45 +00003381 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003382
Steve French630f3f0c2007-10-25 21:17:17 +00003383 *pbuflen = 0;
3384 *acl_inf = NULL;
3385
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003386 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003387 8 /* parm len */, tcon, (void **) &pSMB);
3388 if (rc)
3389 return rc;
3390
3391 pSMB->MaxParameterCount = cpu_to_le32(4);
3392 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3393 pSMB->MaxSetupCount = 0;
3394 pSMB->Fid = fid; /* file handle always le */
3395 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3396 CIFS_ACL_DACL);
3397 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003398 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003399 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003400 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003401
Steve Frencha761ac52007-10-18 21:45:27 +00003402 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003403 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003404 cifs_stats_inc(&tcon->num_acl_get);
3405 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003406 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003407 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003408 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003409 __u32 parm_len;
3410 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003411 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003412 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003413
3414/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003415 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003416 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003417 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003418 goto qsec_out;
3419 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3420
Joe Perchesb6b38f72010-04-21 03:50:45 +00003421 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003422
3423 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3424 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003425 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003426 goto qsec_out;
3427 }
3428
3429/* BB check that data area is minimum length and as big as acl_len */
3430
Steve Frenchaf6f4612007-10-16 18:40:37 +00003431 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003432 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003433 cERROR(1, "acl length %d does not match %d",
3434 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003435 if (*pbuflen > acl_len)
3436 *pbuflen = acl_len;
3437 }
Steve French0a4b92c2006-01-12 15:44:21 -08003438
Steve French630f3f0c2007-10-25 21:17:17 +00003439 /* check if buffer is big enough for the acl
3440 header followed by the smallest SID */
3441 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3442 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003443 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003444 rc = -EINVAL;
3445 *pbuflen = 0;
3446 } else {
3447 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3448 if (*acl_inf == NULL) {
3449 *pbuflen = 0;
3450 rc = -ENOMEM;
3451 }
3452 memcpy(*acl_inf, pdata, *pbuflen);
3453 }
Steve French0a4b92c2006-01-12 15:44:21 -08003454 }
3455qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003456 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003457 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003458 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003459 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003460/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003461 return rc;
3462}
Steve French97837582007-12-31 07:47:21 +00003463
3464int
Steve French96daf2b2011-05-27 04:34:02 +00003465CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
Steve French97837582007-12-31 07:47:21 +00003466 struct cifs_ntsd *pntsd, __u32 acllen)
3467{
3468 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3469 int rc = 0;
3470 int bytes_returned = 0;
3471 SET_SEC_DESC_REQ *pSMB = NULL;
3472 NTRANSACT_RSP *pSMBr = NULL;
3473
3474setCifsAclRetry:
3475 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3476 (void **) &pSMBr);
3477 if (rc)
3478 return (rc);
3479
3480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482
3483 param_count = 8;
3484 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3485 data_count = acllen;
3486 data_offset = param_offset + param_count;
3487 byte_count = 3 /* pad */ + param_count;
3488
3489 pSMB->DataCount = cpu_to_le32(data_count);
3490 pSMB->TotalDataCount = pSMB->DataCount;
3491 pSMB->MaxParameterCount = cpu_to_le32(4);
3492 pSMB->MaxDataCount = cpu_to_le32(16384);
3493 pSMB->ParameterCount = cpu_to_le32(param_count);
3494 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3495 pSMB->TotalParameterCount = pSMB->ParameterCount;
3496 pSMB->DataOffset = cpu_to_le32(data_offset);
3497 pSMB->SetupCount = 0;
3498 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3499 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3500
3501 pSMB->Fid = fid; /* file handle always le */
3502 pSMB->Reserved2 = 0;
3503 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3504
3505 if (pntsd && acllen) {
3506 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3507 (char *) pntsd,
3508 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003509 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003510 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003511 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003512
3513 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3514 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3515
Joe Perchesb6b38f72010-04-21 03:50:45 +00003516 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003517 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003518 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003519 cifs_buf_release(pSMB);
3520
3521 if (rc == -EAGAIN)
3522 goto setCifsAclRetry;
3523
3524 return (rc);
3525}
3526
Jeff Layton79df1ba2010-12-06 12:52:08 -05003527#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003528
Steve French6b8edfe2005-08-23 20:26:03 -07003529/* Legacy Query Path Information call for lookup to old servers such
3530 as Win9x/WinME */
Steve French96daf2b2011-05-27 04:34:02 +00003531int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003532 const unsigned char *searchName,
3533 FILE_ALL_INFO *pFinfo,
3534 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003535{
Steve Frenchad7a2922008-02-07 23:25:02 +00003536 QUERY_INFORMATION_REQ *pSMB;
3537 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003538 int rc = 0;
3539 int bytes_returned;
3540 int name_len;
3541
Joe Perchesb6b38f72010-04-21 03:50:45 +00003542 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003543QInfRetry:
3544 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003545 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003546 if (rc)
3547 return rc;
3548
3549 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3550 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003551 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3552 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003553 name_len++; /* trailing null */
3554 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003555 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003556 name_len = strnlen(searchName, PATH_MAX);
3557 name_len++; /* trailing null */
3558 strncpy(pSMB->FileName, searchName, name_len);
3559 }
3560 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003561 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003562 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003563 pSMB->ByteCount = cpu_to_le16(name_len);
3564
3565 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003566 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003567 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003568 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003569 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003570 struct timespec ts;
3571 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003572
3573 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003574 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003575 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003576 ts.tv_nsec = 0;
3577 ts.tv_sec = time;
3578 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003579 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003580 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3581 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003582 pFinfo->AllocationSize =
3583 cpu_to_le64(le32_to_cpu(pSMBr->size));
3584 pFinfo->EndOfFile = pFinfo->AllocationSize;
3585 pFinfo->Attributes =
3586 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003587 } else
3588 rc = -EIO; /* bad buffer passed in */
3589
3590 cifs_buf_release(pSMB);
3591
3592 if (rc == -EAGAIN)
3593 goto QInfRetry;
3594
3595 return rc;
3596}
3597
Jeff Laytonbcd53572010-02-12 07:44:16 -05003598int
Steve French96daf2b2011-05-27 04:34:02 +00003599CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonbcd53572010-02-12 07:44:16 -05003600 u16 netfid, FILE_ALL_INFO *pFindData)
3601{
3602 struct smb_t2_qfi_req *pSMB = NULL;
3603 struct smb_t2_qfi_rsp *pSMBr = NULL;
3604 int rc = 0;
3605 int bytes_returned;
3606 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003607
Jeff Laytonbcd53572010-02-12 07:44:16 -05003608QFileInfoRetry:
3609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3610 (void **) &pSMBr);
3611 if (rc)
3612 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003613
Jeff Laytonbcd53572010-02-12 07:44:16 -05003614 params = 2 /* level */ + 2 /* fid */;
3615 pSMB->t2.TotalDataCount = 0;
3616 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3617 /* BB find exact max data count below from sess structure BB */
3618 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3619 pSMB->t2.MaxSetupCount = 0;
3620 pSMB->t2.Reserved = 0;
3621 pSMB->t2.Flags = 0;
3622 pSMB->t2.Timeout = 0;
3623 pSMB->t2.Reserved2 = 0;
3624 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3625 Fid) - 4);
3626 pSMB->t2.DataCount = 0;
3627 pSMB->t2.DataOffset = 0;
3628 pSMB->t2.SetupCount = 1;
3629 pSMB->t2.Reserved3 = 0;
3630 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3631 byte_count = params + 1 /* pad */ ;
3632 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3633 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3634 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3635 pSMB->Pad = 0;
3636 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003637 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003638
3639 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3640 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3641 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003642 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003643 } else { /* decode response */
3644 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3645
3646 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3647 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003648 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003649 rc = -EIO; /* bad smb */
3650 else if (pFindData) {
3651 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3652 memcpy((char *) pFindData,
3653 (char *) &pSMBr->hdr.Protocol +
3654 data_offset, sizeof(FILE_ALL_INFO));
3655 } else
3656 rc = -ENOMEM;
3657 }
3658 cifs_buf_release(pSMB);
3659 if (rc == -EAGAIN)
3660 goto QFileInfoRetry;
3661
3662 return rc;
3663}
Steve French6b8edfe2005-08-23 20:26:03 -07003664
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665int
Steve French96daf2b2011-05-27 04:34:02 +00003666CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003668 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003669 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003670 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671{
3672/* level 263 SMB_QUERY_FILE_ALL_INFO */
3673 TRANSACTION2_QPI_REQ *pSMB = NULL;
3674 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3675 int rc = 0;
3676 int bytes_returned;
3677 int name_len;
3678 __u16 params, byte_count;
3679
Joe Perchesb6b38f72010-04-21 03:50:45 +00003680/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681QPathInfoRetry:
3682 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3683 (void **) &pSMBr);
3684 if (rc)
3685 return rc;
3686
3687 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3688 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003689 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003690 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 name_len++; /* trailing null */
3692 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003693 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 name_len = strnlen(searchName, PATH_MAX);
3695 name_len++; /* trailing null */
3696 strncpy(pSMB->FileName, searchName, name_len);
3697 }
3698
Steve French50c2f752007-07-13 00:33:32 +00003699 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 pSMB->TotalDataCount = 0;
3701 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003702 /* BB find exact max SMB PDU from sess structure BB */
3703 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 pSMB->MaxSetupCount = 0;
3705 pSMB->Reserved = 0;
3706 pSMB->Flags = 0;
3707 pSMB->Timeout = 0;
3708 pSMB->Reserved2 = 0;
3709 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003710 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 pSMB->DataCount = 0;
3712 pSMB->DataOffset = 0;
3713 pSMB->SetupCount = 1;
3714 pSMB->Reserved3 = 0;
3715 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3716 byte_count = params + 1 /* pad */ ;
3717 pSMB->TotalParameterCount = cpu_to_le16(params);
3718 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003719 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003720 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3721 else
3722 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003724 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 pSMB->ByteCount = cpu_to_le16(byte_count);
3726
3727 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3728 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3729 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003730 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 } else { /* decode response */
3732 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3733
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003734 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3735 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003736 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003738 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003739 rc = -EIO; /* 24 or 26 expected but we do not read
3740 last field */
3741 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003742 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003744
3745 /* On legacy responses we do not read the last field,
3746 EAsize, fortunately since it varies by subdialect and
3747 also note it differs on Set vs. Get, ie two bytes or 4
3748 bytes depending but we don't care here */
3749 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003750 size = sizeof(FILE_INFO_STANDARD);
3751 else
3752 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003753 memcpy((char *) pFindData,
3754 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003755 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 } else
3757 rc = -ENOMEM;
3758 }
3759 cifs_buf_release(pSMB);
3760 if (rc == -EAGAIN)
3761 goto QPathInfoRetry;
3762
3763 return rc;
3764}
3765
3766int
Steve French96daf2b2011-05-27 04:34:02 +00003767CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003768 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3769{
3770 struct smb_t2_qfi_req *pSMB = NULL;
3771 struct smb_t2_qfi_rsp *pSMBr = NULL;
3772 int rc = 0;
3773 int bytes_returned;
3774 __u16 params, byte_count;
3775
3776UnixQFileInfoRetry:
3777 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3778 (void **) &pSMBr);
3779 if (rc)
3780 return rc;
3781
3782 params = 2 /* level */ + 2 /* fid */;
3783 pSMB->t2.TotalDataCount = 0;
3784 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3785 /* BB find exact max data count below from sess structure BB */
3786 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3787 pSMB->t2.MaxSetupCount = 0;
3788 pSMB->t2.Reserved = 0;
3789 pSMB->t2.Flags = 0;
3790 pSMB->t2.Timeout = 0;
3791 pSMB->t2.Reserved2 = 0;
3792 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3793 Fid) - 4);
3794 pSMB->t2.DataCount = 0;
3795 pSMB->t2.DataOffset = 0;
3796 pSMB->t2.SetupCount = 1;
3797 pSMB->t2.Reserved3 = 0;
3798 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3799 byte_count = params + 1 /* pad */ ;
3800 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3801 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3802 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3803 pSMB->Pad = 0;
3804 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003805 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003806
3807 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3808 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3809 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003810 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003811 } else { /* decode response */
3812 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3813
Jeff Layton820a8032011-05-04 08:05:26 -04003814 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003815 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003816 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003817 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003818 rc = -EIO; /* bad smb */
3819 } else {
3820 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3821 memcpy((char *) pFindData,
3822 (char *) &pSMBr->hdr.Protocol +
3823 data_offset,
3824 sizeof(FILE_UNIX_BASIC_INFO));
3825 }
3826 }
3827
3828 cifs_buf_release(pSMB);
3829 if (rc == -EAGAIN)
3830 goto UnixQFileInfoRetry;
3831
3832 return rc;
3833}
3834
3835int
Steve French96daf2b2011-05-27 04:34:02 +00003836CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003838 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003839 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840{
3841/* SMB_QUERY_FILE_UNIX_BASIC */
3842 TRANSACTION2_QPI_REQ *pSMB = NULL;
3843 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3844 int rc = 0;
3845 int bytes_returned = 0;
3846 int name_len;
3847 __u16 params, byte_count;
3848
Joe Perchesb6b38f72010-04-21 03:50:45 +00003849 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850UnixQPathInfoRetry:
3851 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3852 (void **) &pSMBr);
3853 if (rc)
3854 return rc;
3855
3856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3857 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003858 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003859 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003860 name_len++; /* trailing null */
3861 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003862 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 name_len = strnlen(searchName, PATH_MAX);
3864 name_len++; /* trailing null */
3865 strncpy(pSMB->FileName, searchName, name_len);
3866 }
3867
Steve French50c2f752007-07-13 00:33:32 +00003868 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 pSMB->TotalDataCount = 0;
3870 pSMB->MaxParameterCount = cpu_to_le16(2);
3871 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003872 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 pSMB->MaxSetupCount = 0;
3874 pSMB->Reserved = 0;
3875 pSMB->Flags = 0;
3876 pSMB->Timeout = 0;
3877 pSMB->Reserved2 = 0;
3878 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003879 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 pSMB->DataCount = 0;
3881 pSMB->DataOffset = 0;
3882 pSMB->SetupCount = 1;
3883 pSMB->Reserved3 = 0;
3884 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3885 byte_count = params + 1 /* pad */ ;
3886 pSMB->TotalParameterCount = cpu_to_le16(params);
3887 pSMB->ParameterCount = pSMB->TotalParameterCount;
3888 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3889 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003890 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 pSMB->ByteCount = cpu_to_le16(byte_count);
3892
3893 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3894 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3895 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003896 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 } else { /* decode response */
3898 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3899
Jeff Layton820a8032011-05-04 08:05:26 -04003900 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003901 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003902 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003903 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 rc = -EIO; /* bad smb */
3905 } else {
3906 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3907 memcpy((char *) pFindData,
3908 (char *) &pSMBr->hdr.Protocol +
3909 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003910 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 }
3912 }
3913 cifs_buf_release(pSMB);
3914 if (rc == -EAGAIN)
3915 goto UnixQPathInfoRetry;
3916
3917 return rc;
3918}
3919
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920/* xid, tcon, searchName and codepage are input parms, rest are returned */
3921int
Steve French96daf2b2011-05-27 04:34:02 +00003922CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003923 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003925 __u16 *pnetfid,
3926 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927{
3928/* level 257 SMB_ */
3929 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3930 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003931 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 int rc = 0;
3933 int bytes_returned = 0;
3934 int name_len;
3935 __u16 params, byte_count;
3936
Joe Perchesb6b38f72010-04-21 03:50:45 +00003937 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938
3939findFirstRetry:
3940 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3941 (void **) &pSMBr);
3942 if (rc)
3943 return rc;
3944
3945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3946 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003947 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003948 PATH_MAX, nls_codepage, remap);
3949 /* We can not add the asterik earlier in case
3950 it got remapped to 0xF03A as if it were part of the
3951 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003953 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003954 pSMB->FileName[name_len+1] = 0;
3955 pSMB->FileName[name_len+2] = '*';
3956 pSMB->FileName[name_len+3] = 0;
3957 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3959 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003960 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 } else { /* BB add check for overrun of SMB buf BB */
3962 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003964 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 free buffer exit; BB */
3966 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003967 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003968 pSMB->FileName[name_len+1] = '*';
3969 pSMB->FileName[name_len+2] = 0;
3970 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 }
3972
3973 params = 12 + name_len /* includes null */ ;
3974 pSMB->TotalDataCount = 0; /* no EAs */
3975 pSMB->MaxParameterCount = cpu_to_le16(10);
Jeff Laytonc974bef2011-10-11 06:41:32 -04003976 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 pSMB->MaxSetupCount = 0;
3978 pSMB->Reserved = 0;
3979 pSMB->Flags = 0;
3980 pSMB->Timeout = 0;
3981 pSMB->Reserved2 = 0;
3982 byte_count = params + 1 /* pad */ ;
3983 pSMB->TotalParameterCount = cpu_to_le16(params);
3984 pSMB->ParameterCount = pSMB->TotalParameterCount;
3985 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003986 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3987 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 pSMB->DataCount = 0;
3989 pSMB->DataOffset = 0;
3990 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3991 pSMB->Reserved3 = 0;
3992 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3993 pSMB->SearchAttributes =
3994 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3995 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003996 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3997 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 CIFS_SEARCH_RETURN_RESUME);
3999 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4000
4001 /* BB what should we set StorageType to? Does it matter? BB */
4002 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004003 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 pSMB->ByteCount = cpu_to_le16(byte_count);
4005
4006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004008 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009
Steve French88274812006-03-09 22:21:45 +00004010 if (rc) {/* BB add logic to retry regular search if Unix search
4011 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004013 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004014
Steve French88274812006-03-09 22:21:45 +00004015 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
4017 /* BB eventually could optimize out free and realloc of buf */
4018 /* for this case */
4019 if (rc == -EAGAIN)
4020 goto findFirstRetry;
4021 } else { /* decode response */
4022 /* BB remember to free buffer if error BB */
4023 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004024 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004025 unsigned int lnoff;
4026
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004028 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 else
Steve French4b18f2a2008-04-29 00:06:05 +00004030 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031
4032 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004033 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004034 psrch_inf->srch_entries_start =
4035 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4038 le16_to_cpu(pSMBr->t2.ParameterOffset));
4039
Steve French790fe572007-07-07 19:25:05 +00004040 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004041 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 else
Steve French4b18f2a2008-04-29 00:06:05 +00004043 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
Steve French50c2f752007-07-13 00:33:32 +00004045 psrch_inf->entries_in_buffer =
4046 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004047 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004049 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004050 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004051 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004052 psrch_inf->last_entry = NULL;
4053 return rc;
4054 }
4055
Steve French0752f152008-10-07 20:03:33 +00004056 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004057 lnoff;
4058
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 *pnetfid = parms->SearchHandle;
4060 } else {
4061 cifs_buf_release(pSMB);
4062 }
4063 }
4064
4065 return rc;
4066}
4067
Steve French96daf2b2011-05-27 04:34:02 +00004068int CIFSFindNext(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004069 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070{
4071 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4072 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004073 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 char *response_data;
4075 int rc = 0;
Jeff Layton9438fab2011-08-23 07:21:28 -04004076 int bytes_returned;
4077 unsigned int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 __u16 params, byte_count;
4079
Joe Perchesb6b38f72010-04-21 03:50:45 +00004080 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081
Steve French4b18f2a2008-04-29 00:06:05 +00004082 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 return -ENOENT;
4084
4085 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4086 (void **) &pSMBr);
4087 if (rc)
4088 return rc;
4089
Steve French50c2f752007-07-13 00:33:32 +00004090 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 byte_count = 0;
4092 pSMB->TotalDataCount = 0; /* no EAs */
4093 pSMB->MaxParameterCount = cpu_to_le16(8);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004094 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 pSMB->MaxSetupCount = 0;
4096 pSMB->Reserved = 0;
4097 pSMB->Flags = 0;
4098 pSMB->Timeout = 0;
4099 pSMB->Reserved2 = 0;
4100 pSMB->ParameterOffset = cpu_to_le16(
4101 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4102 pSMB->DataCount = 0;
4103 pSMB->DataOffset = 0;
4104 pSMB->SetupCount = 1;
4105 pSMB->Reserved3 = 0;
4106 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4107 pSMB->SearchHandle = searchHandle; /* always kept as le */
4108 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004109 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4111 pSMB->ResumeKey = psrch_inf->resume_key;
4112 pSMB->SearchFlags =
4113 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4114
4115 name_len = psrch_inf->resume_name_len;
4116 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004117 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4119 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004120 /* 14 byte parm len above enough for 2 byte null terminator */
4121 pSMB->ResumeFileName[name_len] = 0;
4122 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 } else {
4124 rc = -EINVAL;
4125 goto FNext2_err_exit;
4126 }
4127 byte_count = params + 1 /* pad */ ;
4128 pSMB->TotalParameterCount = cpu_to_le16(params);
4129 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004130 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004131 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004132
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004135 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 if (rc) {
4137 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004138 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004139 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004140 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004142 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 } else { /* decode response */
4144 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004145
Steve French790fe572007-07-07 19:25:05 +00004146 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004147 unsigned int lnoff;
4148
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 /* BB fixme add lock for file (srch_info) struct here */
4150 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004151 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152 else
Steve French4b18f2a2008-04-29 00:06:05 +00004153 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 response_data = (char *) &pSMBr->hdr.Protocol +
4155 le16_to_cpu(pSMBr->t2.ParameterOffset);
4156 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4157 response_data = (char *)&pSMBr->hdr.Protocol +
4158 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004159 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004160 cifs_small_buf_release(
4161 psrch_inf->ntwrk_buf_start);
4162 else
4163 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 psrch_inf->srch_entries_start = response_data;
4165 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004166 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004167 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004168 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 else
Steve French4b18f2a2008-04-29 00:06:05 +00004170 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004171 psrch_inf->entries_in_buffer =
4172 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 psrch_inf->index_of_last_entry +=
4174 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004175 lnoff = le16_to_cpu(parms->LastNameOffset);
Jeff Laytonc974bef2011-10-11 06:41:32 -04004176 if (CIFSMaxBufSize < lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004177 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004178 psrch_inf->last_entry = NULL;
4179 return rc;
4180 } else
4181 psrch_inf->last_entry =
4182 psrch_inf->srch_entries_start + lnoff;
4183
Joe Perchesb6b38f72010-04-21 03:50:45 +00004184/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4185 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
4187 /* BB fixme add unlock here */
4188 }
4189
4190 }
4191
4192 /* BB On error, should we leave previous search buf (and count and
4193 last entry fields) intact or free the previous one? */
4194
4195 /* Note: On -EAGAIN error only caller can retry on handle based calls
4196 since file handle passed in no longer valid */
4197FNext2_err_exit:
4198 if (rc != 0)
4199 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004200 return rc;
4201}
4202
4203int
Steve French96daf2b2011-05-27 04:34:02 +00004204CIFSFindClose(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004205 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206{
4207 int rc = 0;
4208 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209
Joe Perchesb6b38f72010-04-21 03:50:45 +00004210 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4212
4213 /* no sense returning error if session restarted
4214 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004215 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216 return 0;
4217 if (rc)
4218 return rc;
4219
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220 pSMB->FileID = searchHandle;
4221 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004222 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004223 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004224 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004225
Steve Frencha4544342005-08-24 13:59:35 -07004226 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227
4228 /* Since session is dead, search handle closed on server already */
4229 if (rc == -EAGAIN)
4230 rc = 0;
4231
4232 return rc;
4233}
4234
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235int
Steve French96daf2b2011-05-27 04:34:02 +00004236CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004237 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004238 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004239 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240{
4241 int rc = 0;
4242 TRANSACTION2_QPI_REQ *pSMB = NULL;
4243 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4244 int name_len, bytes_returned;
4245 __u16 params, byte_count;
4246
Joe Perchesb6b38f72010-04-21 03:50:45 +00004247 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004248 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004249 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250
4251GetInodeNumberRetry:
4252 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004253 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 if (rc)
4255 return rc;
4256
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4258 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004259 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004260 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 name_len++; /* trailing null */
4262 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004263 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 name_len = strnlen(searchName, PATH_MAX);
4265 name_len++; /* trailing null */
4266 strncpy(pSMB->FileName, searchName, name_len);
4267 }
4268
4269 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4270 pSMB->TotalDataCount = 0;
4271 pSMB->MaxParameterCount = cpu_to_le16(2);
4272 /* BB find exact max data count below from sess structure BB */
4273 pSMB->MaxDataCount = cpu_to_le16(4000);
4274 pSMB->MaxSetupCount = 0;
4275 pSMB->Reserved = 0;
4276 pSMB->Flags = 0;
4277 pSMB->Timeout = 0;
4278 pSMB->Reserved2 = 0;
4279 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004280 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281 pSMB->DataCount = 0;
4282 pSMB->DataOffset = 0;
4283 pSMB->SetupCount = 1;
4284 pSMB->Reserved3 = 0;
4285 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4286 byte_count = params + 1 /* pad */ ;
4287 pSMB->TotalParameterCount = cpu_to_le16(params);
4288 pSMB->ParameterCount = pSMB->TotalParameterCount;
4289 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4290 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004291 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 pSMB->ByteCount = cpu_to_le16(byte_count);
4293
4294 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4295 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4296 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004297 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 } else {
4299 /* decode response */
4300 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004302 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 /* If rc should we check for EOPNOSUPP and
4304 disable the srvino flag? or in caller? */
4305 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004306 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4308 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004309 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004311 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004312 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 rc = -EIO;
4314 goto GetInodeNumOut;
4315 }
4316 pfinfo = (struct file_internal_info *)
4317 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004318 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 }
4320 }
4321GetInodeNumOut:
4322 cifs_buf_release(pSMB);
4323 if (rc == -EAGAIN)
4324 goto GetInodeNumberRetry;
4325 return rc;
4326}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004327
Igor Mammedovfec45852008-05-16 13:06:30 +04004328/* parses DFS refferal V3 structure
4329 * caller is responsible for freeing target_nodes
4330 * returns:
4331 * on success - 0
4332 * on failure - errno
4333 */
4334static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004335parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004336 unsigned int *num_of_nodes,
4337 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004338 const struct nls_table *nls_codepage, int remap,
4339 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004340{
4341 int i, rc = 0;
4342 char *data_end;
4343 bool is_unicode;
4344 struct dfs_referral_level_3 *ref;
4345
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004346 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4347 is_unicode = true;
4348 else
4349 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004350 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4351
4352 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004353 cERROR(1, "num_referrals: must be at least > 0,"
4354 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004355 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004356 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004357 }
4358
4359 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004360 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004361 cERROR(1, "Referrals of V%d version are not supported,"
4362 "should be V3", le16_to_cpu(ref->VersionNumber));
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 /* get the upper boundary of the resp buffer */
4368 data_end = (char *)(&(pSMBr->PathConsumed)) +
4369 le16_to_cpu(pSMBr->t2.DataCount);
4370
Steve Frenchf19159d2010-04-21 04:12:10 +00004371 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004372 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004373 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004374
4375 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4376 *num_of_nodes, GFP_KERNEL);
4377 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004378 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004379 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004380 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004381 }
4382
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004383 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004384 for (i = 0; i < *num_of_nodes; i++) {
4385 char *temp;
4386 int max_len;
4387 struct dfs_info3_param *node = (*target_nodes)+i;
4388
Steve French0e0d2cf2009-05-01 05:27:32 +00004389 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004390 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004391 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4392 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004393 if (tmp == NULL) {
4394 rc = -ENOMEM;
4395 goto parse_DFS_referrals_exit;
4396 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004397 cifsConvertToUCS((__le16 *) tmp, searchName,
4398 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004399 node->path_consumed = cifs_ucs2_bytes(tmp,
4400 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004401 nls_codepage);
4402 kfree(tmp);
4403 } else
4404 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4405
Igor Mammedovfec45852008-05-16 13:06:30 +04004406 node->server_type = le16_to_cpu(ref->ServerType);
4407 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4408
4409 /* copy DfsPath */
4410 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4411 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004412 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4413 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004414 if (!node->path_name) {
4415 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004416 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004417 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004418
4419 /* copy link target UNC */
4420 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4421 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004422 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4423 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004424 if (!node->node_name)
4425 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004426 }
4427
Steve Frencha1fe78f2008-05-16 18:48:38 +00004428parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004429 if (rc) {
4430 free_dfs_info_array(*target_nodes, *num_of_nodes);
4431 *target_nodes = NULL;
4432 *num_of_nodes = 0;
4433 }
4434 return rc;
4435}
4436
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437int
Steve French96daf2b2011-05-27 04:34:02 +00004438CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004440 struct dfs_info3_param **target_nodes,
4441 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004442 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443{
4444/* TRANS2_GET_DFS_REFERRAL */
4445 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4446 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 int rc = 0;
4448 int bytes_returned;
4449 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004451 *num_of_nodes = 0;
4452 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453
Joe Perchesb6b38f72010-04-21 03:50:45 +00004454 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 if (ses == NULL)
4456 return -ENODEV;
4457getDFSRetry:
4458 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4459 (void **) &pSMBr);
4460 if (rc)
4461 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004462
4463 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004464 but should never be null here anyway */
4465 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 pSMB->hdr.Tid = ses->ipc_tid;
4467 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004468 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004470 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472
4473 if (ses->capabilities & CAP_UNICODE) {
4474 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4475 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004476 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004477 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 name_len++; /* trailing null */
4479 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004480 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 name_len = strnlen(searchName, PATH_MAX);
4482 name_len++; /* trailing null */
4483 strncpy(pSMB->RequestFileName, searchName, name_len);
4484 }
4485
Steve French790fe572007-07-07 19:25:05 +00004486 if (ses->server) {
Steve French96daf2b2011-05-27 04:34:02 +00004487 if (ses->server->sec_mode &
Steve French1a4e15a2006-10-12 21:33:51 +00004488 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4489 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4490 }
4491
Steve French50c2f752007-07-13 00:33:32 +00004492 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004493
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 params = 2 /* level */ + name_len /*includes null */ ;
4495 pSMB->TotalDataCount = 0;
4496 pSMB->DataCount = 0;
4497 pSMB->DataOffset = 0;
4498 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004499 /* BB find exact max SMB PDU from sess structure BB */
4500 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 pSMB->MaxSetupCount = 0;
4502 pSMB->Reserved = 0;
4503 pSMB->Flags = 0;
4504 pSMB->Timeout = 0;
4505 pSMB->Reserved2 = 0;
4506 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004507 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 pSMB->SetupCount = 1;
4509 pSMB->Reserved3 = 0;
4510 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4511 byte_count = params + 3 /* pad */ ;
4512 pSMB->ParameterCount = cpu_to_le16(params);
4513 pSMB->TotalParameterCount = pSMB->ParameterCount;
4514 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004515 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 pSMB->ByteCount = cpu_to_le16(byte_count);
4517
4518 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4519 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4520 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004521 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004522 goto GetDFSRefExit;
4523 }
4524 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004526 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004527 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004528 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004529 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004531
Joe Perchesb6b38f72010-04-21 03:50:45 +00004532 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004533 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004534 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004535
4536 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004537 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004538 target_nodes, nls_codepage, remap,
4539 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004540
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004542 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543
4544 if (rc == -EAGAIN)
4545 goto getDFSRetry;
4546
4547 return rc;
4548}
4549
Steve French20962432005-09-21 22:05:57 -07004550/* Query File System Info such as free space to old servers such as Win 9x */
4551int
Steve French96daf2b2011-05-27 04:34:02 +00004552SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Steve French20962432005-09-21 22:05:57 -07004553{
4554/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4555 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4556 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4557 FILE_SYSTEM_ALLOC_INFO *response_data;
4558 int rc = 0;
4559 int bytes_returned = 0;
4560 __u16 params, byte_count;
4561
Joe Perchesb6b38f72010-04-21 03:50:45 +00004562 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004563oldQFSInfoRetry:
4564 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4565 (void **) &pSMBr);
4566 if (rc)
4567 return rc;
Steve French20962432005-09-21 22:05:57 -07004568
4569 params = 2; /* level */
4570 pSMB->TotalDataCount = 0;
4571 pSMB->MaxParameterCount = cpu_to_le16(2);
4572 pSMB->MaxDataCount = cpu_to_le16(1000);
4573 pSMB->MaxSetupCount = 0;
4574 pSMB->Reserved = 0;
4575 pSMB->Flags = 0;
4576 pSMB->Timeout = 0;
4577 pSMB->Reserved2 = 0;
4578 byte_count = params + 1 /* pad */ ;
4579 pSMB->TotalParameterCount = cpu_to_le16(params);
4580 pSMB->ParameterCount = pSMB->TotalParameterCount;
4581 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4582 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4583 pSMB->DataCount = 0;
4584 pSMB->DataOffset = 0;
4585 pSMB->SetupCount = 1;
4586 pSMB->Reserved3 = 0;
4587 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4588 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004589 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004590 pSMB->ByteCount = cpu_to_le16(byte_count);
4591
4592 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4593 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4594 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004595 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004596 } else { /* decode response */
4597 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4598
Jeff Layton820a8032011-05-04 08:05:26 -04004599 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004600 rc = -EIO; /* bad smb */
4601 else {
4602 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004603 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004604 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004605
Steve French50c2f752007-07-13 00:33:32 +00004606 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004607 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4608 FSData->f_bsize =
4609 le16_to_cpu(response_data->BytesPerSector) *
4610 le32_to_cpu(response_data->
4611 SectorsPerAllocationUnit);
4612 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004613 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004614 FSData->f_bfree = FSData->f_bavail =
4615 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004616 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4617 (unsigned long long)FSData->f_blocks,
4618 (unsigned long long)FSData->f_bfree,
4619 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004620 }
4621 }
4622 cifs_buf_release(pSMB);
4623
4624 if (rc == -EAGAIN)
4625 goto oldQFSInfoRetry;
4626
4627 return rc;
4628}
4629
Linus Torvalds1da177e2005-04-16 15:20:36 -07004630int
Steve French96daf2b2011-05-27 04:34:02 +00004631CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632{
4633/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4634 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4635 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4636 FILE_SYSTEM_INFO *response_data;
4637 int rc = 0;
4638 int bytes_returned = 0;
4639 __u16 params, byte_count;
4640
Joe Perchesb6b38f72010-04-21 03:50:45 +00004641 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642QFSInfoRetry:
4643 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4644 (void **) &pSMBr);
4645 if (rc)
4646 return rc;
4647
4648 params = 2; /* level */
4649 pSMB->TotalDataCount = 0;
4650 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004651 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 pSMB->MaxSetupCount = 0;
4653 pSMB->Reserved = 0;
4654 pSMB->Flags = 0;
4655 pSMB->Timeout = 0;
4656 pSMB->Reserved2 = 0;
4657 byte_count = params + 1 /* pad */ ;
4658 pSMB->TotalParameterCount = cpu_to_le16(params);
4659 pSMB->ParameterCount = pSMB->TotalParameterCount;
4660 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004661 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 pSMB->DataCount = 0;
4663 pSMB->DataOffset = 0;
4664 pSMB->SetupCount = 1;
4665 pSMB->Reserved3 = 0;
4666 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4667 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004668 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 pSMB->ByteCount = cpu_to_le16(byte_count);
4670
4671 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4672 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4673 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004674 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004676 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677
Jeff Layton820a8032011-05-04 08:05:26 -04004678 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 rc = -EIO; /* bad smb */
4680 else {
4681 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682
4683 response_data =
4684 (FILE_SYSTEM_INFO
4685 *) (((char *) &pSMBr->hdr.Protocol) +
4686 data_offset);
4687 FSData->f_bsize =
4688 le32_to_cpu(response_data->BytesPerSector) *
4689 le32_to_cpu(response_data->
4690 SectorsPerAllocationUnit);
4691 FSData->f_blocks =
4692 le64_to_cpu(response_data->TotalAllocationUnits);
4693 FSData->f_bfree = FSData->f_bavail =
4694 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004695 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4696 (unsigned long long)FSData->f_blocks,
4697 (unsigned long long)FSData->f_bfree,
4698 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 }
4700 }
4701 cifs_buf_release(pSMB);
4702
4703 if (rc == -EAGAIN)
4704 goto QFSInfoRetry;
4705
4706 return rc;
4707}
4708
4709int
Steve French96daf2b2011-05-27 04:34:02 +00004710CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711{
4712/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4713 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4714 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4715 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4716 int rc = 0;
4717 int bytes_returned = 0;
4718 __u16 params, byte_count;
4719
Joe Perchesb6b38f72010-04-21 03:50:45 +00004720 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721QFSAttributeRetry:
4722 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4723 (void **) &pSMBr);
4724 if (rc)
4725 return rc;
4726
4727 params = 2; /* level */
4728 pSMB->TotalDataCount = 0;
4729 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004730 /* BB find exact max SMB PDU from sess structure BB */
4731 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 pSMB->MaxSetupCount = 0;
4733 pSMB->Reserved = 0;
4734 pSMB->Flags = 0;
4735 pSMB->Timeout = 0;
4736 pSMB->Reserved2 = 0;
4737 byte_count = params + 1 /* pad */ ;
4738 pSMB->TotalParameterCount = cpu_to_le16(params);
4739 pSMB->ParameterCount = pSMB->TotalParameterCount;
4740 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004741 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 pSMB->DataCount = 0;
4743 pSMB->DataOffset = 0;
4744 pSMB->SetupCount = 1;
4745 pSMB->Reserved3 = 0;
4746 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4747 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004748 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 pSMB->ByteCount = cpu_to_le16(byte_count);
4750
4751 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4752 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4753 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004754 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 } else { /* decode response */
4756 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4757
Jeff Layton820a8032011-05-04 08:05:26 -04004758 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004759 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 rc = -EIO; /* bad smb */
4761 } else {
4762 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4763 response_data =
4764 (FILE_SYSTEM_ATTRIBUTE_INFO
4765 *) (((char *) &pSMBr->hdr.Protocol) +
4766 data_offset);
4767 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004768 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 }
4770 }
4771 cifs_buf_release(pSMB);
4772
4773 if (rc == -EAGAIN)
4774 goto QFSAttributeRetry;
4775
4776 return rc;
4777}
4778
4779int
Steve French96daf2b2011-05-27 04:34:02 +00004780CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781{
4782/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4783 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4784 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4785 FILE_SYSTEM_DEVICE_INFO *response_data;
4786 int rc = 0;
4787 int bytes_returned = 0;
4788 __u16 params, byte_count;
4789
Joe Perchesb6b38f72010-04-21 03:50:45 +00004790 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791QFSDeviceRetry:
4792 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4793 (void **) &pSMBr);
4794 if (rc)
4795 return rc;
4796
4797 params = 2; /* level */
4798 pSMB->TotalDataCount = 0;
4799 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004800 /* BB find exact max SMB PDU from sess structure BB */
4801 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 pSMB->MaxSetupCount = 0;
4803 pSMB->Reserved = 0;
4804 pSMB->Flags = 0;
4805 pSMB->Timeout = 0;
4806 pSMB->Reserved2 = 0;
4807 byte_count = params + 1 /* pad */ ;
4808 pSMB->TotalParameterCount = cpu_to_le16(params);
4809 pSMB->ParameterCount = pSMB->TotalParameterCount;
4810 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004811 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812
4813 pSMB->DataCount = 0;
4814 pSMB->DataOffset = 0;
4815 pSMB->SetupCount = 1;
4816 pSMB->Reserved3 = 0;
4817 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4818 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004819 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820 pSMB->ByteCount = cpu_to_le16(byte_count);
4821
4822 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4823 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4824 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004825 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 } else { /* decode response */
4827 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4828
Jeff Layton820a8032011-05-04 08:05:26 -04004829 if (rc || get_bcc(&pSMBr->hdr) <
4830 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 rc = -EIO; /* bad smb */
4832 else {
4833 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4834 response_data =
Steve French737b7582005-04-28 22:41:06 -07004835 (FILE_SYSTEM_DEVICE_INFO *)
4836 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 data_offset);
4838 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004839 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 }
4841 }
4842 cifs_buf_release(pSMB);
4843
4844 if (rc == -EAGAIN)
4845 goto QFSDeviceRetry;
4846
4847 return rc;
4848}
4849
4850int
Steve French96daf2b2011-05-27 04:34:02 +00004851CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852{
4853/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4854 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4855 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4856 FILE_SYSTEM_UNIX_INFO *response_data;
4857 int rc = 0;
4858 int bytes_returned = 0;
4859 __u16 params, byte_count;
4860
Joe Perchesb6b38f72010-04-21 03:50:45 +00004861 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004863 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4864 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 if (rc)
4866 return rc;
4867
4868 params = 2; /* level */
4869 pSMB->TotalDataCount = 0;
4870 pSMB->DataCount = 0;
4871 pSMB->DataOffset = 0;
4872 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004873 /* BB find exact max SMB PDU from sess structure BB */
4874 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875 pSMB->MaxSetupCount = 0;
4876 pSMB->Reserved = 0;
4877 pSMB->Flags = 0;
4878 pSMB->Timeout = 0;
4879 pSMB->Reserved2 = 0;
4880 byte_count = params + 1 /* pad */ ;
4881 pSMB->ParameterCount = cpu_to_le16(params);
4882 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004883 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4884 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004885 pSMB->SetupCount = 1;
4886 pSMB->Reserved3 = 0;
4887 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4888 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004889 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 pSMB->ByteCount = cpu_to_le16(byte_count);
4891
4892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4894 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004895 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 } else { /* decode response */
4897 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4898
Jeff Layton820a8032011-05-04 08:05:26 -04004899 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 rc = -EIO; /* bad smb */
4901 } else {
4902 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4903 response_data =
4904 (FILE_SYSTEM_UNIX_INFO
4905 *) (((char *) &pSMBr->hdr.Protocol) +
4906 data_offset);
4907 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004908 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 }
4910 }
4911 cifs_buf_release(pSMB);
4912
4913 if (rc == -EAGAIN)
4914 goto QFSUnixRetry;
4915
4916
4917 return rc;
4918}
4919
Jeremy Allisonac670552005-06-22 17:26:35 -07004920int
Steve French96daf2b2011-05-27 04:34:02 +00004921CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004922{
4923/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4924 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4925 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4926 int rc = 0;
4927 int bytes_returned = 0;
4928 __u16 params, param_offset, offset, byte_count;
4929
Joe Perchesb6b38f72010-04-21 03:50:45 +00004930 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004931SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004932 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004933 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4934 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004935 if (rc)
4936 return rc;
4937
4938 params = 4; /* 2 bytes zero followed by info level. */
4939 pSMB->MaxSetupCount = 0;
4940 pSMB->Reserved = 0;
4941 pSMB->Flags = 0;
4942 pSMB->Timeout = 0;
4943 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004944 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4945 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004946 offset = param_offset + params;
4947
4948 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004949 /* BB find exact max SMB PDU from sess structure BB */
4950 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004951 pSMB->SetupCount = 1;
4952 pSMB->Reserved3 = 0;
4953 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4954 byte_count = 1 /* pad */ + params + 12;
4955
4956 pSMB->DataCount = cpu_to_le16(12);
4957 pSMB->ParameterCount = cpu_to_le16(params);
4958 pSMB->TotalDataCount = pSMB->DataCount;
4959 pSMB->TotalParameterCount = pSMB->ParameterCount;
4960 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4961 pSMB->DataOffset = cpu_to_le16(offset);
4962
4963 /* Params. */
4964 pSMB->FileNum = 0;
4965 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4966
4967 /* Data. */
4968 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4969 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4970 pSMB->ClientUnixCap = cpu_to_le64(cap);
4971
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004972 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004973 pSMB->ByteCount = cpu_to_le16(byte_count);
4974
4975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4977 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004978 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004979 } else { /* decode response */
4980 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004981 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004982 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004983 }
4984 cifs_buf_release(pSMB);
4985
4986 if (rc == -EAGAIN)
4987 goto SETFSUnixRetry;
4988
4989 return rc;
4990}
4991
4992
Linus Torvalds1da177e2005-04-16 15:20:36 -07004993
4994int
Steve French96daf2b2011-05-27 04:34:02 +00004995CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
Steve French737b7582005-04-28 22:41:06 -07004996 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997{
4998/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4999 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5000 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5001 FILE_SYSTEM_POSIX_INFO *response_data;
5002 int rc = 0;
5003 int bytes_returned = 0;
5004 __u16 params, byte_count;
5005
Joe Perchesb6b38f72010-04-21 03:50:45 +00005006 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007QFSPosixRetry:
5008 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5009 (void **) &pSMBr);
5010 if (rc)
5011 return rc;
5012
5013 params = 2; /* level */
5014 pSMB->TotalDataCount = 0;
5015 pSMB->DataCount = 0;
5016 pSMB->DataOffset = 0;
5017 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005018 /* BB find exact max SMB PDU from sess structure BB */
5019 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 pSMB->MaxSetupCount = 0;
5021 pSMB->Reserved = 0;
5022 pSMB->Flags = 0;
5023 pSMB->Timeout = 0;
5024 pSMB->Reserved2 = 0;
5025 byte_count = params + 1 /* pad */ ;
5026 pSMB->ParameterCount = cpu_to_le16(params);
5027 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005028 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5029 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005030 pSMB->SetupCount = 1;
5031 pSMB->Reserved3 = 0;
5032 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5033 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005034 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005035 pSMB->ByteCount = cpu_to_le16(byte_count);
5036
5037 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5038 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5039 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005040 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 } else { /* decode response */
5042 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5043
Jeff Layton820a8032011-05-04 08:05:26 -04005044 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045 rc = -EIO; /* bad smb */
5046 } else {
5047 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5048 response_data =
5049 (FILE_SYSTEM_POSIX_INFO
5050 *) (((char *) &pSMBr->hdr.Protocol) +
5051 data_offset);
5052 FSData->f_bsize =
5053 le32_to_cpu(response_data->BlockSize);
5054 FSData->f_blocks =
5055 le64_to_cpu(response_data->TotalBlocks);
5056 FSData->f_bfree =
5057 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005058 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059 FSData->f_bavail = FSData->f_bfree;
5060 } else {
5061 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005062 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005063 }
Steve French790fe572007-07-07 19:25:05 +00005064 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005066 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005067 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005069 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 }
5071 }
5072 cifs_buf_release(pSMB);
5073
5074 if (rc == -EAGAIN)
5075 goto QFSPosixRetry;
5076
5077 return rc;
5078}
5079
5080
Steve French50c2f752007-07-13 00:33:32 +00005081/* We can not use write of zero bytes trick to
5082 set file size due to need for large file support. Also note that
5083 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 routine which is only needed to work around a sharing violation bug
5085 in Samba which this routine can run into */
5086
5087int
Steve French96daf2b2011-05-27 04:34:02 +00005088CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005089 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005090 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091{
5092 struct smb_com_transaction2_spi_req *pSMB = NULL;
5093 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5094 struct file_end_of_file_info *parm_data;
5095 int name_len;
5096 int rc = 0;
5097 int bytes_returned = 0;
5098 __u16 params, byte_count, data_count, param_offset, offset;
5099
Joe Perchesb6b38f72010-04-21 03:50:45 +00005100 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101SetEOFRetry:
5102 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5103 (void **) &pSMBr);
5104 if (rc)
5105 return rc;
5106
5107 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5108 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005109 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005110 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 name_len++; /* trailing null */
5112 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005113 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 name_len = strnlen(fileName, PATH_MAX);
5115 name_len++; /* trailing null */
5116 strncpy(pSMB->FileName, fileName, name_len);
5117 }
5118 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005119 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005121 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 pSMB->MaxSetupCount = 0;
5123 pSMB->Reserved = 0;
5124 pSMB->Flags = 0;
5125 pSMB->Timeout = 0;
5126 pSMB->Reserved2 = 0;
5127 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005128 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005130 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005131 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5132 pSMB->InformationLevel =
5133 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5134 else
5135 pSMB->InformationLevel =
5136 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5137 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005138 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5139 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005140 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141 else
5142 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005143 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 }
5145
5146 parm_data =
5147 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5148 offset);
5149 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5150 pSMB->DataOffset = cpu_to_le16(offset);
5151 pSMB->SetupCount = 1;
5152 pSMB->Reserved3 = 0;
5153 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5154 byte_count = 3 /* pad */ + params + data_count;
5155 pSMB->DataCount = cpu_to_le16(data_count);
5156 pSMB->TotalDataCount = pSMB->DataCount;
5157 pSMB->ParameterCount = cpu_to_le16(params);
5158 pSMB->TotalParameterCount = pSMB->ParameterCount;
5159 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005160 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 parm_data->FileSize = cpu_to_le64(size);
5162 pSMB->ByteCount = cpu_to_le16(byte_count);
5163 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5164 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005165 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005166 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167
5168 cifs_buf_release(pSMB);
5169
5170 if (rc == -EAGAIN)
5171 goto SetEOFRetry;
5172
5173 return rc;
5174}
5175
5176int
Steve French96daf2b2011-05-27 04:34:02 +00005177CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005178 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005179{
5180 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005181 struct file_end_of_file_info *parm_data;
5182 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183 __u16 params, param_offset, offset, byte_count, count;
5184
Joe Perchesb6b38f72010-04-21 03:50:45 +00005185 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5186 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005187 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5188
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 if (rc)
5190 return rc;
5191
5192 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5193 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005194
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 params = 6;
5196 pSMB->MaxSetupCount = 0;
5197 pSMB->Reserved = 0;
5198 pSMB->Flags = 0;
5199 pSMB->Timeout = 0;
5200 pSMB->Reserved2 = 0;
5201 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5202 offset = param_offset + params;
5203
Linus Torvalds1da177e2005-04-16 15:20:36 -07005204 count = sizeof(struct file_end_of_file_info);
5205 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005206 /* BB find exact max SMB PDU from sess structure BB */
5207 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 pSMB->SetupCount = 1;
5209 pSMB->Reserved3 = 0;
5210 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5211 byte_count = 3 /* pad */ + params + count;
5212 pSMB->DataCount = cpu_to_le16(count);
5213 pSMB->ParameterCount = cpu_to_le16(params);
5214 pSMB->TotalDataCount = pSMB->DataCount;
5215 pSMB->TotalParameterCount = pSMB->ParameterCount;
5216 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5217 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005218 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5219 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 pSMB->DataOffset = cpu_to_le16(offset);
5221 parm_data->FileSize = cpu_to_le64(size);
5222 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005223 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5225 pSMB->InformationLevel =
5226 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5227 else
5228 pSMB->InformationLevel =
5229 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005230 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5232 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005233 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 else
5235 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005236 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 }
5238 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005239 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005241 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005243 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 }
5245
Steve French50c2f752007-07-13 00:33:32 +00005246 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 since file handle passed in no longer valid */
5248
5249 return rc;
5250}
5251
Steve French50c2f752007-07-13 00:33:32 +00005252/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 an open handle, rather than by pathname - this is awkward due to
5254 potential access conflicts on the open, but it is unavoidable for these
5255 old servers since the only other choice is to go from 100 nanosecond DCE
5256 time and resort to the original setpathinfo level which takes the ancient
5257 DOS time format with 2 second granularity */
5258int
Steve French96daf2b2011-05-27 04:34:02 +00005259CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005260 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261{
5262 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 char *data_offset;
5264 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005265 __u16 params, param_offset, offset, byte_count, count;
5266
Joe Perchesb6b38f72010-04-21 03:50:45 +00005267 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005268 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5269
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270 if (rc)
5271 return rc;
5272
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005273 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5274 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005275
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 params = 6;
5277 pSMB->MaxSetupCount = 0;
5278 pSMB->Reserved = 0;
5279 pSMB->Flags = 0;
5280 pSMB->Timeout = 0;
5281 pSMB->Reserved2 = 0;
5282 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5283 offset = param_offset + params;
5284
Steve French50c2f752007-07-13 00:33:32 +00005285 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286
Steve French26f57362007-08-30 22:09:15 +00005287 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005289 /* BB find max SMB PDU from sess */
5290 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005291 pSMB->SetupCount = 1;
5292 pSMB->Reserved3 = 0;
5293 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5294 byte_count = 3 /* pad */ + params + count;
5295 pSMB->DataCount = cpu_to_le16(count);
5296 pSMB->ParameterCount = cpu_to_le16(params);
5297 pSMB->TotalDataCount = pSMB->DataCount;
5298 pSMB->TotalParameterCount = pSMB->ParameterCount;
5299 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5300 pSMB->DataOffset = cpu_to_le16(offset);
5301 pSMB->Fid = fid;
5302 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5303 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5304 else
5305 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5306 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005307 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005309 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005310 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005311 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005312 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313
Steve French50c2f752007-07-13 00:33:32 +00005314 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 since file handle passed in no longer valid */
5316
5317 return rc;
5318}
5319
Jeff Layton6d22f092008-09-23 11:48:35 -04005320int
Steve French96daf2b2011-05-27 04:34:02 +00005321CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
Jeff Layton6d22f092008-09-23 11:48:35 -04005322 bool delete_file, __u16 fid, __u32 pid_of_opener)
5323{
5324 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5325 char *data_offset;
5326 int rc = 0;
5327 __u16 params, param_offset, offset, byte_count, count;
5328
Joe Perchesb6b38f72010-04-21 03:50:45 +00005329 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005330 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5331
5332 if (rc)
5333 return rc;
5334
5335 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5336 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5337
5338 params = 6;
5339 pSMB->MaxSetupCount = 0;
5340 pSMB->Reserved = 0;
5341 pSMB->Flags = 0;
5342 pSMB->Timeout = 0;
5343 pSMB->Reserved2 = 0;
5344 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5345 offset = param_offset + params;
5346
5347 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5348
5349 count = 1;
5350 pSMB->MaxParameterCount = cpu_to_le16(2);
5351 /* BB find max SMB PDU from sess */
5352 pSMB->MaxDataCount = cpu_to_le16(1000);
5353 pSMB->SetupCount = 1;
5354 pSMB->Reserved3 = 0;
5355 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5356 byte_count = 3 /* pad */ + params + count;
5357 pSMB->DataCount = cpu_to_le16(count);
5358 pSMB->ParameterCount = cpu_to_le16(params);
5359 pSMB->TotalDataCount = pSMB->DataCount;
5360 pSMB->TotalParameterCount = pSMB->ParameterCount;
5361 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5362 pSMB->DataOffset = cpu_to_le16(offset);
5363 pSMB->Fid = fid;
5364 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5365 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005366 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005367 pSMB->ByteCount = cpu_to_le16(byte_count);
5368 *data_offset = delete_file ? 1 : 0;
5369 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5370 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005371 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005372
5373 return rc;
5374}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375
5376int
Steve French96daf2b2011-05-27 04:34:02 +00005377CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton6fc000e2008-08-02 07:26:12 -04005378 const char *fileName, const FILE_BASIC_INFO *data,
5379 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005380{
5381 TRANSACTION2_SPI_REQ *pSMB = NULL;
5382 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5383 int name_len;
5384 int rc = 0;
5385 int bytes_returned = 0;
5386 char *data_offset;
5387 __u16 params, param_offset, offset, byte_count, count;
5388
Joe Perchesb6b38f72010-04-21 03:50:45 +00005389 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390
5391SetTimesRetry:
5392 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5393 (void **) &pSMBr);
5394 if (rc)
5395 return rc;
5396
5397 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5398 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005399 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005400 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 name_len++; /* trailing null */
5402 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005403 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005404 name_len = strnlen(fileName, PATH_MAX);
5405 name_len++; /* trailing null */
5406 strncpy(pSMB->FileName, fileName, name_len);
5407 }
5408
5409 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005410 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005412 /* BB find max SMB PDU from sess structure BB */
5413 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 pSMB->MaxSetupCount = 0;
5415 pSMB->Reserved = 0;
5416 pSMB->Flags = 0;
5417 pSMB->Timeout = 0;
5418 pSMB->Reserved2 = 0;
5419 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005420 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 offset = param_offset + params;
5422 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5423 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5424 pSMB->DataOffset = cpu_to_le16(offset);
5425 pSMB->SetupCount = 1;
5426 pSMB->Reserved3 = 0;
5427 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5428 byte_count = 3 /* pad */ + params + count;
5429
5430 pSMB->DataCount = cpu_to_le16(count);
5431 pSMB->ParameterCount = cpu_to_le16(params);
5432 pSMB->TotalDataCount = pSMB->DataCount;
5433 pSMB->TotalParameterCount = pSMB->ParameterCount;
5434 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5435 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5436 else
5437 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5438 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005439 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005440 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441 pSMB->ByteCount = cpu_to_le16(byte_count);
5442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005444 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005445 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446
5447 cifs_buf_release(pSMB);
5448
5449 if (rc == -EAGAIN)
5450 goto SetTimesRetry;
5451
5452 return rc;
5453}
5454
5455/* Can not be used to set time stamps yet (due to old DOS time format) */
5456/* Can be used to set attributes */
5457#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5458 handling it anyway and NT4 was what we thought it would be needed for
5459 Do not delete it until we prove whether needed for Win9x though */
5460int
Steve French96daf2b2011-05-27 04:34:02 +00005461CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462 __u16 dos_attrs, const struct nls_table *nls_codepage)
5463{
5464 SETATTR_REQ *pSMB = NULL;
5465 SETATTR_RSP *pSMBr = NULL;
5466 int rc = 0;
5467 int bytes_returned;
5468 int name_len;
5469
Joe Perchesb6b38f72010-04-21 03:50:45 +00005470 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005471
5472SetAttrLgcyRetry:
5473 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5474 (void **) &pSMBr);
5475 if (rc)
5476 return rc;
5477
5478 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5479 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005480 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 PATH_MAX, nls_codepage);
5482 name_len++; /* trailing null */
5483 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005484 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 name_len = strnlen(fileName, PATH_MAX);
5486 name_len++; /* trailing null */
5487 strncpy(pSMB->fileName, fileName, name_len);
5488 }
5489 pSMB->attr = cpu_to_le16(dos_attrs);
5490 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005491 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5493 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5494 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005495 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005496 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497
5498 cifs_buf_release(pSMB);
5499
5500 if (rc == -EAGAIN)
5501 goto SetAttrLgcyRetry;
5502
5503 return rc;
5504}
5505#endif /* temporarily unneeded SetAttr legacy function */
5506
Jeff Layton654cf142009-07-09 20:02:49 -04005507static void
5508cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5509 const struct cifs_unix_set_info_args *args)
5510{
5511 u64 mode = args->mode;
5512
5513 /*
5514 * Samba server ignores set of file size to zero due to bugs in some
5515 * older clients, but we should be precise - we use SetFileSize to
5516 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005517 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005518 * zero instead of -1 here
5519 */
5520 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5521 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5522 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5523 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5524 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5525 data_offset->Uid = cpu_to_le64(args->uid);
5526 data_offset->Gid = cpu_to_le64(args->gid);
5527 /* better to leave device as zero when it is */
5528 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5529 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5530 data_offset->Permissions = cpu_to_le64(mode);
5531
5532 if (S_ISREG(mode))
5533 data_offset->Type = cpu_to_le32(UNIX_FILE);
5534 else if (S_ISDIR(mode))
5535 data_offset->Type = cpu_to_le32(UNIX_DIR);
5536 else if (S_ISLNK(mode))
5537 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5538 else if (S_ISCHR(mode))
5539 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5540 else if (S_ISBLK(mode))
5541 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5542 else if (S_ISFIFO(mode))
5543 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5544 else if (S_ISSOCK(mode))
5545 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5546}
5547
Linus Torvalds1da177e2005-04-16 15:20:36 -07005548int
Steve French96daf2b2011-05-27 04:34:02 +00005549CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005550 const struct cifs_unix_set_info_args *args,
5551 u16 fid, u32 pid_of_opener)
5552{
5553 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5554 FILE_UNIX_BASIC_INFO *data_offset;
5555 int rc = 0;
5556 u16 params, param_offset, offset, byte_count, count;
5557
Joe Perchesb6b38f72010-04-21 03:50:45 +00005558 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005559 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5560
5561 if (rc)
5562 return rc;
5563
5564 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5565 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5566
5567 params = 6;
5568 pSMB->MaxSetupCount = 0;
5569 pSMB->Reserved = 0;
5570 pSMB->Flags = 0;
5571 pSMB->Timeout = 0;
5572 pSMB->Reserved2 = 0;
5573 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5574 offset = param_offset + params;
5575
5576 data_offset = (FILE_UNIX_BASIC_INFO *)
5577 ((char *)(&pSMB->hdr.Protocol) + offset);
5578 count = sizeof(FILE_UNIX_BASIC_INFO);
5579
5580 pSMB->MaxParameterCount = cpu_to_le16(2);
5581 /* BB find max SMB PDU from sess */
5582 pSMB->MaxDataCount = cpu_to_le16(1000);
5583 pSMB->SetupCount = 1;
5584 pSMB->Reserved3 = 0;
5585 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5586 byte_count = 3 /* pad */ + params + count;
5587 pSMB->DataCount = cpu_to_le16(count);
5588 pSMB->ParameterCount = cpu_to_le16(params);
5589 pSMB->TotalDataCount = pSMB->DataCount;
5590 pSMB->TotalParameterCount = pSMB->ParameterCount;
5591 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5592 pSMB->DataOffset = cpu_to_le16(offset);
5593 pSMB->Fid = fid;
5594 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5595 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005596 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005597 pSMB->ByteCount = cpu_to_le16(byte_count);
5598
5599 cifs_fill_unix_set_info(data_offset, args);
5600
5601 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5602 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005603 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005604
5605 /* Note: On -EAGAIN error only caller can retry on handle based calls
5606 since file handle passed in no longer valid */
5607
5608 return rc;
5609}
5610
5611int
Steve French96daf2b2011-05-27 04:34:02 +00005612CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
Jeff Layton01ea95e2009-07-09 20:02:49 -04005613 const struct cifs_unix_set_info_args *args,
5614 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615{
5616 TRANSACTION2_SPI_REQ *pSMB = NULL;
5617 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5618 int name_len;
5619 int rc = 0;
5620 int bytes_returned = 0;
5621 FILE_UNIX_BASIC_INFO *data_offset;
5622 __u16 params, param_offset, offset, count, byte_count;
5623
Joe Perchesb6b38f72010-04-21 03:50:45 +00005624 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625setPermsRetry:
5626 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5627 (void **) &pSMBr);
5628 if (rc)
5629 return rc;
5630
5631 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5632 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005633 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005634 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 name_len++; /* trailing null */
5636 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005637 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638 name_len = strnlen(fileName, PATH_MAX);
5639 name_len++; /* trailing null */
5640 strncpy(pSMB->FileName, fileName, name_len);
5641 }
5642
5643 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005644 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005645 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005646 /* BB find max SMB PDU from sess structure BB */
5647 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 pSMB->MaxSetupCount = 0;
5649 pSMB->Reserved = 0;
5650 pSMB->Flags = 0;
5651 pSMB->Timeout = 0;
5652 pSMB->Reserved2 = 0;
5653 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005654 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005655 offset = param_offset + params;
5656 data_offset =
5657 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5658 offset);
5659 memset(data_offset, 0, count);
5660 pSMB->DataOffset = cpu_to_le16(offset);
5661 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5662 pSMB->SetupCount = 1;
5663 pSMB->Reserved3 = 0;
5664 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5665 byte_count = 3 /* pad */ + params + count;
5666 pSMB->ParameterCount = cpu_to_le16(params);
5667 pSMB->DataCount = cpu_to_le16(count);
5668 pSMB->TotalParameterCount = pSMB->ParameterCount;
5669 pSMB->TotalDataCount = pSMB->DataCount;
5670 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5671 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005672 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005673
Jeff Layton654cf142009-07-09 20:02:49 -04005674 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675
5676 pSMB->ByteCount = cpu_to_le16(byte_count);
5677 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005679 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005680 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
Steve French0d817bc2008-05-22 02:02:03 +00005682 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005683 if (rc == -EAGAIN)
5684 goto setPermsRetry;
5685 return rc;
5686}
5687
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005689/*
5690 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5691 * function used by listxattr and getxattr type calls. When ea_name is set,
5692 * it looks for that attribute name and stuffs that value into the EAData
5693 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5694 * buffer. In both cases, the return value is either the length of the
5695 * resulting data or a negative error code. If EAData is a NULL pointer then
5696 * the data isn't copied to it, but the length is returned.
5697 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005698ssize_t
Steve French96daf2b2011-05-27 04:34:02 +00005699CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005700 const unsigned char *searchName, const unsigned char *ea_name,
5701 char *EAData, size_t buf_size,
5702 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005703{
5704 /* BB assumes one setup word */
5705 TRANSACTION2_QPI_REQ *pSMB = NULL;
5706 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5707 int rc = 0;
5708 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005709 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005710 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005711 struct fea *temp_fea;
5712 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005713 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005714 __u16 params, byte_count, data_offset;
Jeff Layton5980fc92011-07-28 12:48:26 -04005715 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716
Joe Perchesb6b38f72010-04-21 03:50:45 +00005717 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005718QAllEAsRetry:
5719 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5720 (void **) &pSMBr);
5721 if (rc)
5722 return rc;
5723
5724 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005725 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005726 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005727 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005728 list_len++; /* trailing null */
5729 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005731 list_len = strnlen(searchName, PATH_MAX);
5732 list_len++; /* trailing null */
5733 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 }
5735
Jeff Layton6e462b92010-02-10 16:18:26 -05005736 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005737 pSMB->TotalDataCount = 0;
5738 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005739 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005740 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005741 pSMB->MaxSetupCount = 0;
5742 pSMB->Reserved = 0;
5743 pSMB->Flags = 0;
5744 pSMB->Timeout = 0;
5745 pSMB->Reserved2 = 0;
5746 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005747 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005748 pSMB->DataCount = 0;
5749 pSMB->DataOffset = 0;
5750 pSMB->SetupCount = 1;
5751 pSMB->Reserved3 = 0;
5752 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5753 byte_count = params + 1 /* pad */ ;
5754 pSMB->TotalParameterCount = cpu_to_le16(params);
5755 pSMB->ParameterCount = pSMB->TotalParameterCount;
5756 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5757 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005758 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005759 pSMB->ByteCount = cpu_to_le16(byte_count);
5760
5761 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5762 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5763 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005764 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005765 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005766 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005767
5768
5769 /* BB also check enough total bytes returned */
5770 /* BB we need to improve the validity checking
5771 of these trans2 responses */
5772
5773 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005774 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005775 rc = -EIO; /* bad smb */
5776 goto QAllEAsOut;
5777 }
5778
5779 /* check that length of list is not more than bcc */
5780 /* check that each entry does not go beyond length
5781 of list */
5782 /* check that each element of each entry does not
5783 go beyond end of list */
5784 /* validate_trans2_offsets() */
5785 /* BB check if start of smb + data_offset > &bcc+ bcc */
5786
5787 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5788 ea_response_data = (struct fealist *)
5789 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5790
Jeff Layton6e462b92010-02-10 16:18:26 -05005791 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005792 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005793 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005794 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005795 goto QAllEAsOut;
5796 }
5797
Jeff Layton0cd126b2010-02-10 16:18:26 -05005798 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005799 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005800 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005801 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005802 rc = -EIO;
5803 goto QAllEAsOut;
5804 }
5805
Jeff Laytonf0d38682010-02-10 16:18:26 -05005806 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005807 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005808 temp_fea = ea_response_data->list;
5809 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005810 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005811 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005812 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005813
Jeff Layton6e462b92010-02-10 16:18:26 -05005814 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005815 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005816 /* make sure we can read name_len and value_len */
5817 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005818 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005819 rc = -EIO;
5820 goto QAllEAsOut;
5821 }
5822
5823 name_len = temp_fea->name_len;
5824 value_len = le16_to_cpu(temp_fea->value_len);
5825 list_len -= name_len + 1 + value_len;
5826 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005827 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005828 rc = -EIO;
5829 goto QAllEAsOut;
5830 }
5831
Jeff Layton31c05192010-02-10 16:18:26 -05005832 if (ea_name) {
Jeff Layton91d065c2011-07-26 18:23:47 -04005833 if (ea_name_len == name_len &&
Jeff Laytonac423442011-10-11 06:41:32 -04005834 memcmp(ea_name, temp_ptr, name_len) == 0) {
Jeff Layton31c05192010-02-10 16:18:26 -05005835 temp_ptr += name_len + 1;
5836 rc = value_len;
5837 if (buf_size == 0)
5838 goto QAllEAsOut;
5839 if ((size_t)value_len > buf_size) {
5840 rc = -ERANGE;
5841 goto QAllEAsOut;
5842 }
5843 memcpy(EAData, temp_ptr, value_len);
5844 goto QAllEAsOut;
5845 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005846 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005847 /* account for prefix user. and trailing null */
5848 rc += (5 + 1 + name_len);
5849 if (rc < (int) buf_size) {
5850 memcpy(EAData, "user.", 5);
5851 EAData += 5;
5852 memcpy(EAData, temp_ptr, name_len);
5853 EAData += name_len;
5854 /* null terminate name */
5855 *EAData = 0;
5856 ++EAData;
5857 } else if (buf_size == 0) {
5858 /* skip copy - calc size only */
5859 } else {
5860 /* stop before overrun buffer */
5861 rc = -ERANGE;
5862 break;
5863 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005864 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005865 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005866 temp_fea = (struct fea *)temp_ptr;
5867 }
5868
Jeff Layton31c05192010-02-10 16:18:26 -05005869 /* didn't find the named attribute */
5870 if (ea_name)
5871 rc = -ENODATA;
5872
Jeff Laytonf0d38682010-02-10 16:18:26 -05005873QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005874 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005875 if (rc == -EAGAIN)
5876 goto QAllEAsRetry;
5877
5878 return (ssize_t)rc;
5879}
5880
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881int
Steve French96daf2b2011-05-27 04:34:02 +00005882CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005883 const char *ea_name, const void *ea_value,
5884 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5885 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886{
5887 struct smb_com_transaction2_spi_req *pSMB = NULL;
5888 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5889 struct fealist *parm_data;
5890 int name_len;
5891 int rc = 0;
5892 int bytes_returned = 0;
5893 __u16 params, param_offset, byte_count, offset, count;
5894
Joe Perchesb6b38f72010-04-21 03:50:45 +00005895 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896SetEARetry:
5897 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5898 (void **) &pSMBr);
5899 if (rc)
5900 return rc;
5901
5902 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5903 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005904 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005905 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906 name_len++; /* trailing null */
5907 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005908 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909 name_len = strnlen(fileName, PATH_MAX);
5910 name_len++; /* trailing null */
5911 strncpy(pSMB->FileName, fileName, name_len);
5912 }
5913
5914 params = 6 + name_len;
5915
5916 /* done calculating parms using name_len of file name,
5917 now use name_len to calculate length of ea name
5918 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005919 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 name_len = 0;
5921 else
Steve French50c2f752007-07-13 00:33:32 +00005922 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005923
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00005924 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005925 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005926 /* BB find max SMB PDU from sess */
5927 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005928 pSMB->MaxSetupCount = 0;
5929 pSMB->Reserved = 0;
5930 pSMB->Flags = 0;
5931 pSMB->Timeout = 0;
5932 pSMB->Reserved2 = 0;
5933 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005934 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005935 offset = param_offset + params;
5936 pSMB->InformationLevel =
5937 cpu_to_le16(SMB_SET_FILE_EA);
5938
5939 parm_data =
5940 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5941 offset);
5942 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5943 pSMB->DataOffset = cpu_to_le16(offset);
5944 pSMB->SetupCount = 1;
5945 pSMB->Reserved3 = 0;
5946 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5947 byte_count = 3 /* pad */ + params + count;
5948 pSMB->DataCount = cpu_to_le16(count);
5949 parm_data->list_len = cpu_to_le32(count);
5950 parm_data->list[0].EA_flags = 0;
5951 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005952 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005953 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005954 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005955 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005956 parm_data->list[0].name[name_len] = 0;
5957 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5958 /* caller ensures that ea_value_len is less than 64K but
5959 we need to ensure that it fits within the smb */
5960
Steve French50c2f752007-07-13 00:33:32 +00005961 /*BB add length check to see if it would fit in
5962 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005963 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5964 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005965 memcpy(parm_data->list[0].name+name_len+1,
5966 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967
5968 pSMB->TotalDataCount = pSMB->DataCount;
5969 pSMB->ParameterCount = cpu_to_le16(params);
5970 pSMB->TotalParameterCount = pSMB->ParameterCount;
5971 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005972 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005973 pSMB->ByteCount = cpu_to_le16(byte_count);
5974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005976 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005977 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978
5979 cifs_buf_release(pSMB);
5980
5981 if (rc == -EAGAIN)
5982 goto SetEARetry;
5983
5984 return rc;
5985}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005986#endif
Steve French0eff0e22011-02-24 05:39:23 +00005987
5988#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5989/*
5990 * Years ago the kernel added a "dnotify" function for Samba server,
5991 * to allow network clients (such as Windows) to display updated
5992 * lists of files in directory listings automatically when
5993 * files are added by one user when another user has the
5994 * same directory open on their desktop. The Linux cifs kernel
5995 * client hooked into the kernel side of this interface for
5996 * the same reason, but ironically when the VFS moved from
5997 * "dnotify" to "inotify" it became harder to plug in Linux
5998 * network file system clients (the most obvious use case
5999 * for notify interfaces is when multiple users can update
6000 * the contents of the same directory - exactly what network
6001 * file systems can do) although the server (Samba) could
6002 * still use it. For the short term we leave the worker
6003 * function ifdeffed out (below) until inotify is fixed
6004 * in the VFS to make it easier to plug in network file
6005 * system clients. If inotify turns out to be permanently
6006 * incompatible for network fs clients, we could instead simply
6007 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6008 */
Steve French96daf2b2011-05-27 04:34:02 +00006009int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
Steve French0eff0e22011-02-24 05:39:23 +00006010 const int notify_subdirs, const __u16 netfid,
6011 __u32 filter, struct file *pfile, int multishot,
6012 const struct nls_table *nls_codepage)
6013{
6014 int rc = 0;
6015 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6016 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6017 struct dir_notify_req *dnotify_req;
6018 int bytes_returned;
6019
6020 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6021 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6022 (void **) &pSMBr);
6023 if (rc)
6024 return rc;
6025
6026 pSMB->TotalParameterCount = 0 ;
6027 pSMB->TotalDataCount = 0;
6028 pSMB->MaxParameterCount = cpu_to_le32(2);
Jeff Laytonc974bef2011-10-11 06:41:32 -04006029 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
Steve French0eff0e22011-02-24 05:39:23 +00006030 pSMB->MaxSetupCount = 4;
6031 pSMB->Reserved = 0;
6032 pSMB->ParameterOffset = 0;
6033 pSMB->DataCount = 0;
6034 pSMB->DataOffset = 0;
6035 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6036 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6037 pSMB->ParameterCount = pSMB->TotalParameterCount;
6038 if (notify_subdirs)
6039 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6040 pSMB->Reserved2 = 0;
6041 pSMB->CompletionFilter = cpu_to_le32(filter);
6042 pSMB->Fid = netfid; /* file handle always le */
6043 pSMB->ByteCount = 0;
6044
6045 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6046 (struct smb_hdr *)pSMBr, &bytes_returned,
6047 CIFS_ASYNC_OP);
6048 if (rc) {
6049 cFYI(1, "Error in Notify = %d", rc);
6050 } else {
6051 /* Add file to outstanding requests */
6052 /* BB change to kmem cache alloc */
6053 dnotify_req = kmalloc(
6054 sizeof(struct dir_notify_req),
6055 GFP_KERNEL);
6056 if (dnotify_req) {
6057 dnotify_req->Pid = pSMB->hdr.Pid;
6058 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6059 dnotify_req->Mid = pSMB->hdr.Mid;
6060 dnotify_req->Tid = pSMB->hdr.Tid;
6061 dnotify_req->Uid = pSMB->hdr.Uid;
6062 dnotify_req->netfid = netfid;
6063 dnotify_req->pfile = pfile;
6064 dnotify_req->filter = filter;
6065 dnotify_req->multishot = multishot;
6066 spin_lock(&GlobalMid_Lock);
6067 list_add_tail(&dnotify_req->lhead,
6068 &GlobalDnotifyReqList);
6069 spin_unlock(&GlobalMid_Lock);
6070 } else
6071 rc = -ENOMEM;
6072 }
6073 cifs_buf_release(pSMB);
6074 return rc;
6075}
6076#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */