blob: 136df013b0aa5f084e156fe743c5b434b6079eae [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 French790fe572007-07-07 19:25:05 +000088static void mark_open_files_invalid(struct cifsTconInfo *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
108cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
109{
110 int rc = 0;
111 struct cifsSesInfo *ses;
112 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
230small_smb_init(int smb_command, int wct, struct cifsTconInfo *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 French5815449d2006-02-14 01:36:20 +0000256 struct cifsSesInfo *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
Jeff Laytonf5695992010-09-29 15:27:08 -0400282__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
283 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
308smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
309 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
321smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
322 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
370CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
371{
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 French254e55e2006-06-04 05:53:15 +0000454 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
455 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
456 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000457 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000458 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000459 /* even though we do not use raw we might as well set this
460 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000461 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000462 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000463 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
464 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE;
467 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000468 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000469 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000470 /* OS/2 often does not set timezone therefore
471 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000472 * Could deviate slightly from the right zone.
473 * Smallest defined timezone difference is 15 minutes
474 * (i.e. Nepal). Rounding up/down is done to match
475 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000476 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000477 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000478 struct timespec ts, utc;
479 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400480 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
481 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000482 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000483 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000484 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000485 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000486 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000487 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000489 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000490 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000491 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000492 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000494 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000495 server->timeAdj = (int)tmp;
496 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000497 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000498 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000499
Steve French39798772006-05-31 22:40:51 +0000500
Steve French254e55e2006-06-04 05:53:15 +0000501 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000502 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000503
Steve French50c2f752007-07-13 00:33:32 +0000504 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500506 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000507 CIFS_CRYPTO_KEY_SIZE);
508 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
509 rc = -EIO; /* need cryptkey unless plain text */
510 goto neg_err_exit;
511 }
Steve French39798772006-05-31 22:40:51 +0000512
Steve Frenchf19159d2010-04-21 04:12:10 +0000513 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000514 /* we will not end up setting signing flags - as no signing
515 was in LANMAN and server did not return the flags on */
516 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000517#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000518 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000519 cERROR(1, "mount failed, cifs module not built "
520 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300521 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000522#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000523 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000524 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000525 /* unknown wct */
526 rc = -EOPNOTSUPP;
527 goto neg_err_exit;
528 }
529 /* else wct == 17 NTLM */
530 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000531 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000532 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000533
Steve French790fe572007-07-07 19:25:05 +0000534 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000535#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000536 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000537#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000538 cERROR(1, "Server requests plain text password"
539 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000540
Steve French790fe572007-07-07 19:25:05 +0000541 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000542 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000543 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000544 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000545 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000546 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000547 else if (secFlags & CIFSSEC_MAY_KRB5)
548 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000549 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000550 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000551 else if (secFlags & CIFSSEC_MAY_LANMAN)
552 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000553 else {
554 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000555 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000556 goto neg_err_exit;
557 }
558 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000559
Steve French254e55e2006-06-04 05:53:15 +0000560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
562 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
563 /* probably no need to store and check maxvcs */
564 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000566 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000567 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000568 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000569 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
570 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000571 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500572 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000573 CIFS_CRYPTO_KEY_SIZE);
574 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
575 && (pSMBr->EncryptionKeyLength == 0)) {
576 /* decode security blob */
577 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
578 rc = -EIO; /* no crypt key only if plain text pwd */
579 goto neg_err_exit;
580 }
581
582 /* BB might be helpful to save off the domain of server here */
583
Steve French50c2f752007-07-13 00:33:32 +0000584 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000585 (server->capabilities & CAP_EXTENDED_SECURITY)) {
Jeff Layton820a8032011-05-04 08:05:26 -0400586 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000587 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000589 goto neg_err_exit;
590 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530591 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500592 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530593 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000594 if (memcmp(server->server_GUID,
595 pSMBr->u.extended_response.
596 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000598 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000599 pSMBr->u.extended_response.GUID,
600 16);
601 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530603 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000604 memcpy(server->server_GUID,
605 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500606 }
Jeff Laytone187e442007-10-16 17:10:44 +0000607
608 if (count == 16) {
609 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000610 } else {
611 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400612 SecurityBlob, count - 16,
613 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000614 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000615 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000616 else
Steve French254e55e2006-06-04 05:53:15 +0000617 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500618 if (server->secType == Kerberos) {
619 if (!server->sec_kerberos &&
620 !server->sec_mskerberos)
621 rc = -EOPNOTSUPP;
622 } else if (server->secType == RawNTLMSSP) {
623 if (!server->sec_ntlmssp)
624 rc = -EOPNOTSUPP;
625 } else
626 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Steve French254e55e2006-06-04 05:53:15 +0000628 } else
629 server->capabilities &= ~CAP_EXTENDED_SECURITY;
630
Steve French6344a422006-06-12 04:18:35 +0000631#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000632signing_check:
Steve French6344a422006-06-12 04:18:35 +0000633#endif
Steve French762e5ab2007-06-28 18:41:42 +0000634 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
635 /* MUST_SIGN already includes the MAY_SIGN FLAG
636 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000637 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000638 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000639 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000640 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000642 rc = -EOPNOTSUPP;
643 }
Steve French50c2f752007-07-13 00:33:32 +0000644 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
647 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000648 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000649 if ((server->secMode &
650 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000651 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000652 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000653 } else
654 server->secMode |= SECMODE_SIGN_REQUIRED;
655 } else {
656 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000657 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000658 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000659 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
Steve French50c2f752007-07-13 00:33:32 +0000661
662neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700663 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000664
Joe Perchesb6b38f72010-04-21 03:50:45 +0000665 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return rc;
667}
668
669int
670CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
671{
672 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Joe Perchesb6b38f72010-04-21 03:50:45 +0000675 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500676
677 /* BB: do we need to check this? These should never be NULL. */
678 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
679 return -EIO;
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500682 * No need to return error on this operation if tid invalidated and
683 * closed on server already e.g. due to tcp session crashing. Also,
684 * the tcon is no longer on the list, so no need to take lock before
685 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 */
Steve French268875b2009-06-25 00:29:21 +0000687 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000688 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Steve French50c2f752007-07-13 00:33:32 +0000690 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700691 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500692 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return rc;
Steve French133672e2007-11-13 22:41:37 +0000694
695 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
Steve French50c2f752007-07-13 00:33:32 +0000699 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500700 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if (rc == -EAGAIN)
702 rc = 0;
703
704 return rc;
705}
706
Jeff Layton766fdbb2011-01-11 07:24:21 -0500707/*
708 * This is a no-op for now. We're not really interested in the reply, but
709 * rather in the fact that the server sent one and that server->lstrp
710 * gets updated.
711 *
712 * FIXME: maybe we should consider checking that the reply matches request?
713 */
714static void
715cifs_echo_callback(struct mid_q_entry *mid)
716{
717 struct TCP_Server_Info *server = mid->callback_data;
718
719 DeleteMidQEntry(mid);
720 atomic_dec(&server->inFlight);
721 wake_up(&server->request_q);
722}
723
724int
725CIFSSMBEcho(struct TCP_Server_Info *server)
726{
727 ECHO_REQ *smb;
728 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400729 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500730
731 cFYI(1, "In echo request");
732
733 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
734 if (rc)
735 return rc;
736
737 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000738 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c82011-01-20 21:19:25 -0500739 smb->hdr.WordCount = 1;
740 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400741 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000743 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400744 iov.iov_base = smb;
745 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
Jeff Layton59ffd842011-05-19 16:22:55 -0400747 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748 if (rc)
749 cFYI(1, "Echo request failed: %d", rc);
750
751 cifs_small_buf_release(smb);
752
753 return rc;
754}
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756int
757CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
758{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 LOGOFF_ANDX_REQ *pSMB;
760 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Joe Perchesb6b38f72010-04-21 03:50:45 +0000762 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500763
764 /*
765 * BB: do we need to check validity of ses and server? They should
766 * always be valid since we have an active reference. If not, that
767 * should probably be a BUG()
768 */
769 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return -EIO;
771
Steve Frenchd7b619c2010-02-25 05:36:46 +0000772 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000773 if (ses->need_reconnect)
774 goto session_already_dead; /* no need to send SMBlogoff if uid
775 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
777 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000778 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return rc;
780 }
781
Steve French3b795212008-11-13 19:45:32 +0000782 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700783
Steve French3b795212008-11-13 19:45:32 +0000784 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
786 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 pSMB->hdr.Uid = ses->Suid;
789
790 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000791 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000792session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000793 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000796 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 error */
798 if (rc == -EAGAIN)
799 rc = 0;
800 return rc;
801}
802
803int
Steve French2d785a52007-07-15 01:48:57 +0000804CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
805 __u16 type, const struct nls_table *nls_codepage, int remap)
806{
807 TRANSACTION2_SPI_REQ *pSMB = NULL;
808 TRANSACTION2_SPI_RSP *pSMBr = NULL;
809 struct unlink_psx_rq *pRqD;
810 int name_len;
811 int rc = 0;
812 int bytes_returned = 0;
813 __u16 params, param_offset, offset, byte_count;
814
Joe Perchesb6b38f72010-04-21 03:50:45 +0000815 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000816PsxDelete:
817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
821
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
823 name_len =
824 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
825 PATH_MAX, nls_codepage, remap);
826 name_len++; /* trailing null */
827 name_len *= 2;
828 } else { /* BB add path length overrun check */
829 name_len = strnlen(fileName, PATH_MAX);
830 name_len++; /* trailing null */
831 strncpy(pSMB->FileName, fileName, name_len);
832 }
833
834 params = 6 + name_len;
835 pSMB->MaxParameterCount = cpu_to_le16(2);
836 pSMB->MaxDataCount = 0; /* BB double check this with jra */
837 pSMB->MaxSetupCount = 0;
838 pSMB->Reserved = 0;
839 pSMB->Flags = 0;
840 pSMB->Timeout = 0;
841 pSMB->Reserved2 = 0;
842 param_offset = offsetof(struct smb_com_transaction2_spi_req,
843 InformationLevel) - 4;
844 offset = param_offset + params;
845
846 /* Setup pointer to Request Data (inode type) */
847 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
848 pRqD->type = cpu_to_le16(type);
849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
850 pSMB->DataOffset = cpu_to_le16(offset);
851 pSMB->SetupCount = 1;
852 pSMB->Reserved3 = 0;
853 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
854 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
855
856 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
858 pSMB->ParameterCount = cpu_to_le16(params);
859 pSMB->TotalParameterCount = pSMB->ParameterCount;
860 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
861 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000862 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000863 pSMB->ByteCount = cpu_to_le16(byte_count);
864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000866 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000867 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000868 cifs_buf_release(pSMB);
869
870 cifs_stats_inc(&tcon->num_deletes);
871
872 if (rc == -EAGAIN)
873 goto PsxDelete;
874
875 return rc;
876}
877
878int
Steve French737b7582005-04-28 22:41:06 -0700879CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
880 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 DELETE_FILE_REQ *pSMB = NULL;
883 DELETE_FILE_RSP *pSMBr = NULL;
884 int rc = 0;
885 int bytes_returned;
886 int name_len;
887
888DelFileRetry:
889 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
890 (void **) &pSMBr);
891 if (rc)
892 return rc;
893
894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
895 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000896 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700897 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 name_len++; /* trailing null */
899 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700900 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len = strnlen(fileName, PATH_MAX);
902 name_len++; /* trailing null */
903 strncpy(pSMB->fileName, fileName, name_len);
904 }
905 pSMB->SearchAttributes =
906 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
907 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000908 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 pSMB->ByteCount = cpu_to_le16(name_len + 1);
910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700912 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000913 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000914 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 cifs_buf_release(pSMB);
917 if (rc == -EAGAIN)
918 goto DelFileRetry;
919
920 return rc;
921}
922
923int
Steve French50c2f752007-07-13 00:33:32 +0000924CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
927 DELETE_DIRECTORY_REQ *pSMB = NULL;
928 DELETE_DIRECTORY_RSP *pSMBr = NULL;
929 int rc = 0;
930 int bytes_returned;
931 int name_len;
932
Joe Perchesb6b38f72010-04-21 03:50:45 +0000933 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934RmDirRetry:
935 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
936 (void **) &pSMBr);
937 if (rc)
938 return rc;
939
940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700941 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
942 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
944 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700945 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len = strnlen(dirName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->DirName, dirName, name_len);
949 }
950
951 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000952 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700956 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000957 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000958 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto RmDirRetry;
963 return rc;
964}
965
966int
967CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700968 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 int rc = 0;
971 CREATE_DIRECTORY_REQ *pSMB = NULL;
972 CREATE_DIRECTORY_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
975
Joe Perchesb6b38f72010-04-21 03:50:45 +0000976 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977MkDirRetry:
978 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
982
983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000984 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700985 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len++; /* trailing null */
987 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700988 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name_len = strnlen(name, PATH_MAX);
990 name_len++; /* trailing null */
991 strncpy(pSMB->DirName, name, name_len);
992 }
993
994 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000995 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 pSMB->ByteCount = cpu_to_le16(name_len + 1);
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700999 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001000 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001001 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto MkDirRetry;
1006 return rc;
1007}
1008
Steve French2dd29d32007-04-23 22:07:35 +00001009int
1010CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001012 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001013 const struct nls_table *nls_codepage, int remap)
1014{
1015 TRANSACTION2_SPI_REQ *pSMB = NULL;
1016 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1017 int name_len;
1018 int rc = 0;
1019 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001020 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001021 OPEN_PSX_REQ *pdata;
1022 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001023
Joe Perchesb6b38f72010-04-21 03:50:45 +00001024 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001025PsxCreat:
1026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1027 (void **) &pSMBr);
1028 if (rc)
1029 return rc;
1030
1031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1032 name_len =
1033 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1034 PATH_MAX, nls_codepage, remap);
1035 name_len++; /* trailing null */
1036 name_len *= 2;
1037 } else { /* BB improve the check for buffer overruns BB */
1038 name_len = strnlen(name, PATH_MAX);
1039 name_len++; /* trailing null */
1040 strncpy(pSMB->FileName, name, name_len);
1041 }
1042
1043 params = 6 + name_len;
1044 count = sizeof(OPEN_PSX_REQ);
1045 pSMB->MaxParameterCount = cpu_to_le16(2);
1046 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1047 pSMB->MaxSetupCount = 0;
1048 pSMB->Reserved = 0;
1049 pSMB->Flags = 0;
1050 pSMB->Timeout = 0;
1051 pSMB->Reserved2 = 0;
1052 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001053 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001054 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001055 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001056 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001057 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001058 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001059 pdata->OpenFlags = cpu_to_le32(*pOplock);
1060 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1061 pSMB->DataOffset = cpu_to_le16(offset);
1062 pSMB->SetupCount = 1;
1063 pSMB->Reserved3 = 0;
1064 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1065 byte_count = 3 /* pad */ + params + count;
1066
1067 pSMB->DataCount = cpu_to_le16(count);
1068 pSMB->ParameterCount = cpu_to_le16(params);
1069 pSMB->TotalDataCount = pSMB->DataCount;
1070 pSMB->TotalParameterCount = pSMB->ParameterCount;
1071 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1072 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001073 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001074 pSMB->ByteCount = cpu_to_le16(byte_count);
1075 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1076 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1077 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001078 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001079 goto psx_create_err;
1080 }
1081
Joe Perchesb6b38f72010-04-21 03:50:45 +00001082 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001083 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1084
Jeff Layton820a8032011-05-04 08:05:26 -04001085 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001086 rc = -EIO; /* bad smb */
1087 goto psx_create_err;
1088 }
1089
1090 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001091 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001092 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001093
Steve French2dd29d32007-04-23 22:07:35 +00001094 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001095 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001096 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1097 /* Let caller know file was created so we can set the mode. */
1098 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001099 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001100 *pOplock |= CIFS_CREATE_ACTION;
1101 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1103 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001104 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001105 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001106 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001107 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001108 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001109 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001110 goto psx_create_err;
1111 }
Steve French50c2f752007-07-13 00:33:32 +00001112 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001114 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001115 }
Steve French2dd29d32007-04-23 22:07:35 +00001116
1117psx_create_err:
1118 cifs_buf_release(pSMB);
1119
Steve French65bc98b2009-07-10 15:27:25 +00001120 if (posix_flags & SMB_O_DIRECTORY)
1121 cifs_stats_inc(&tcon->num_posixmkdirs);
1122 else
1123 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125 if (rc == -EAGAIN)
1126 goto PsxCreat;
1127
Steve French50c2f752007-07-13 00:33:32 +00001128 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001129}
1130
Steve Frencha9d02ad2005-08-24 23:06:05 -07001131static __u16 convert_disposition(int disposition)
1132{
1133 __u16 ofun = 0;
1134
1135 switch (disposition) {
1136 case FILE_SUPERSEDE:
1137 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1138 break;
1139 case FILE_OPEN:
1140 ofun = SMBOPEN_OAPPEND;
1141 break;
1142 case FILE_CREATE:
1143 ofun = SMBOPEN_OCREATE;
1144 break;
1145 case FILE_OPEN_IF:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1147 break;
1148 case FILE_OVERWRITE:
1149 ofun = SMBOPEN_OTRUNC;
1150 break;
1151 case FILE_OVERWRITE_IF:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1153 break;
1154 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001155 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156 ofun = SMBOPEN_OAPPEND; /* regular open */
1157 }
1158 return ofun;
1159}
1160
Jeff Layton35fc37d2008-05-14 10:22:03 -07001161static int
1162access_flags_to_smbopen_mode(const int access_flags)
1163{
1164 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1165
1166 if (masked_flags == GENERIC_READ)
1167 return SMBOPEN_READ;
1168 else if (masked_flags == GENERIC_WRITE)
1169 return SMBOPEN_WRITE;
1170
1171 /* just go for read/write */
1172 return SMBOPEN_READWRITE;
1173}
1174
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175int
1176SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1177 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001178 const int access_flags, const int create_options, __u16 *netfid,
1179 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 const struct nls_table *nls_codepage, int remap)
1181{
1182 int rc = -EACCES;
1183 OPENX_REQ *pSMB = NULL;
1184 OPENX_RSP *pSMBr = NULL;
1185 int bytes_returned;
1186 int name_len;
1187 __u16 count;
1188
1189OldOpenRetry:
1190 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1191 (void **) &pSMBr);
1192 if (rc)
1193 return rc;
1194
1195 pSMB->AndXCommand = 0xFF; /* none */
1196
1197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1198 count = 1; /* account for one byte pad to word boundary */
1199 name_len =
1200 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1201 fileName, PATH_MAX, nls_codepage, remap);
1202 name_len++; /* trailing null */
1203 name_len *= 2;
1204 } else { /* BB improve check for buffer overruns BB */
1205 count = 0; /* no pad */
1206 name_len = strnlen(fileName, PATH_MAX);
1207 name_len++; /* trailing null */
1208 strncpy(pSMB->fileName, fileName, name_len);
1209 }
1210 if (*pOplock & REQ_OPLOCK)
1211 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001212 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001214
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001216 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1221
Steve French790fe572007-07-07 19:25:05 +00001222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
Jeff Layton67750fb2008-05-09 22:28:02 +00001227 if (create_options & CREATE_OPTION_READONLY)
1228 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
1230 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001231/* pSMB->CreateOptions = cpu_to_le32(create_options &
1232 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001234
1235 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001236 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001238 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239
1240 pSMB->ByteCount = cpu_to_le16(count);
1241 /* long_op set to 1 to allow for oplock break timeouts */
1242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001243 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 cifs_stats_inc(&tcon->num_opens);
1245 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001246 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 } else {
1248 /* BB verify if wct == 15 */
1249
Steve French582d21e2008-05-13 04:54:12 +00001250/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251
1252 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1253 /* Let caller know file was created so we can set the mode. */
1254 /* Do we care about the CreateAction in any other cases? */
1255 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001256/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 *pOplock |= CIFS_CREATE_ACTION; */
1258 /* BB FIXME END */
1259
Steve French790fe572007-07-07 19:25:05 +00001260 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1262 pfile_info->LastAccessTime = 0; /* BB fixme */
1263 pfile_info->LastWriteTime = 0; /* BB fixme */
1264 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001265 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001266 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->AllocationSize =
1269 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1270 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001272 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 }
1274 }
1275
1276 cifs_buf_release(pSMB);
1277 if (rc == -EAGAIN)
1278 goto OldOpenRetry;
1279 return rc;
1280}
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282int
1283CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1284 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001285 const int access_flags, const int create_options, __u16 *netfid,
1286 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001287 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288{
1289 int rc = -EACCES;
1290 OPEN_REQ *pSMB = NULL;
1291 OPEN_RSP *pSMBr = NULL;
1292 int bytes_returned;
1293 int name_len;
1294 __u16 count;
1295
1296openRetry:
1297 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1298 (void **) &pSMBr);
1299 if (rc)
1300 return rc;
1301
1302 pSMB->AndXCommand = 0xFF; /* none */
1303
1304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1305 count = 1; /* account for one byte pad to word boundary */
1306 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001307 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001308 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 name_len++; /* trailing null */
1310 name_len *= 2;
1311 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001312 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 count = 0; /* no pad */
1314 name_len = strnlen(fileName, PATH_MAX);
1315 name_len++; /* trailing null */
1316 pSMB->NameLength = cpu_to_le16(name_len);
1317 strncpy(pSMB->fileName, fileName, name_len);
1318 }
1319 if (*pOplock & REQ_OPLOCK)
1320 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001321 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1324 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001325 /* set file as system file if special file such
1326 as fifo and server expecting SFU style and
1327 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001328 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001329 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1330 else
1331 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 /* XP does not handle ATTR_POSIX_SEMANTICS */
1334 /* but it helps speed up case sensitive checks for other
1335 servers such as Samba */
1336 if (tcon->ses->capabilities & CAP_UNIX)
1337 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1338
Jeff Layton67750fb2008-05-09 22:28:02 +00001339 if (create_options & CREATE_OPTION_READONLY)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1343 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001344 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001345 /* BB Expirement with various impersonation levels and verify */
1346 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->SecurityFlags =
1348 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1349
1350 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001351 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
1353 pSMB->ByteCount = cpu_to_le16(count);
1354 /* long_op set to 1 to allow for oplock break timeouts */
1355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001356 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001357 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001359 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 } else {
Steve French09d1db52005-04-28 22:41:08 -07001361 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1363 /* Let caller know file was created so we can set the mode. */
1364 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001365 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001366 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001367 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001368 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1369 36 /* CreationTime to Attributes */);
1370 /* the file_info buf is endian converted by caller */
1371 pfile_info->AllocationSize = pSMBr->AllocationSize;
1372 pfile_info->EndOfFile = pSMBr->EndOfFile;
1373 pfile_info->NumberOfLinks = cpu_to_le32(1);
1374 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 cifs_buf_release(pSMB);
1379 if (rc == -EAGAIN)
1380 goto openRetry;
1381 return rc;
1382}
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384int
Steve French50c2f752007-07-13 00:33:32 +00001385CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1386 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1387 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388{
1389 int rc = -EACCES;
1390 READ_REQ *pSMB = NULL;
1391 READ_RSP *pSMBr = NULL;
1392 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001393 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001394 int resp_buf_type = 0;
1395 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Joe Perchesb6b38f72010-04-21 03:50:45 +00001397 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001398 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001399 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001400 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001401 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001402 if ((lseek >> 32) > 0) {
1403 /* can not handle this big offset for old */
1404 return -EIO;
1405 }
1406 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407
1408 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001409 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 if (rc)
1411 return rc;
1412
1413 /* 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;
1419 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001420 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421 pSMB->OffsetHigh = cpu_to_le32(lseek >> 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
1490CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1491 const int netfid, const unsigned int count,
1492 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001493 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494{
1495 int rc = -EACCES;
1496 WRITE_REQ *pSMB = NULL;
1497 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001498 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499 __u32 bytes_sent;
1500 __u16 byte_count;
1501
Steve Frencha24e2d72010-04-03 17:20:21 +00001502 *nbytes = 0;
1503
Joe Perchesb6b38f72010-04-21 03:50:45 +00001504 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001505 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001506 return -ECONNABORTED;
1507
Steve French790fe572007-07-07 19:25:05 +00001508 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001509 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001510 else {
Steve French1c955182005-08-30 20:58:07 -07001511 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001512 if ((offset >> 32) > 0) {
1513 /* can not handle big offset for old srv */
1514 return -EIO;
1515 }
1516 }
Steve French1c955182005-08-30 20:58:07 -07001517
1518 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 (void **) &pSMBr);
1520 if (rc)
1521 return rc;
1522 /* tcon and ses pointer are checked in smb_init */
1523 if (tcon->ses->server == NULL)
1524 return -ECONNABORTED;
1525
1526 pSMB->AndXCommand = 0xFF; /* none */
1527 pSMB->Fid = netfid;
1528 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001529 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001530 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001531
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 pSMB->Reserved = 0xFFFFFFFF;
1533 pSMB->WriteMode = 0;
1534 pSMB->Remaining = 0;
1535
Steve French50c2f752007-07-13 00:33:32 +00001536 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 can send more if LARGE_WRITE_X capability returned by the server and if
1538 our buffer is big enough or if we convert to iovecs on socket writes
1539 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001540 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1542 } else {
1543 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1544 & ~0xFF;
1545 }
1546
1547 if (bytes_sent > count)
1548 bytes_sent = count;
1549 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001550 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001551 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001552 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001553 else if (ubuf) {
1554 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 cifs_buf_release(pSMB);
1556 return -EFAULT;
1557 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001558 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 /* No buffer */
1560 cifs_buf_release(pSMB);
1561 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001562 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001563 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001565 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001566 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001567
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1569 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001570 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001571
Steve French790fe572007-07-07 19:25:05 +00001572 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001573 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001574 else { /* old style write has byte count 4 bytes earlier
1575 so 4 bytes pad */
1576 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001577 (struct smb_com_writex_req *)pSMB;
1578 pSMBW->ByteCount = cpu_to_le16(byte_count);
1579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1582 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001583 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001585 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 } else {
1587 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1588 *nbytes = (*nbytes) << 16;
1589 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301590
1591 /*
1592 * Mask off high 16 bits when bytes written as returned by the
1593 * server is greater than bytes requested by the client. Some
1594 * OS/2 servers are known to set incorrect CountHigh values.
1595 */
1596 if (*nbytes > count)
1597 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 }
1599
1600 cifs_buf_release(pSMB);
1601
Steve French50c2f752007-07-13 00:33:32 +00001602 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 since file handle passed in no longer valid */
1604
1605 return rc;
1606}
1607
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001608void
1609cifs_writedata_release(struct kref *refcount)
1610{
1611 struct cifs_writedata *wdata = container_of(refcount,
1612 struct cifs_writedata, refcount);
1613
1614 if (wdata->cfile)
1615 cifsFileInfo_put(wdata->cfile);
1616
1617 kfree(wdata);
1618}
1619
1620/*
1621 * Write failed with a retryable error. Resend the write request. It's also
1622 * possible that the page was redirtied so re-clean the page.
1623 */
1624static void
1625cifs_writev_requeue(struct cifs_writedata *wdata)
1626{
1627 int i, rc;
1628 struct inode *inode = wdata->cfile->dentry->d_inode;
1629
1630 for (i = 0; i < wdata->nr_pages; i++) {
1631 lock_page(wdata->pages[i]);
1632 clear_page_dirty_for_io(wdata->pages[i]);
1633 }
1634
1635 do {
1636 rc = cifs_async_writev(wdata);
1637 } while (rc == -EAGAIN);
1638
1639 for (i = 0; i < wdata->nr_pages; i++) {
1640 if (rc != 0)
1641 SetPageError(wdata->pages[i]);
1642 unlock_page(wdata->pages[i]);
1643 }
1644
1645 mapping_set_error(inode->i_mapping, rc);
1646 kref_put(&wdata->refcount, cifs_writedata_release);
1647}
1648
1649static void
1650cifs_writev_complete(struct work_struct *work)
1651{
1652 struct cifs_writedata *wdata = container_of(work,
1653 struct cifs_writedata, work);
1654 struct inode *inode = wdata->cfile->dentry->d_inode;
1655 int i = 0;
1656
1657 if (wdata->result == 0) {
1658 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1659 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1660 wdata->bytes);
1661 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1662 return cifs_writev_requeue(wdata);
1663
1664 for (i = 0; i < wdata->nr_pages; i++) {
1665 struct page *page = wdata->pages[i];
1666 if (wdata->result == -EAGAIN)
1667 __set_page_dirty_nobuffers(page);
1668 else if (wdata->result < 0)
1669 SetPageError(page);
1670 end_page_writeback(page);
1671 page_cache_release(page);
1672 }
1673 if (wdata->result != -EAGAIN)
1674 mapping_set_error(inode->i_mapping, wdata->result);
1675 kref_put(&wdata->refcount, cifs_writedata_release);
1676}
1677
1678struct cifs_writedata *
1679cifs_writedata_alloc(unsigned int nr_pages)
1680{
1681 struct cifs_writedata *wdata;
1682
1683 /* this would overflow */
1684 if (nr_pages == 0) {
1685 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1686 return NULL;
1687 }
1688
1689 /* writedata + number of page pointers */
1690 wdata = kzalloc(sizeof(*wdata) +
1691 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1692 if (wdata != NULL) {
1693 INIT_WORK(&wdata->work, cifs_writev_complete);
1694 kref_init(&wdata->refcount);
1695 }
1696 return wdata;
1697}
1698
1699/*
1700 * Check the midState and signature on received buffer (if any), and queue the
1701 * workqueue completion task.
1702 */
1703static void
1704cifs_writev_callback(struct mid_q_entry *mid)
1705{
1706 struct cifs_writedata *wdata = mid->callback_data;
1707 struct cifsTconInfo *tcon = tlink_tcon(wdata->cfile->tlink);
1708 unsigned int written;
1709 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1710
1711 switch (mid->midState) {
1712 case MID_RESPONSE_RECEIVED:
1713 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1714 if (wdata->result != 0)
1715 break;
1716
1717 written = le16_to_cpu(smb->CountHigh);
1718 written <<= 16;
1719 written += le16_to_cpu(smb->Count);
1720 /*
1721 * Mask off high 16 bits when bytes written as returned
1722 * by the server is greater than bytes requested by the
1723 * client. OS/2 servers are known to set incorrect
1724 * CountHigh values.
1725 */
1726 if (written > wdata->bytes)
1727 written &= 0xFFFF;
1728
1729 if (written < wdata->bytes)
1730 wdata->result = -ENOSPC;
1731 else
1732 wdata->bytes = written;
1733 break;
1734 case MID_REQUEST_SUBMITTED:
1735 case MID_RETRY_NEEDED:
1736 wdata->result = -EAGAIN;
1737 break;
1738 default:
1739 wdata->result = -EIO;
1740 break;
1741 }
1742
1743 queue_work(system_nrt_wq, &wdata->work);
1744 DeleteMidQEntry(mid);
1745 atomic_dec(&tcon->ses->server->inFlight);
1746 wake_up(&tcon->ses->server->request_q);
1747}
1748
1749/* cifs_async_writev - send an async write, and set up mid to handle result */
1750int
1751cifs_async_writev(struct cifs_writedata *wdata)
1752{
1753 int i, rc = -EACCES;
1754 WRITE_REQ *smb = NULL;
1755 int wct;
1756 struct cifsTconInfo *tcon = tlink_tcon(wdata->cfile->tlink);
1757 struct inode *inode = wdata->cfile->dentry->d_inode;
1758 struct kvec *iov = NULL;
1759
1760 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1761 wct = 14;
1762 } else {
1763 wct = 12;
1764 if (wdata->offset >> 32 > 0) {
1765 /* can not handle big offset for old srv */
1766 return -EIO;
1767 }
1768 }
1769
1770 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
1771 if (rc)
1772 goto async_writev_out;
1773
1774 /* 1 iov per page + 1 for header */
1775 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
1776 if (iov == NULL) {
1777 rc = -ENOMEM;
1778 goto async_writev_out;
1779 }
1780
1781 smb->AndXCommand = 0xFF; /* none */
1782 smb->Fid = wdata->cfile->netfid;
1783 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
1784 if (wct == 14)
1785 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
1786 smb->Reserved = 0xFFFFFFFF;
1787 smb->WriteMode = 0;
1788 smb->Remaining = 0;
1789
1790 smb->DataOffset =
1791 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1792
1793 /* 4 for RFC1001 length + 1 for BCC */
1794 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
1795 iov[0].iov_base = smb;
1796
1797 /* marshal up the pages into iov array */
1798 wdata->bytes = 0;
1799 for (i = 0; i < wdata->nr_pages; i++) {
1800 iov[i + 1].iov_len = min(inode->i_size -
1801 page_offset(wdata->pages[i]),
1802 (loff_t)PAGE_CACHE_SIZE);
1803 iov[i + 1].iov_base = kmap(wdata->pages[i]);
1804 wdata->bytes += iov[i + 1].iov_len;
1805 }
1806
1807 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
1808
1809 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
1810 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
1811
1812 if (wct == 14) {
1813 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
1814 put_bcc(wdata->bytes + 1, &smb->hdr);
1815 } else {
1816 /* wct == 12 */
1817 struct smb_com_writex_req *smbw =
1818 (struct smb_com_writex_req *)smb;
1819 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
1820 put_bcc(wdata->bytes + 5, &smbw->hdr);
1821 iov[0].iov_len += 4; /* pad bigger by four bytes */
1822 }
1823
1824 kref_get(&wdata->refcount);
1825 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
1826 cifs_writev_callback, wdata, false);
1827
1828 if (rc == 0)
1829 cifs_stats_inc(&tcon->num_writes);
1830 else
1831 kref_put(&wdata->refcount, cifs_writedata_release);
1832
1833 /* send is done, unmap pages */
1834 for (i = 0; i < wdata->nr_pages; i++)
1835 kunmap(wdata->pages[i]);
1836
1837async_writev_out:
1838 cifs_small_buf_release(smb);
1839 kfree(iov);
1840 return rc;
1841}
1842
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001843int
1844CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001846 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1847 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848{
1849 int rc = -EACCES;
1850 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001851 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001852 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001853 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001855 *nbytes = 0;
1856
Joe Perchesb6b38f72010-04-21 03:50:45 +00001857 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001858
Steve French4c3130e2008-12-09 00:28:16 +00001859 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001860 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001861 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001862 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001863 if ((offset >> 32) > 0) {
1864 /* can not handle big offset for old srv */
1865 return -EIO;
1866 }
1867 }
Steve French8cc64c62005-10-03 13:49:43 -07001868 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 if (rc)
1870 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 /* tcon and ses pointer are checked in smb_init */
1872 if (tcon->ses->server == NULL)
1873 return -ECONNABORTED;
1874
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001875 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 pSMB->Fid = netfid;
1877 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001878 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001879 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 pSMB->Reserved = 0xFFFFFFFF;
1881 pSMB->WriteMode = 0;
1882 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001883
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001885 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
Steve French3e844692005-10-03 13:37:24 -07001887 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1888 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001889 /* header + 1 byte pad */
1890 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001891 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001892 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001893 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001894 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001895 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001896 pSMB->ByteCount = cpu_to_le16(count + 1);
1897 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001898 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001899 (struct smb_com_writex_req *)pSMB;
1900 pSMBW->ByteCount = cpu_to_le16(count + 5);
1901 }
Steve French3e844692005-10-03 13:37:24 -07001902 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001903 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001904 iov[0].iov_len = smb_hdr_len + 4;
1905 else /* wct == 12 pad bigger by four bytes */
1906 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001907
Steve French3e844692005-10-03 13:37:24 -07001908
Steve Frenchec637e32005-12-12 20:53:18 -08001909 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001910 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001911 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001913 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001914 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001915 /* presumably this can not happen, but best to be safe */
1916 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001917 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001918 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001919 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1920 *nbytes = (*nbytes) << 16;
1921 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301922
1923 /*
1924 * Mask off high 16 bits when bytes written as returned by the
1925 * server is greater than bytes requested by the client. OS/2
1926 * servers are known to set incorrect CountHigh values.
1927 */
1928 if (*nbytes > count)
1929 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001930 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
Steve French4b8f9302006-02-26 16:41:18 +00001932/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001933 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001934 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001935 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001936 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
Steve French50c2f752007-07-13 00:33:32 +00001938 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001939 since file handle passed in no longer valid */
1940
1941 return rc;
1942}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001943
1944
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945int
1946CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1947 const __u16 smb_file_id, const __u64 len,
1948 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001949 const __u32 numLock, const __u8 lockType,
1950 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951{
1952 int rc = 0;
1953 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001954/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 int bytes_returned;
1956 int timeout = 0;
1957 __u16 count;
1958
Joe Perchesb6b38f72010-04-21 03:50:45 +00001959 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001960 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 if (rc)
1963 return rc;
1964
Steve French790fe572007-07-07 19:25:05 +00001965 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001966 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001968 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001969 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1971 } else {
1972 pSMB->Timeout = 0;
1973 }
1974
1975 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1976 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1977 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001978 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 pSMB->AndXCommand = 0xFF; /* none */
1980 pSMB->Fid = smb_file_id; /* netfid stays le */
1981
Steve French790fe572007-07-07 19:25:05 +00001982 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1984 /* BB where to store pid high? */
1985 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1986 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1987 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1988 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1989 count = sizeof(LOCKING_ANDX_RANGE);
1990 } else {
1991 /* oplock break */
1992 count = 0;
1993 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001994 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 pSMB->ByteCount = cpu_to_le16(count);
1996
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001997 if (waitFlag) {
1998 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001999 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002000 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002001 } else {
Steve French133672e2007-11-13 22:41:37 +00002002 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2003 timeout);
2004 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002005 }
Steve Frencha4544342005-08-24 13:59:35 -07002006 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002007 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002008 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009
Steve French50c2f752007-07-13 00:33:32 +00002010 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 since file handle passed in no longer valid */
2012 return rc;
2013}
2014
2015int
Steve French08547b02006-02-28 22:39:25 +00002016CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
2017 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00002018 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00002019 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002020{
2021 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2022 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002023 struct cifs_posix_lock *parm_data;
2024 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002025 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002026 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002027 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002028 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002029 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002030
Joe Perchesb6b38f72010-04-21 03:50:45 +00002031 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002032
Steve French790fe572007-07-07 19:25:05 +00002033 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002034 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002035
Steve French08547b02006-02-28 22:39:25 +00002036 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2037
2038 if (rc)
2039 return rc;
2040
2041 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2042
Steve French50c2f752007-07-13 00:33:32 +00002043 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002044 pSMB->MaxSetupCount = 0;
2045 pSMB->Reserved = 0;
2046 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002047 pSMB->Reserved2 = 0;
2048 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2049 offset = param_offset + params;
2050
Steve French08547b02006-02-28 22:39:25 +00002051 count = sizeof(struct cifs_posix_lock);
2052 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002053 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002054 pSMB->SetupCount = 1;
2055 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002056 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002057 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2058 else
2059 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2060 byte_count = 3 /* pad */ + params + count;
2061 pSMB->DataCount = cpu_to_le16(count);
2062 pSMB->ParameterCount = cpu_to_le16(params);
2063 pSMB->TotalDataCount = pSMB->DataCount;
2064 pSMB->TotalParameterCount = pSMB->ParameterCount;
2065 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002066 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002067 (((char *) &pSMB->hdr.Protocol) + offset);
2068
2069 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002070 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002071 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002072 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002073 pSMB->Timeout = cpu_to_le32(-1);
2074 } else
2075 pSMB->Timeout = 0;
2076
Steve French08547b02006-02-28 22:39:25 +00002077 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002078 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002079 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002080
2081 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002082 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002083 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2084 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002085 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002086 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002087 if (waitFlag) {
2088 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2089 (struct smb_hdr *) pSMBr, &bytes_returned);
2090 } else {
Steve French133672e2007-11-13 22:41:37 +00002091 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002092 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002093 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2094 &resp_buf_type, timeout);
2095 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2096 not try to free it twice below on exit */
2097 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002098 }
2099
Steve French08547b02006-02-28 22:39:25 +00002100 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002101 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002102 } else if (get_flag) {
2103 /* lock structure can be returned on get */
2104 __u16 data_offset;
2105 __u16 data_count;
2106 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002107
Jeff Layton820a8032011-05-04 08:05:26 -04002108 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002109 rc = -EIO; /* bad smb */
2110 goto plk_err_exit;
2111 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002112 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2113 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002114 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002115 rc = -EIO;
2116 goto plk_err_exit;
2117 }
2118 parm_data = (struct cifs_posix_lock *)
2119 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002120 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002121 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002122 else {
2123 if (parm_data->lock_type ==
2124 __constant_cpu_to_le16(CIFS_RDLCK))
2125 pLockData->fl_type = F_RDLCK;
2126 else if (parm_data->lock_type ==
2127 __constant_cpu_to_le16(CIFS_WRLCK))
2128 pLockData->fl_type = F_WRLCK;
2129
Steve French5443d132011-03-13 05:08:25 +00002130 pLockData->fl_start = le64_to_cpu(parm_data->start);
2131 pLockData->fl_end = pLockData->fl_start +
2132 le64_to_cpu(parm_data->length) - 1;
2133 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002134 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002135 }
Steve French50c2f752007-07-13 00:33:32 +00002136
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002137plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002138 if (pSMB)
2139 cifs_small_buf_release(pSMB);
2140
Steve French133672e2007-11-13 22:41:37 +00002141 if (resp_buf_type == CIFS_SMALL_BUFFER)
2142 cifs_small_buf_release(iov[0].iov_base);
2143 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2144 cifs_buf_release(iov[0].iov_base);
2145
Steve French08547b02006-02-28 22:39:25 +00002146 /* Note: On -EAGAIN error only caller can retry on handle based calls
2147 since file handle passed in no longer valid */
2148
2149 return rc;
2150}
2151
2152
2153int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
2155{
2156 int rc = 0;
2157 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002158 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159
2160/* do not retry on dead session on close */
2161 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002162 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163 return 0;
2164 if (rc)
2165 return rc;
2166
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002168 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002169 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002170 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002171 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002173 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002175 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 }
2177 }
2178
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002180 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 rc = 0;
2182
2183 return rc;
2184}
2185
2186int
Steve Frenchb298f222009-02-21 21:17:43 +00002187CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
2188{
2189 int rc = 0;
2190 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002191 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002192
2193 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2194 if (rc)
2195 return rc;
2196
2197 pSMB->FileID = (__u16) smb_file_id;
2198 pSMB->ByteCount = 0;
2199 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2200 cifs_stats_inc(&tcon->num_flushes);
2201 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002202 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002203
2204 return rc;
2205}
2206
2207int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
2209 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002210 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211{
2212 int rc = 0;
2213 RENAME_REQ *pSMB = NULL;
2214 RENAME_RSP *pSMBr = NULL;
2215 int bytes_returned;
2216 int name_len, name_len2;
2217 __u16 count;
2218
Joe Perchesb6b38f72010-04-21 03:50:45 +00002219 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220renameRetry:
2221 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2222 (void **) &pSMBr);
2223 if (rc)
2224 return rc;
2225
2226 pSMB->BufferFormat = 0x04;
2227 pSMB->SearchAttributes =
2228 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2229 ATTR_DIRECTORY);
2230
2231 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2232 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002233 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002234 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235 name_len++; /* trailing null */
2236 name_len *= 2;
2237 pSMB->OldFileName[name_len] = 0x04; /* pad */
2238 /* protocol requires ASCII signature byte on Unicode string */
2239 pSMB->OldFileName[name_len + 1] = 0x00;
2240 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002241 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002242 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2244 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002245 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 name_len = strnlen(fromName, PATH_MAX);
2247 name_len++; /* trailing null */
2248 strncpy(pSMB->OldFileName, fromName, name_len);
2249 name_len2 = strnlen(toName, PATH_MAX);
2250 name_len2++; /* trailing null */
2251 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2252 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2253 name_len2++; /* trailing null */
2254 name_len2++; /* signature byte */
2255 }
2256
2257 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002258 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002259 pSMB->ByteCount = cpu_to_le16(count);
2260
2261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002263 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002264 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002265 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002266
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 cifs_buf_release(pSMB);
2268
2269 if (rc == -EAGAIN)
2270 goto renameRetry;
2271
2272 return rc;
2273}
2274
Steve French50c2f752007-07-13 00:33:32 +00002275int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002276 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002277 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278{
2279 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2280 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002281 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 char *data_offset;
2283 char dummy_string[30];
2284 int rc = 0;
2285 int bytes_returned = 0;
2286 int len_of_str;
2287 __u16 params, param_offset, offset, count, byte_count;
2288
Joe Perchesb6b38f72010-04-21 03:50:45 +00002289 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2291 (void **) &pSMBr);
2292 if (rc)
2293 return rc;
2294
2295 params = 6;
2296 pSMB->MaxSetupCount = 0;
2297 pSMB->Reserved = 0;
2298 pSMB->Flags = 0;
2299 pSMB->Timeout = 0;
2300 pSMB->Reserved2 = 0;
2301 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2302 offset = param_offset + params;
2303
2304 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2305 rename_info = (struct set_file_rename *) data_offset;
2306 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002307 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 pSMB->SetupCount = 1;
2309 pSMB->Reserved3 = 0;
2310 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2311 byte_count = 3 /* pad */ + params;
2312 pSMB->ParameterCount = cpu_to_le16(params);
2313 pSMB->TotalParameterCount = pSMB->ParameterCount;
2314 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2315 pSMB->DataOffset = cpu_to_le16(offset);
2316 /* construct random name ".cifs_tmp<inodenum><mid>" */
2317 rename_info->overwrite = cpu_to_le32(1);
2318 rename_info->root_fid = 0;
2319 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002320 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002321 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2322 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002323 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002325 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002326 target_name, PATH_MAX, nls_codepage,
2327 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 }
2329 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002330 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 byte_count += count;
2332 pSMB->DataCount = cpu_to_le16(count);
2333 pSMB->TotalDataCount = pSMB->DataCount;
2334 pSMB->Fid = netfid;
2335 pSMB->InformationLevel =
2336 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2337 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002338 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339 pSMB->ByteCount = cpu_to_le16(byte_count);
2340 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002341 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002342 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002343 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002344 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002345
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 cifs_buf_release(pSMB);
2347
2348 /* Note: On -EAGAIN error only caller can retry on handle based calls
2349 since file handle passed in no longer valid */
2350
2351 return rc;
2352}
2353
2354int
Steve French50c2f752007-07-13 00:33:32 +00002355CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2356 const __u16 target_tid, const char *toName, const int flags,
2357 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358{
2359 int rc = 0;
2360 COPY_REQ *pSMB = NULL;
2361 COPY_RSP *pSMBr = NULL;
2362 int bytes_returned;
2363 int name_len, name_len2;
2364 __u16 count;
2365
Joe Perchesb6b38f72010-04-21 03:50:45 +00002366 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367copyRetry:
2368 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2369 (void **) &pSMBr);
2370 if (rc)
2371 return rc;
2372
2373 pSMB->BufferFormat = 0x04;
2374 pSMB->Tid2 = target_tid;
2375
2376 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2377
2378 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002379 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002380 fromName, PATH_MAX, nls_codepage,
2381 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 name_len++; /* trailing null */
2383 name_len *= 2;
2384 pSMB->OldFileName[name_len] = 0x04; /* pad */
2385 /* protocol requires ASCII signature byte on Unicode string */
2386 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002387 name_len2 =
2388 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002389 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2391 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002392 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 name_len = strnlen(fromName, PATH_MAX);
2394 name_len++; /* trailing null */
2395 strncpy(pSMB->OldFileName, fromName, name_len);
2396 name_len2 = strnlen(toName, PATH_MAX);
2397 name_len2++; /* trailing null */
2398 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2399 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2400 name_len2++; /* trailing null */
2401 name_len2++; /* signature byte */
2402 }
2403
2404 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002405 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 pSMB->ByteCount = cpu_to_le16(count);
2407
2408 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2409 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2410 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002411 cFYI(1, "Send error in copy = %d with %d files copied",
2412 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 }
Steve French0d817bc2008-05-22 02:02:03 +00002414 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
2416 if (rc == -EAGAIN)
2417 goto copyRetry;
2418
2419 return rc;
2420}
2421
2422int
2423CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2424 const char *fromName, const char *toName,
2425 const struct nls_table *nls_codepage)
2426{
2427 TRANSACTION2_SPI_REQ *pSMB = NULL;
2428 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2429 char *data_offset;
2430 int name_len;
2431 int name_len_target;
2432 int rc = 0;
2433 int bytes_returned = 0;
2434 __u16 params, param_offset, offset, byte_count;
2435
Joe Perchesb6b38f72010-04-21 03:50:45 +00002436 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437createSymLinkRetry:
2438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2439 (void **) &pSMBr);
2440 if (rc)
2441 return rc;
2442
2443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2444 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002445 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 /* find define for this maxpathcomponent */
2447 , nls_codepage);
2448 name_len++; /* trailing null */
2449 name_len *= 2;
2450
Steve French50c2f752007-07-13 00:33:32 +00002451 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 name_len = strnlen(fromName, PATH_MAX);
2453 name_len++; /* trailing null */
2454 strncpy(pSMB->FileName, fromName, name_len);
2455 }
2456 params = 6 + name_len;
2457 pSMB->MaxSetupCount = 0;
2458 pSMB->Reserved = 0;
2459 pSMB->Flags = 0;
2460 pSMB->Timeout = 0;
2461 pSMB->Reserved2 = 0;
2462 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002463 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 offset = param_offset + params;
2465
2466 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2467 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2468 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002469 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 /* find define for this maxpathcomponent */
2471 , nls_codepage);
2472 name_len_target++; /* trailing null */
2473 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002474 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 name_len_target = strnlen(toName, PATH_MAX);
2476 name_len_target++; /* trailing null */
2477 strncpy(data_offset, toName, name_len_target);
2478 }
2479
2480 pSMB->MaxParameterCount = cpu_to_le16(2);
2481 /* BB find exact max on data count below from sess */
2482 pSMB->MaxDataCount = cpu_to_le16(1000);
2483 pSMB->SetupCount = 1;
2484 pSMB->Reserved3 = 0;
2485 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2486 byte_count = 3 /* pad */ + params + name_len_target;
2487 pSMB->DataCount = cpu_to_le16(name_len_target);
2488 pSMB->ParameterCount = cpu_to_le16(params);
2489 pSMB->TotalDataCount = pSMB->DataCount;
2490 pSMB->TotalParameterCount = pSMB->ParameterCount;
2491 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2492 pSMB->DataOffset = cpu_to_le16(offset);
2493 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2494 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002495 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 pSMB->ByteCount = cpu_to_le16(byte_count);
2497 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002499 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002500 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002501 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
Steve French0d817bc2008-05-22 02:02:03 +00002503 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
2505 if (rc == -EAGAIN)
2506 goto createSymLinkRetry;
2507
2508 return rc;
2509}
2510
2511int
2512CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2513 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002514 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515{
2516 TRANSACTION2_SPI_REQ *pSMB = NULL;
2517 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2518 char *data_offset;
2519 int name_len;
2520 int name_len_target;
2521 int rc = 0;
2522 int bytes_returned = 0;
2523 __u16 params, param_offset, offset, byte_count;
2524
Joe Perchesb6b38f72010-04-21 03:50:45 +00002525 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526createHardLinkRetry:
2527 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2528 (void **) &pSMBr);
2529 if (rc)
2530 return rc;
2531
2532 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002533 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002534 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 name_len++; /* trailing null */
2536 name_len *= 2;
2537
Steve French50c2f752007-07-13 00:33:32 +00002538 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 name_len = strnlen(toName, PATH_MAX);
2540 name_len++; /* trailing null */
2541 strncpy(pSMB->FileName, toName, name_len);
2542 }
2543 params = 6 + name_len;
2544 pSMB->MaxSetupCount = 0;
2545 pSMB->Reserved = 0;
2546 pSMB->Flags = 0;
2547 pSMB->Timeout = 0;
2548 pSMB->Reserved2 = 0;
2549 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002550 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 offset = param_offset + params;
2552
2553 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2554 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2555 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002556 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002557 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 name_len_target++; /* trailing null */
2559 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002560 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 name_len_target = strnlen(fromName, PATH_MAX);
2562 name_len_target++; /* trailing null */
2563 strncpy(data_offset, fromName, name_len_target);
2564 }
2565
2566 pSMB->MaxParameterCount = cpu_to_le16(2);
2567 /* BB find exact max on data count below from sess*/
2568 pSMB->MaxDataCount = cpu_to_le16(1000);
2569 pSMB->SetupCount = 1;
2570 pSMB->Reserved3 = 0;
2571 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2572 byte_count = 3 /* pad */ + params + name_len_target;
2573 pSMB->ParameterCount = cpu_to_le16(params);
2574 pSMB->TotalParameterCount = pSMB->ParameterCount;
2575 pSMB->DataCount = cpu_to_le16(name_len_target);
2576 pSMB->TotalDataCount = pSMB->DataCount;
2577 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2578 pSMB->DataOffset = cpu_to_le16(offset);
2579 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2580 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002581 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 pSMB->ByteCount = cpu_to_le16(byte_count);
2583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2584 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002585 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002586 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002587 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
2589 cifs_buf_release(pSMB);
2590 if (rc == -EAGAIN)
2591 goto createHardLinkRetry;
2592
2593 return rc;
2594}
2595
2596int
2597CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2598 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002599 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600{
2601 int rc = 0;
2602 NT_RENAME_REQ *pSMB = NULL;
2603 RENAME_RSP *pSMBr = NULL;
2604 int bytes_returned;
2605 int name_len, name_len2;
2606 __u16 count;
2607
Joe Perchesb6b38f72010-04-21 03:50:45 +00002608 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609winCreateHardLinkRetry:
2610
2611 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2612 (void **) &pSMBr);
2613 if (rc)
2614 return rc;
2615
2616 pSMB->SearchAttributes =
2617 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2618 ATTR_DIRECTORY);
2619 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2620 pSMB->ClusterCount = 0;
2621
2622 pSMB->BufferFormat = 0x04;
2623
2624 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2625 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002626 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002627 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 name_len++; /* trailing null */
2629 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002630
2631 /* protocol specifies ASCII buffer format (0x04) for unicode */
2632 pSMB->OldFileName[name_len] = 0x04;
2633 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002635 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002636 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2638 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002639 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 name_len = strnlen(fromName, PATH_MAX);
2641 name_len++; /* trailing null */
2642 strncpy(pSMB->OldFileName, fromName, name_len);
2643 name_len2 = strnlen(toName, PATH_MAX);
2644 name_len2++; /* trailing null */
2645 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2646 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2647 name_len2++; /* trailing null */
2648 name_len2++; /* signature byte */
2649 }
2650
2651 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002652 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 pSMB->ByteCount = cpu_to_le16(count);
2654
2655 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2656 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002657 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002658 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002659 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002660
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 cifs_buf_release(pSMB);
2662 if (rc == -EAGAIN)
2663 goto winCreateHardLinkRetry;
2664
2665 return rc;
2666}
2667
2668int
2669CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002670 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 const struct nls_table *nls_codepage)
2672{
2673/* SMB_QUERY_FILE_UNIX_LINK */
2674 TRANSACTION2_QPI_REQ *pSMB = NULL;
2675 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2676 int rc = 0;
2677 int bytes_returned;
2678 int name_len;
2679 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002680 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
Joe Perchesb6b38f72010-04-21 03:50:45 +00002682 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684querySymLinkRetry:
2685 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2686 (void **) &pSMBr);
2687 if (rc)
2688 return rc;
2689
2690 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2691 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002692 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2693 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 name_len++; /* trailing null */
2695 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002696 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 name_len = strnlen(searchName, PATH_MAX);
2698 name_len++; /* trailing null */
2699 strncpy(pSMB->FileName, searchName, name_len);
2700 }
2701
2702 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2703 pSMB->TotalDataCount = 0;
2704 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002705 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 pSMB->MaxSetupCount = 0;
2707 pSMB->Reserved = 0;
2708 pSMB->Flags = 0;
2709 pSMB->Timeout = 0;
2710 pSMB->Reserved2 = 0;
2711 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002712 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 pSMB->DataCount = 0;
2714 pSMB->DataOffset = 0;
2715 pSMB->SetupCount = 1;
2716 pSMB->Reserved3 = 0;
2717 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2718 byte_count = params + 1 /* pad */ ;
2719 pSMB->TotalParameterCount = cpu_to_le16(params);
2720 pSMB->ParameterCount = pSMB->TotalParameterCount;
2721 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2722 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002723 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 pSMB->ByteCount = cpu_to_le16(byte_count);
2725
2726 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2727 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2728 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002729 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 } else {
2731 /* decode response */
2732
2733 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002735 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002736 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002738 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002739 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740
Jeff Layton460b9692009-04-30 07:17:56 -04002741 data_start = ((char *) &pSMBr->hdr.Protocol) +
2742 le16_to_cpu(pSMBr->t2.DataOffset);
2743
Steve French0e0d2cf2009-05-01 05:27:32 +00002744 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2745 is_unicode = true;
2746 else
2747 is_unicode = false;
2748
Steve French737b7582005-04-28 22:41:06 -07002749 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002750 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002751 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002752 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002753 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 }
2755 }
2756 cifs_buf_release(pSMB);
2757 if (rc == -EAGAIN)
2758 goto querySymLinkRetry;
2759 return rc;
2760}
2761
Steve Frenchc52a9552011-02-24 06:16:22 +00002762#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2763/*
2764 * Recent Windows versions now create symlinks more frequently
2765 * and they use the "reparse point" mechanism below. We can of course
2766 * do symlinks nicely to Samba and other servers which support the
2767 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2768 * "MF" symlinks optionally, but for recent Windows we really need to
2769 * reenable the code below and fix the cifs_symlink callers to handle this.
2770 * In the interim this code has been moved to its own config option so
2771 * it is not compiled in by default until callers fixed up and more tested.
2772 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773int
2774CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2775 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002776 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 const struct nls_table *nls_codepage)
2778{
2779 int rc = 0;
2780 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002781 struct smb_com_transaction_ioctl_req *pSMB;
2782 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783
Joe Perchesb6b38f72010-04-21 03:50:45 +00002784 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2786 (void **) &pSMBr);
2787 if (rc)
2788 return rc;
2789
2790 pSMB->TotalParameterCount = 0 ;
2791 pSMB->TotalDataCount = 0;
2792 pSMB->MaxParameterCount = cpu_to_le32(2);
2793 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002794 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2795 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 pSMB->MaxSetupCount = 4;
2797 pSMB->Reserved = 0;
2798 pSMB->ParameterOffset = 0;
2799 pSMB->DataCount = 0;
2800 pSMB->DataOffset = 0;
2801 pSMB->SetupCount = 4;
2802 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2803 pSMB->ParameterCount = pSMB->TotalParameterCount;
2804 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2805 pSMB->IsFsctl = 1; /* FSCTL */
2806 pSMB->IsRootFlag = 0;
2807 pSMB->Fid = fid; /* file handle always le */
2808 pSMB->ByteCount = 0;
2809
2810 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2811 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2812 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002813 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 } else { /* decode response */
2815 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2816 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002817 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2818 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002820 goto qreparse_out;
2821 }
2822 if (data_count && (data_count < 2048)) {
2823 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002824 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825
Steve Frenchafe48c32009-05-02 05:25:46 +00002826 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002827 (struct reparse_data *)
2828 ((char *)&pSMBr->hdr.Protocol
2829 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002830 if ((char *)reparse_buf >= end_of_smb) {
2831 rc = -EIO;
2832 goto qreparse_out;
2833 }
2834 if ((reparse_buf->LinkNamesBuf +
2835 reparse_buf->TargetNameOffset +
2836 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002837 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002838 rc = -EIO;
2839 goto qreparse_out;
2840 }
Steve French50c2f752007-07-13 00:33:32 +00002841
Steve Frenchafe48c32009-05-02 05:25:46 +00002842 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2843 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002844 (reparse_buf->LinkNamesBuf +
2845 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002846 buflen,
2847 reparse_buf->TargetNameLen,
2848 nls_codepage, 0);
2849 } else { /* ASCII names */
2850 strncpy(symlinkinfo,
2851 reparse_buf->LinkNamesBuf +
2852 reparse_buf->TargetNameOffset,
2853 min_t(const int, buflen,
2854 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002856 } else {
2857 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002858 cFYI(1, "Invalid return data count on "
2859 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002861 symlinkinfo[buflen] = 0; /* just in case so the caller
2862 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002863 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 }
Steve French989c7e52009-05-02 05:32:20 +00002865
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002867 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868
2869 /* Note: On -EAGAIN error only caller can retry on handle based calls
2870 since file handle passed in no longer valid */
2871
2872 return rc;
2873}
Steve Frenchc52a9552011-02-24 06:16:22 +00002874#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875
2876#ifdef CONFIG_CIFS_POSIX
2877
2878/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002879static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2880 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881{
2882 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002883 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2884 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2885 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002886 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
2888 return;
2889}
2890
2891/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002892static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2893 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894{
2895 int size = 0;
2896 int i;
2897 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002898 struct cifs_posix_ace *pACE;
2899 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2900 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
2902 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2903 return -EOPNOTSUPP;
2904
Steve French790fe572007-07-07 19:25:05 +00002905 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 count = le16_to_cpu(cifs_acl->access_entry_count);
2907 pACE = &cifs_acl->ace_array[0];
2908 size = sizeof(struct cifs_posix_acl);
2909 size += sizeof(struct cifs_posix_ace) * count;
2910 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002911 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002912 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2913 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 return -EINVAL;
2915 }
Steve French790fe572007-07-07 19:25:05 +00002916 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 count = le16_to_cpu(cifs_acl->access_entry_count);
2918 size = sizeof(struct cifs_posix_acl);
2919 size += sizeof(struct cifs_posix_ace) * count;
2920/* skip past access ACEs to get to default ACEs */
2921 pACE = &cifs_acl->ace_array[count];
2922 count = le16_to_cpu(cifs_acl->default_entry_count);
2923 size += sizeof(struct cifs_posix_ace) * count;
2924 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002925 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 return -EINVAL;
2927 } else {
2928 /* illegal type */
2929 return -EINVAL;
2930 }
2931
2932 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002933 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002934 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002935 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 return -ERANGE;
2937 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002938 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002939 for (i = 0; i < count ; i++) {
2940 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2941 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 }
2943 }
2944 return size;
2945}
2946
Steve French50c2f752007-07-13 00:33:32 +00002947static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2948 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949{
2950 __u16 rc = 0; /* 0 = ACL converted ok */
2951
Steve Frenchff7feac2005-11-15 16:45:16 -08002952 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2953 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002955 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 /* Probably no need to le convert -1 on any arch but can not hurt */
2957 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002958 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002959 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002960 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 return rc;
2962}
2963
2964/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002965static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2966 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967{
2968 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002969 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2970 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 int count;
2972 int i;
2973
Steve French790fe572007-07-07 19:25:05 +00002974 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 return 0;
2976
2977 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002978 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002979 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002980 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002981 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002982 cFYI(1, "unknown POSIX ACL version %d",
2983 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 return 0;
2985 }
2986 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002987 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002988 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002989 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002990 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002992 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 return 0;
2994 }
Steve French50c2f752007-07-13 00:33:32 +00002995 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2997 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002998 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 /* ACE not converted */
3000 break;
3001 }
3002 }
Steve French790fe572007-07-07 19:25:05 +00003003 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3005 rc += sizeof(struct cifs_posix_acl);
3006 /* BB add check to make sure ACL does not overflow SMB */
3007 }
3008 return rc;
3009}
3010
3011int
3012CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003013 const unsigned char *searchName,
3014 char *acl_inf, const int buflen, const int acl_type,
3015 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016{
3017/* SMB_QUERY_POSIX_ACL */
3018 TRANSACTION2_QPI_REQ *pSMB = NULL;
3019 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3020 int rc = 0;
3021 int bytes_returned;
3022 int name_len;
3023 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003024
Joe Perchesb6b38f72010-04-21 03:50:45 +00003025 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
3027queryAclRetry:
3028 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3029 (void **) &pSMBr);
3030 if (rc)
3031 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003032
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3034 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003035 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003036 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 name_len++; /* trailing null */
3038 name_len *= 2;
3039 pSMB->FileName[name_len] = 0;
3040 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003041 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 name_len = strnlen(searchName, PATH_MAX);
3043 name_len++; /* trailing null */
3044 strncpy(pSMB->FileName, searchName, name_len);
3045 }
3046
3047 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3048 pSMB->TotalDataCount = 0;
3049 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003050 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 pSMB->MaxDataCount = cpu_to_le16(4000);
3052 pSMB->MaxSetupCount = 0;
3053 pSMB->Reserved = 0;
3054 pSMB->Flags = 0;
3055 pSMB->Timeout = 0;
3056 pSMB->Reserved2 = 0;
3057 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003058 offsetof(struct smb_com_transaction2_qpi_req,
3059 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 pSMB->DataCount = 0;
3061 pSMB->DataOffset = 0;
3062 pSMB->SetupCount = 1;
3063 pSMB->Reserved3 = 0;
3064 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3065 byte_count = params + 1 /* pad */ ;
3066 pSMB->TotalParameterCount = cpu_to_le16(params);
3067 pSMB->ParameterCount = pSMB->TotalParameterCount;
3068 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3069 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003070 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 pSMB->ByteCount = cpu_to_le16(byte_count);
3072
3073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003075 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003077 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 } else {
3079 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003080
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003083 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 rc = -EIO; /* bad smb */
3085 else {
3086 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3087 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3088 rc = cifs_copy_posix_acl(acl_inf,
3089 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003090 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 }
3092 }
3093 cifs_buf_release(pSMB);
3094 if (rc == -EAGAIN)
3095 goto queryAclRetry;
3096 return rc;
3097}
3098
3099int
3100CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003101 const unsigned char *fileName,
3102 const char *local_acl, const int buflen,
3103 const int acl_type,
3104 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105{
3106 struct smb_com_transaction2_spi_req *pSMB = NULL;
3107 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3108 char *parm_data;
3109 int name_len;
3110 int rc = 0;
3111 int bytes_returned = 0;
3112 __u16 params, byte_count, data_count, param_offset, offset;
3113
Joe Perchesb6b38f72010-04-21 03:50:45 +00003114 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115setAclRetry:
3116 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003117 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 if (rc)
3119 return rc;
3120 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3121 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003122 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003123 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 name_len++; /* trailing null */
3125 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003126 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 name_len = strnlen(fileName, PATH_MAX);
3128 name_len++; /* trailing null */
3129 strncpy(pSMB->FileName, fileName, name_len);
3130 }
3131 params = 6 + name_len;
3132 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003133 /* BB find max SMB size from sess */
3134 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 pSMB->MaxSetupCount = 0;
3136 pSMB->Reserved = 0;
3137 pSMB->Flags = 0;
3138 pSMB->Timeout = 0;
3139 pSMB->Reserved2 = 0;
3140 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003141 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 offset = param_offset + params;
3143 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3144 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3145
3146 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003147 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148
Steve French790fe572007-07-07 19:25:05 +00003149 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 rc = -EOPNOTSUPP;
3151 goto setACLerrorExit;
3152 }
3153 pSMB->DataOffset = cpu_to_le16(offset);
3154 pSMB->SetupCount = 1;
3155 pSMB->Reserved3 = 0;
3156 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3157 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3158 byte_count = 3 /* pad */ + params + data_count;
3159 pSMB->DataCount = cpu_to_le16(data_count);
3160 pSMB->TotalDataCount = pSMB->DataCount;
3161 pSMB->ParameterCount = cpu_to_le16(params);
3162 pSMB->TotalParameterCount = pSMB->ParameterCount;
3163 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003164 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 pSMB->ByteCount = cpu_to_le16(byte_count);
3166 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003167 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003168 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003169 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170
3171setACLerrorExit:
3172 cifs_buf_release(pSMB);
3173 if (rc == -EAGAIN)
3174 goto setAclRetry;
3175 return rc;
3176}
3177
Steve Frenchf654bac2005-04-28 22:41:04 -07003178/* BB fix tabs in this function FIXME BB */
3179int
3180CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003181 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003182{
Steve French50c2f752007-07-13 00:33:32 +00003183 int rc = 0;
3184 struct smb_t2_qfi_req *pSMB = NULL;
3185 struct smb_t2_qfi_rsp *pSMBr = NULL;
3186 int bytes_returned;
3187 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003188
Joe Perchesb6b38f72010-04-21 03:50:45 +00003189 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003190 if (tcon == NULL)
3191 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003192
3193GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003194 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3195 (void **) &pSMBr);
3196 if (rc)
3197 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003198
Steve Frenchad7a2922008-02-07 23:25:02 +00003199 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003200 pSMB->t2.TotalDataCount = 0;
3201 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3202 /* BB find exact max data count below from sess structure BB */
3203 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3204 pSMB->t2.MaxSetupCount = 0;
3205 pSMB->t2.Reserved = 0;
3206 pSMB->t2.Flags = 0;
3207 pSMB->t2.Timeout = 0;
3208 pSMB->t2.Reserved2 = 0;
3209 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3210 Fid) - 4);
3211 pSMB->t2.DataCount = 0;
3212 pSMB->t2.DataOffset = 0;
3213 pSMB->t2.SetupCount = 1;
3214 pSMB->t2.Reserved3 = 0;
3215 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3216 byte_count = params + 1 /* pad */ ;
3217 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3218 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3219 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3220 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003221 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003222 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003223 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003224
Steve French790fe572007-07-07 19:25:05 +00003225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3227 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003228 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003229 } else {
3230 /* decode response */
3231 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003232 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003233 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003234 /* If rc should we check for EOPNOSUPP and
3235 disable the srvino flag? or in caller? */
3236 rc = -EIO; /* bad smb */
3237 else {
3238 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3239 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3240 struct file_chattr_info *pfinfo;
3241 /* BB Do we need a cast or hash here ? */
3242 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003243 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003244 rc = -EIO;
3245 goto GetExtAttrOut;
3246 }
3247 pfinfo = (struct file_chattr_info *)
3248 (data_offset + (char *) &pSMBr->hdr.Protocol);
3249 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003250 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003251 }
3252 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003253GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003254 cifs_buf_release(pSMB);
3255 if (rc == -EAGAIN)
3256 goto GetExtAttrRetry;
3257 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003258}
3259
Steve Frenchf654bac2005-04-28 22:41:04 -07003260#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261
Jeff Layton79df1ba2010-12-06 12:52:08 -05003262#ifdef CONFIG_CIFS_ACL
3263/*
3264 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3265 * all NT TRANSACTS that we init here have total parm and data under about 400
3266 * bytes (to fit in small cifs buffer size), which is the case so far, it
3267 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3268 * returned setup area) and MaxParameterCount (returned parms size) must be set
3269 * by caller
3270 */
3271static int
3272smb_init_nttransact(const __u16 sub_command, const int setup_count,
3273 const int parm_len, struct cifsTconInfo *tcon,
3274 void **ret_buf)
3275{
3276 int rc;
3277 __u32 temp_offset;
3278 struct smb_com_ntransact_req *pSMB;
3279
3280 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3281 (void **)&pSMB);
3282 if (rc)
3283 return rc;
3284 *ret_buf = (void *)pSMB;
3285 pSMB->Reserved = 0;
3286 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3287 pSMB->TotalDataCount = 0;
3288 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3289 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3290 pSMB->ParameterCount = pSMB->TotalParameterCount;
3291 pSMB->DataCount = pSMB->TotalDataCount;
3292 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3293 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3294 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3295 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3296 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3297 pSMB->SubCommand = cpu_to_le16(sub_command);
3298 return 0;
3299}
3300
3301static int
3302validate_ntransact(char *buf, char **ppparm, char **ppdata,
3303 __u32 *pparmlen, __u32 *pdatalen)
3304{
3305 char *end_of_smb;
3306 __u32 data_count, data_offset, parm_count, parm_offset;
3307 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003308 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003309
3310 *pdatalen = 0;
3311 *pparmlen = 0;
3312
3313 if (buf == NULL)
3314 return -EINVAL;
3315
3316 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3317
Jeff Layton820a8032011-05-04 08:05:26 -04003318 bcc = get_bcc(&pSMBr->hdr);
3319 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003320 (char *)&pSMBr->ByteCount;
3321
3322 data_offset = le32_to_cpu(pSMBr->DataOffset);
3323 data_count = le32_to_cpu(pSMBr->DataCount);
3324 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3325 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3326
3327 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3328 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3329
3330 /* should we also check that parm and data areas do not overlap? */
3331 if (*ppparm > end_of_smb) {
3332 cFYI(1, "parms start after end of smb");
3333 return -EINVAL;
3334 } else if (parm_count + *ppparm > end_of_smb) {
3335 cFYI(1, "parm end after end of smb");
3336 return -EINVAL;
3337 } else if (*ppdata > end_of_smb) {
3338 cFYI(1, "data starts after end of smb");
3339 return -EINVAL;
3340 } else if (data_count + *ppdata > end_of_smb) {
3341 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3342 *ppdata, data_count, (data_count + *ppdata),
3343 end_of_smb, pSMBr);
3344 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003345 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003346 cFYI(1, "parm count and data count larger than SMB");
3347 return -EINVAL;
3348 }
3349 *pdatalen = data_count;
3350 *pparmlen = parm_count;
3351 return 0;
3352}
3353
Steve French0a4b92c2006-01-12 15:44:21 -08003354/* Get Security Descriptor (by handle) from remote server for a file or dir */
3355int
3356CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003357 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003358{
3359 int rc = 0;
3360 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003361 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003362 struct kvec iov[1];
3363
Joe Perchesb6b38f72010-04-21 03:50:45 +00003364 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003365
Steve French630f3f0c2007-10-25 21:17:17 +00003366 *pbuflen = 0;
3367 *acl_inf = NULL;
3368
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003369 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003370 8 /* parm len */, tcon, (void **) &pSMB);
3371 if (rc)
3372 return rc;
3373
3374 pSMB->MaxParameterCount = cpu_to_le32(4);
3375 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3376 pSMB->MaxSetupCount = 0;
3377 pSMB->Fid = fid; /* file handle always le */
3378 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3379 CIFS_ACL_DACL);
3380 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003381 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003382 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003383 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003384
Steve Frencha761ac52007-10-18 21:45:27 +00003385 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003386 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003387 cifs_stats_inc(&tcon->num_acl_get);
3388 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003389 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003390 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003391 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003392 __u32 parm_len;
3393 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003394 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003395 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003396
3397/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003398 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003399 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003400 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003401 goto qsec_out;
3402 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3403
Joe Perchesb6b38f72010-04-21 03:50:45 +00003404 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003405
3406 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3407 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003408 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003409 goto qsec_out;
3410 }
3411
3412/* BB check that data area is minimum length and as big as acl_len */
3413
Steve Frenchaf6f4612007-10-16 18:40:37 +00003414 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003415 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003416 cERROR(1, "acl length %d does not match %d",
3417 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003418 if (*pbuflen > acl_len)
3419 *pbuflen = acl_len;
3420 }
Steve French0a4b92c2006-01-12 15:44:21 -08003421
Steve French630f3f0c2007-10-25 21:17:17 +00003422 /* check if buffer is big enough for the acl
3423 header followed by the smallest SID */
3424 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3425 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003426 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003427 rc = -EINVAL;
3428 *pbuflen = 0;
3429 } else {
3430 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3431 if (*acl_inf == NULL) {
3432 *pbuflen = 0;
3433 rc = -ENOMEM;
3434 }
3435 memcpy(*acl_inf, pdata, *pbuflen);
3436 }
Steve French0a4b92c2006-01-12 15:44:21 -08003437 }
3438qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003439 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003440 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003441 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003442 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003443/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003444 return rc;
3445}
Steve French97837582007-12-31 07:47:21 +00003446
3447int
3448CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3449 struct cifs_ntsd *pntsd, __u32 acllen)
3450{
3451 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3452 int rc = 0;
3453 int bytes_returned = 0;
3454 SET_SEC_DESC_REQ *pSMB = NULL;
3455 NTRANSACT_RSP *pSMBr = NULL;
3456
3457setCifsAclRetry:
3458 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3459 (void **) &pSMBr);
3460 if (rc)
3461 return (rc);
3462
3463 pSMB->MaxSetupCount = 0;
3464 pSMB->Reserved = 0;
3465
3466 param_count = 8;
3467 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3468 data_count = acllen;
3469 data_offset = param_offset + param_count;
3470 byte_count = 3 /* pad */ + param_count;
3471
3472 pSMB->DataCount = cpu_to_le32(data_count);
3473 pSMB->TotalDataCount = pSMB->DataCount;
3474 pSMB->MaxParameterCount = cpu_to_le32(4);
3475 pSMB->MaxDataCount = cpu_to_le32(16384);
3476 pSMB->ParameterCount = cpu_to_le32(param_count);
3477 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3478 pSMB->TotalParameterCount = pSMB->ParameterCount;
3479 pSMB->DataOffset = cpu_to_le32(data_offset);
3480 pSMB->SetupCount = 0;
3481 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3482 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3483
3484 pSMB->Fid = fid; /* file handle always le */
3485 pSMB->Reserved2 = 0;
3486 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3487
3488 if (pntsd && acllen) {
3489 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3490 (char *) pntsd,
3491 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003492 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003493 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003494 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003495
3496 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3497 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3498
Joe Perchesb6b38f72010-04-21 03:50:45 +00003499 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003500 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003501 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003502 cifs_buf_release(pSMB);
3503
3504 if (rc == -EAGAIN)
3505 goto setCifsAclRetry;
3506
3507 return (rc);
3508}
3509
Jeff Layton79df1ba2010-12-06 12:52:08 -05003510#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003511
Steve French6b8edfe2005-08-23 20:26:03 -07003512/* Legacy Query Path Information call for lookup to old servers such
3513 as Win9x/WinME */
3514int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003515 const unsigned char *searchName,
3516 FILE_ALL_INFO *pFinfo,
3517 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003518{
Steve Frenchad7a2922008-02-07 23:25:02 +00003519 QUERY_INFORMATION_REQ *pSMB;
3520 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003521 int rc = 0;
3522 int bytes_returned;
3523 int name_len;
3524
Joe Perchesb6b38f72010-04-21 03:50:45 +00003525 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003526QInfRetry:
3527 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003528 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003529 if (rc)
3530 return rc;
3531
3532 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3533 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003534 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3535 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003536 name_len++; /* trailing null */
3537 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003538 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003539 name_len = strnlen(searchName, PATH_MAX);
3540 name_len++; /* trailing null */
3541 strncpy(pSMB->FileName, searchName, name_len);
3542 }
3543 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003544 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003545 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003546 pSMB->ByteCount = cpu_to_le16(name_len);
3547
3548 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003549 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003550 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003551 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003552 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003553 struct timespec ts;
3554 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003555
3556 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003557 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003558 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003559 ts.tv_nsec = 0;
3560 ts.tv_sec = time;
3561 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003562 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003563 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3564 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003565 pFinfo->AllocationSize =
3566 cpu_to_le64(le32_to_cpu(pSMBr->size));
3567 pFinfo->EndOfFile = pFinfo->AllocationSize;
3568 pFinfo->Attributes =
3569 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003570 } else
3571 rc = -EIO; /* bad buffer passed in */
3572
3573 cifs_buf_release(pSMB);
3574
3575 if (rc == -EAGAIN)
3576 goto QInfRetry;
3577
3578 return rc;
3579}
3580
Jeff Laytonbcd53572010-02-12 07:44:16 -05003581int
3582CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3583 u16 netfid, FILE_ALL_INFO *pFindData)
3584{
3585 struct smb_t2_qfi_req *pSMB = NULL;
3586 struct smb_t2_qfi_rsp *pSMBr = NULL;
3587 int rc = 0;
3588 int bytes_returned;
3589 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003590
Jeff Laytonbcd53572010-02-12 07:44:16 -05003591QFileInfoRetry:
3592 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3593 (void **) &pSMBr);
3594 if (rc)
3595 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003596
Jeff Laytonbcd53572010-02-12 07:44:16 -05003597 params = 2 /* level */ + 2 /* fid */;
3598 pSMB->t2.TotalDataCount = 0;
3599 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3600 /* BB find exact max data count below from sess structure BB */
3601 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3602 pSMB->t2.MaxSetupCount = 0;
3603 pSMB->t2.Reserved = 0;
3604 pSMB->t2.Flags = 0;
3605 pSMB->t2.Timeout = 0;
3606 pSMB->t2.Reserved2 = 0;
3607 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3608 Fid) - 4);
3609 pSMB->t2.DataCount = 0;
3610 pSMB->t2.DataOffset = 0;
3611 pSMB->t2.SetupCount = 1;
3612 pSMB->t2.Reserved3 = 0;
3613 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3614 byte_count = params + 1 /* pad */ ;
3615 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3616 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3617 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3618 pSMB->Pad = 0;
3619 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003620 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003621
3622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3623 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3624 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003625 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003626 } else { /* decode response */
3627 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3628
3629 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3630 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003631 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003632 rc = -EIO; /* bad smb */
3633 else if (pFindData) {
3634 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3635 memcpy((char *) pFindData,
3636 (char *) &pSMBr->hdr.Protocol +
3637 data_offset, sizeof(FILE_ALL_INFO));
3638 } else
3639 rc = -ENOMEM;
3640 }
3641 cifs_buf_release(pSMB);
3642 if (rc == -EAGAIN)
3643 goto QFileInfoRetry;
3644
3645 return rc;
3646}
Steve French6b8edfe2005-08-23 20:26:03 -07003647
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648int
3649CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3650 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003651 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003652 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003653 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003654{
3655/* level 263 SMB_QUERY_FILE_ALL_INFO */
3656 TRANSACTION2_QPI_REQ *pSMB = NULL;
3657 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3658 int rc = 0;
3659 int bytes_returned;
3660 int name_len;
3661 __u16 params, byte_count;
3662
Joe Perchesb6b38f72010-04-21 03:50:45 +00003663/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664QPathInfoRetry:
3665 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3666 (void **) &pSMBr);
3667 if (rc)
3668 return rc;
3669
3670 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3671 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003672 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003673 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 name_len++; /* trailing null */
3675 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003676 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 name_len = strnlen(searchName, PATH_MAX);
3678 name_len++; /* trailing null */
3679 strncpy(pSMB->FileName, searchName, name_len);
3680 }
3681
Steve French50c2f752007-07-13 00:33:32 +00003682 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 pSMB->TotalDataCount = 0;
3684 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003685 /* BB find exact max SMB PDU from sess structure BB */
3686 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 pSMB->MaxSetupCount = 0;
3688 pSMB->Reserved = 0;
3689 pSMB->Flags = 0;
3690 pSMB->Timeout = 0;
3691 pSMB->Reserved2 = 0;
3692 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003693 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 pSMB->DataCount = 0;
3695 pSMB->DataOffset = 0;
3696 pSMB->SetupCount = 1;
3697 pSMB->Reserved3 = 0;
3698 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3699 byte_count = params + 1 /* pad */ ;
3700 pSMB->TotalParameterCount = cpu_to_le16(params);
3701 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003702 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003703 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3704 else
3705 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003707 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 pSMB->ByteCount = cpu_to_le16(byte_count);
3709
3710 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3711 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3712 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003713 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714 } else { /* decode response */
3715 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3716
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003717 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3718 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003719 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003721 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003722 rc = -EIO; /* 24 or 26 expected but we do not read
3723 last field */
3724 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003725 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003727
3728 /* On legacy responses we do not read the last field,
3729 EAsize, fortunately since it varies by subdialect and
3730 also note it differs on Set vs. Get, ie two bytes or 4
3731 bytes depending but we don't care here */
3732 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003733 size = sizeof(FILE_INFO_STANDARD);
3734 else
3735 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 memcpy((char *) pFindData,
3737 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003738 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 } else
3740 rc = -ENOMEM;
3741 }
3742 cifs_buf_release(pSMB);
3743 if (rc == -EAGAIN)
3744 goto QPathInfoRetry;
3745
3746 return rc;
3747}
3748
3749int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003750CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3751 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3752{
3753 struct smb_t2_qfi_req *pSMB = NULL;
3754 struct smb_t2_qfi_rsp *pSMBr = NULL;
3755 int rc = 0;
3756 int bytes_returned;
3757 __u16 params, byte_count;
3758
3759UnixQFileInfoRetry:
3760 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3761 (void **) &pSMBr);
3762 if (rc)
3763 return rc;
3764
3765 params = 2 /* level */ + 2 /* fid */;
3766 pSMB->t2.TotalDataCount = 0;
3767 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3768 /* BB find exact max data count below from sess structure BB */
3769 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3770 pSMB->t2.MaxSetupCount = 0;
3771 pSMB->t2.Reserved = 0;
3772 pSMB->t2.Flags = 0;
3773 pSMB->t2.Timeout = 0;
3774 pSMB->t2.Reserved2 = 0;
3775 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3776 Fid) - 4);
3777 pSMB->t2.DataCount = 0;
3778 pSMB->t2.DataOffset = 0;
3779 pSMB->t2.SetupCount = 1;
3780 pSMB->t2.Reserved3 = 0;
3781 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3782 byte_count = params + 1 /* pad */ ;
3783 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3784 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3785 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3786 pSMB->Pad = 0;
3787 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003788 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003789
3790 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3791 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3792 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003793 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003794 } else { /* decode response */
3795 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3796
Jeff Layton820a8032011-05-04 08:05:26 -04003797 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003798 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003799 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003800 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003801 rc = -EIO; /* bad smb */
3802 } else {
3803 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3804 memcpy((char *) pFindData,
3805 (char *) &pSMBr->hdr.Protocol +
3806 data_offset,
3807 sizeof(FILE_UNIX_BASIC_INFO));
3808 }
3809 }
3810
3811 cifs_buf_release(pSMB);
3812 if (rc == -EAGAIN)
3813 goto UnixQFileInfoRetry;
3814
3815 return rc;
3816}
3817
3818int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3820 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003821 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003822 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823{
3824/* SMB_QUERY_FILE_UNIX_BASIC */
3825 TRANSACTION2_QPI_REQ *pSMB = NULL;
3826 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3827 int rc = 0;
3828 int bytes_returned = 0;
3829 int name_len;
3830 __u16 params, byte_count;
3831
Joe Perchesb6b38f72010-04-21 03:50:45 +00003832 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833UnixQPathInfoRetry:
3834 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3835 (void **) &pSMBr);
3836 if (rc)
3837 return rc;
3838
3839 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3840 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003841 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003842 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 name_len++; /* trailing null */
3844 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003845 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 name_len = strnlen(searchName, PATH_MAX);
3847 name_len++; /* trailing null */
3848 strncpy(pSMB->FileName, searchName, name_len);
3849 }
3850
Steve French50c2f752007-07-13 00:33:32 +00003851 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 pSMB->TotalDataCount = 0;
3853 pSMB->MaxParameterCount = cpu_to_le16(2);
3854 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003855 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 pSMB->MaxSetupCount = 0;
3857 pSMB->Reserved = 0;
3858 pSMB->Flags = 0;
3859 pSMB->Timeout = 0;
3860 pSMB->Reserved2 = 0;
3861 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003862 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863 pSMB->DataCount = 0;
3864 pSMB->DataOffset = 0;
3865 pSMB->SetupCount = 1;
3866 pSMB->Reserved3 = 0;
3867 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3868 byte_count = params + 1 /* pad */ ;
3869 pSMB->TotalParameterCount = cpu_to_le16(params);
3870 pSMB->ParameterCount = pSMB->TotalParameterCount;
3871 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3872 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003873 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874 pSMB->ByteCount = cpu_to_le16(byte_count);
3875
3876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3878 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003879 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 } else { /* decode response */
3881 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3882
Jeff Layton820a8032011-05-04 08:05:26 -04003883 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003884 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003885 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003886 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887 rc = -EIO; /* bad smb */
3888 } else {
3889 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3890 memcpy((char *) pFindData,
3891 (char *) &pSMBr->hdr.Protocol +
3892 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003893 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 }
3895 }
3896 cifs_buf_release(pSMB);
3897 if (rc == -EAGAIN)
3898 goto UnixQPathInfoRetry;
3899
3900 return rc;
3901}
3902
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903/* xid, tcon, searchName and codepage are input parms, rest are returned */
3904int
3905CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003906 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003908 __u16 *pnetfid,
3909 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910{
3911/* level 257 SMB_ */
3912 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3913 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003914 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915 int rc = 0;
3916 int bytes_returned = 0;
3917 int name_len;
3918 __u16 params, byte_count;
3919
Joe Perchesb6b38f72010-04-21 03:50:45 +00003920 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003921
3922findFirstRetry:
3923 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3924 (void **) &pSMBr);
3925 if (rc)
3926 return rc;
3927
3928 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3929 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003930 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003931 PATH_MAX, nls_codepage, remap);
3932 /* We can not add the asterik earlier in case
3933 it got remapped to 0xF03A as if it were part of the
3934 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003936 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003937 pSMB->FileName[name_len+1] = 0;
3938 pSMB->FileName[name_len+2] = '*';
3939 pSMB->FileName[name_len+3] = 0;
3940 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3942 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003943 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 } else { /* BB add check for overrun of SMB buf BB */
3945 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003947 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 free buffer exit; BB */
3949 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003950 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003951 pSMB->FileName[name_len+1] = '*';
3952 pSMB->FileName[name_len+2] = 0;
3953 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 }
3955
3956 params = 12 + name_len /* includes null */ ;
3957 pSMB->TotalDataCount = 0; /* no EAs */
3958 pSMB->MaxParameterCount = cpu_to_le16(10);
3959 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3960 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3961 pSMB->MaxSetupCount = 0;
3962 pSMB->Reserved = 0;
3963 pSMB->Flags = 0;
3964 pSMB->Timeout = 0;
3965 pSMB->Reserved2 = 0;
3966 byte_count = params + 1 /* pad */ ;
3967 pSMB->TotalParameterCount = cpu_to_le16(params);
3968 pSMB->ParameterCount = pSMB->TotalParameterCount;
3969 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003970 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3971 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 pSMB->DataCount = 0;
3973 pSMB->DataOffset = 0;
3974 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3975 pSMB->Reserved3 = 0;
3976 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3977 pSMB->SearchAttributes =
3978 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3979 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003980 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3981 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982 CIFS_SEARCH_RETURN_RESUME);
3983 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3984
3985 /* BB what should we set StorageType to? Does it matter? BB */
3986 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003987 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 pSMB->ByteCount = cpu_to_le16(byte_count);
3989
3990 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3991 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003992 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993
Steve French88274812006-03-09 22:21:45 +00003994 if (rc) {/* BB add logic to retry regular search if Unix search
3995 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003997 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003998
Steve French88274812006-03-09 22:21:45 +00003999 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000
4001 /* BB eventually could optimize out free and realloc of buf */
4002 /* for this case */
4003 if (rc == -EAGAIN)
4004 goto findFirstRetry;
4005 } else { /* decode response */
4006 /* BB remember to free buffer if error BB */
4007 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004008 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004009 unsigned int lnoff;
4010
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004012 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 else
Steve French4b18f2a2008-04-29 00:06:05 +00004014 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015
4016 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004017 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004018 psrch_inf->srch_entries_start =
4019 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4022 le16_to_cpu(pSMBr->t2.ParameterOffset));
4023
Steve French790fe572007-07-07 19:25:05 +00004024 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004025 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 else
Steve French4b18f2a2008-04-29 00:06:05 +00004027 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028
Steve French50c2f752007-07-13 00:33:32 +00004029 psrch_inf->entries_in_buffer =
4030 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004031 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004033 lnoff = le16_to_cpu(parms->LastNameOffset);
4034 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4035 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004036 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004037 psrch_inf->last_entry = NULL;
4038 return rc;
4039 }
4040
Steve French0752f152008-10-07 20:03:33 +00004041 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004042 lnoff;
4043
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 *pnetfid = parms->SearchHandle;
4045 } else {
4046 cifs_buf_release(pSMB);
4047 }
4048 }
4049
4050 return rc;
4051}
4052
4053int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004054 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055{
4056 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4057 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004058 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 char *response_data;
4060 int rc = 0;
4061 int bytes_returned, name_len;
4062 __u16 params, byte_count;
4063
Joe Perchesb6b38f72010-04-21 03:50:45 +00004064 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004065
Steve French4b18f2a2008-04-29 00:06:05 +00004066 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 return -ENOENT;
4068
4069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4070 (void **) &pSMBr);
4071 if (rc)
4072 return rc;
4073
Steve French50c2f752007-07-13 00:33:32 +00004074 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 byte_count = 0;
4076 pSMB->TotalDataCount = 0; /* no EAs */
4077 pSMB->MaxParameterCount = cpu_to_le16(8);
4078 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00004079 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
4080 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 pSMB->MaxSetupCount = 0;
4082 pSMB->Reserved = 0;
4083 pSMB->Flags = 0;
4084 pSMB->Timeout = 0;
4085 pSMB->Reserved2 = 0;
4086 pSMB->ParameterOffset = cpu_to_le16(
4087 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4088 pSMB->DataCount = 0;
4089 pSMB->DataOffset = 0;
4090 pSMB->SetupCount = 1;
4091 pSMB->Reserved3 = 0;
4092 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4093 pSMB->SearchHandle = searchHandle; /* always kept as le */
4094 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004095 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4097 pSMB->ResumeKey = psrch_inf->resume_key;
4098 pSMB->SearchFlags =
4099 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4100
4101 name_len = psrch_inf->resume_name_len;
4102 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004103 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4105 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004106 /* 14 byte parm len above enough for 2 byte null terminator */
4107 pSMB->ResumeFileName[name_len] = 0;
4108 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 } else {
4110 rc = -EINVAL;
4111 goto FNext2_err_exit;
4112 }
4113 byte_count = params + 1 /* pad */ ;
4114 pSMB->TotalParameterCount = cpu_to_le16(params);
4115 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004116 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004118
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004121 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 if (rc) {
4123 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004124 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004125 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004126 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004128 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 } else { /* decode response */
4130 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004131
Steve French790fe572007-07-07 19:25:05 +00004132 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004133 unsigned int lnoff;
4134
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 /* BB fixme add lock for file (srch_info) struct here */
4136 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004137 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 else
Steve French4b18f2a2008-04-29 00:06:05 +00004139 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 response_data = (char *) &pSMBr->hdr.Protocol +
4141 le16_to_cpu(pSMBr->t2.ParameterOffset);
4142 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4143 response_data = (char *)&pSMBr->hdr.Protocol +
4144 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004145 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004146 cifs_small_buf_release(
4147 psrch_inf->ntwrk_buf_start);
4148 else
4149 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 psrch_inf->srch_entries_start = response_data;
4151 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004152 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004153 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004154 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 else
Steve French4b18f2a2008-04-29 00:06:05 +00004156 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004157 psrch_inf->entries_in_buffer =
4158 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 psrch_inf->index_of_last_entry +=
4160 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004161 lnoff = le16_to_cpu(parms->LastNameOffset);
4162 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4163 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004164 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004165 psrch_inf->last_entry = NULL;
4166 return rc;
4167 } else
4168 psrch_inf->last_entry =
4169 psrch_inf->srch_entries_start + lnoff;
4170
Joe Perchesb6b38f72010-04-21 03:50:45 +00004171/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4172 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173
4174 /* BB fixme add unlock here */
4175 }
4176
4177 }
4178
4179 /* BB On error, should we leave previous search buf (and count and
4180 last entry fields) intact or free the previous one? */
4181
4182 /* Note: On -EAGAIN error only caller can retry on handle based calls
4183 since file handle passed in no longer valid */
4184FNext2_err_exit:
4185 if (rc != 0)
4186 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 return rc;
4188}
4189
4190int
Steve French50c2f752007-07-13 00:33:32 +00004191CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
4192 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193{
4194 int rc = 0;
4195 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196
Joe Perchesb6b38f72010-04-21 03:50:45 +00004197 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4199
4200 /* no sense returning error if session restarted
4201 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004202 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203 return 0;
4204 if (rc)
4205 return rc;
4206
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207 pSMB->FileID = searchHandle;
4208 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004209 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004210 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004211 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004212
Steve Frencha4544342005-08-24 13:59:35 -07004213 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
4215 /* Since session is dead, search handle closed on server already */
4216 if (rc == -EAGAIN)
4217 rc = 0;
4218
4219 return rc;
4220}
4221
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222int
4223CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004224 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004225 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004226 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227{
4228 int rc = 0;
4229 TRANSACTION2_QPI_REQ *pSMB = NULL;
4230 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4231 int name_len, bytes_returned;
4232 __u16 params, byte_count;
4233
Joe Perchesb6b38f72010-04-21 03:50:45 +00004234 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004235 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004236 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
4238GetInodeNumberRetry:
4239 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004240 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 if (rc)
4242 return rc;
4243
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4245 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004246 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004247 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 name_len++; /* trailing null */
4249 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004250 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 name_len = strnlen(searchName, PATH_MAX);
4252 name_len++; /* trailing null */
4253 strncpy(pSMB->FileName, searchName, name_len);
4254 }
4255
4256 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4257 pSMB->TotalDataCount = 0;
4258 pSMB->MaxParameterCount = cpu_to_le16(2);
4259 /* BB find exact max data count below from sess structure BB */
4260 pSMB->MaxDataCount = cpu_to_le16(4000);
4261 pSMB->MaxSetupCount = 0;
4262 pSMB->Reserved = 0;
4263 pSMB->Flags = 0;
4264 pSMB->Timeout = 0;
4265 pSMB->Reserved2 = 0;
4266 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004267 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 pSMB->DataCount = 0;
4269 pSMB->DataOffset = 0;
4270 pSMB->SetupCount = 1;
4271 pSMB->Reserved3 = 0;
4272 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4273 byte_count = params + 1 /* pad */ ;
4274 pSMB->TotalParameterCount = cpu_to_le16(params);
4275 pSMB->ParameterCount = pSMB->TotalParameterCount;
4276 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4277 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004278 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 pSMB->ByteCount = cpu_to_le16(byte_count);
4280
4281 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4282 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4283 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004284 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 } else {
4286 /* decode response */
4287 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004289 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 /* If rc should we check for EOPNOSUPP and
4291 disable the srvino flag? or in caller? */
4292 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004293 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4295 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004296 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004298 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004299 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300 rc = -EIO;
4301 goto GetInodeNumOut;
4302 }
4303 pfinfo = (struct file_internal_info *)
4304 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004305 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 }
4307 }
4308GetInodeNumOut:
4309 cifs_buf_release(pSMB);
4310 if (rc == -EAGAIN)
4311 goto GetInodeNumberRetry;
4312 return rc;
4313}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314
Igor Mammedovfec45852008-05-16 13:06:30 +04004315/* parses DFS refferal V3 structure
4316 * caller is responsible for freeing target_nodes
4317 * returns:
4318 * on success - 0
4319 * on failure - errno
4320 */
4321static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004322parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004323 unsigned int *num_of_nodes,
4324 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004325 const struct nls_table *nls_codepage, int remap,
4326 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004327{
4328 int i, rc = 0;
4329 char *data_end;
4330 bool is_unicode;
4331 struct dfs_referral_level_3 *ref;
4332
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004333 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4334 is_unicode = true;
4335 else
4336 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004337 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4338
4339 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004340 cERROR(1, "num_referrals: must be at least > 0,"
4341 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004342 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004343 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004344 }
4345
4346 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004347 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004348 cERROR(1, "Referrals of V%d version are not supported,"
4349 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004350 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004351 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004352 }
4353
4354 /* get the upper boundary of the resp buffer */
4355 data_end = (char *)(&(pSMBr->PathConsumed)) +
4356 le16_to_cpu(pSMBr->t2.DataCount);
4357
Steve Frenchf19159d2010-04-21 04:12:10 +00004358 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004359 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004360 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004361
4362 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4363 *num_of_nodes, GFP_KERNEL);
4364 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004365 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004366 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004367 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004368 }
4369
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004370 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004371 for (i = 0; i < *num_of_nodes; i++) {
4372 char *temp;
4373 int max_len;
4374 struct dfs_info3_param *node = (*target_nodes)+i;
4375
Steve French0e0d2cf2009-05-01 05:27:32 +00004376 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004377 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004378 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4379 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004380 if (tmp == NULL) {
4381 rc = -ENOMEM;
4382 goto parse_DFS_referrals_exit;
4383 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004384 cifsConvertToUCS((__le16 *) tmp, searchName,
4385 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004386 node->path_consumed = cifs_ucs2_bytes(tmp,
4387 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004388 nls_codepage);
4389 kfree(tmp);
4390 } else
4391 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4392
Igor Mammedovfec45852008-05-16 13:06:30 +04004393 node->server_type = le16_to_cpu(ref->ServerType);
4394 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4395
4396 /* copy DfsPath */
4397 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4398 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004399 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4400 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004401 if (!node->path_name) {
4402 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004403 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004404 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004405
4406 /* copy link target UNC */
4407 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4408 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004409 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4410 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004411 if (!node->node_name)
4412 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004413 }
4414
Steve Frencha1fe78f2008-05-16 18:48:38 +00004415parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004416 if (rc) {
4417 free_dfs_info_array(*target_nodes, *num_of_nodes);
4418 *target_nodes = NULL;
4419 *num_of_nodes = 0;
4420 }
4421 return rc;
4422}
4423
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424int
4425CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4426 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004427 struct dfs_info3_param **target_nodes,
4428 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004429 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430{
4431/* TRANS2_GET_DFS_REFERRAL */
4432 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4433 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 int rc = 0;
4435 int bytes_returned;
4436 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004438 *num_of_nodes = 0;
4439 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440
Joe Perchesb6b38f72010-04-21 03:50:45 +00004441 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 if (ses == NULL)
4443 return -ENODEV;
4444getDFSRetry:
4445 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4446 (void **) &pSMBr);
4447 if (rc)
4448 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004449
4450 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004451 but should never be null here anyway */
4452 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 pSMB->hdr.Tid = ses->ipc_tid;
4454 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004455 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004457 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
4460 if (ses->capabilities & CAP_UNICODE) {
4461 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4462 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004463 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004464 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465 name_len++; /* trailing null */
4466 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004467 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 name_len = strnlen(searchName, PATH_MAX);
4469 name_len++; /* trailing null */
4470 strncpy(pSMB->RequestFileName, searchName, name_len);
4471 }
4472
Steve French790fe572007-07-07 19:25:05 +00004473 if (ses->server) {
4474 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004475 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4476 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4477 }
4478
Steve French50c2f752007-07-13 00:33:32 +00004479 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004480
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 params = 2 /* level */ + name_len /*includes null */ ;
4482 pSMB->TotalDataCount = 0;
4483 pSMB->DataCount = 0;
4484 pSMB->DataOffset = 0;
4485 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004486 /* BB find exact max SMB PDU from sess structure BB */
4487 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 pSMB->MaxSetupCount = 0;
4489 pSMB->Reserved = 0;
4490 pSMB->Flags = 0;
4491 pSMB->Timeout = 0;
4492 pSMB->Reserved2 = 0;
4493 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004494 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 pSMB->SetupCount = 1;
4496 pSMB->Reserved3 = 0;
4497 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4498 byte_count = params + 3 /* pad */ ;
4499 pSMB->ParameterCount = cpu_to_le16(params);
4500 pSMB->TotalParameterCount = pSMB->ParameterCount;
4501 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004502 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 pSMB->ByteCount = cpu_to_le16(byte_count);
4504
4505 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4506 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4507 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004508 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004509 goto GetDFSRefExit;
4510 }
4511 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004513 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004514 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004515 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004516 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004518
Joe Perchesb6b38f72010-04-21 03:50:45 +00004519 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004520 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004521 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004522
4523 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004524 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004525 target_nodes, nls_codepage, remap,
4526 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004527
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004529 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530
4531 if (rc == -EAGAIN)
4532 goto getDFSRetry;
4533
4534 return rc;
4535}
4536
Steve French20962432005-09-21 22:05:57 -07004537/* Query File System Info such as free space to old servers such as Win 9x */
4538int
4539SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4540{
4541/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4542 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4543 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4544 FILE_SYSTEM_ALLOC_INFO *response_data;
4545 int rc = 0;
4546 int bytes_returned = 0;
4547 __u16 params, byte_count;
4548
Joe Perchesb6b38f72010-04-21 03:50:45 +00004549 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004550oldQFSInfoRetry:
4551 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4552 (void **) &pSMBr);
4553 if (rc)
4554 return rc;
Steve French20962432005-09-21 22:05:57 -07004555
4556 params = 2; /* level */
4557 pSMB->TotalDataCount = 0;
4558 pSMB->MaxParameterCount = cpu_to_le16(2);
4559 pSMB->MaxDataCount = cpu_to_le16(1000);
4560 pSMB->MaxSetupCount = 0;
4561 pSMB->Reserved = 0;
4562 pSMB->Flags = 0;
4563 pSMB->Timeout = 0;
4564 pSMB->Reserved2 = 0;
4565 byte_count = params + 1 /* pad */ ;
4566 pSMB->TotalParameterCount = cpu_to_le16(params);
4567 pSMB->ParameterCount = pSMB->TotalParameterCount;
4568 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4569 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4570 pSMB->DataCount = 0;
4571 pSMB->DataOffset = 0;
4572 pSMB->SetupCount = 1;
4573 pSMB->Reserved3 = 0;
4574 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4575 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004576 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004577 pSMB->ByteCount = cpu_to_le16(byte_count);
4578
4579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4580 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4581 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004582 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004583 } else { /* decode response */
4584 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4585
Jeff Layton820a8032011-05-04 08:05:26 -04004586 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004587 rc = -EIO; /* bad smb */
4588 else {
4589 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004590 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004591 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004592
Steve French50c2f752007-07-13 00:33:32 +00004593 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004594 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4595 FSData->f_bsize =
4596 le16_to_cpu(response_data->BytesPerSector) *
4597 le32_to_cpu(response_data->
4598 SectorsPerAllocationUnit);
4599 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004600 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004601 FSData->f_bfree = FSData->f_bavail =
4602 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004603 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4604 (unsigned long long)FSData->f_blocks,
4605 (unsigned long long)FSData->f_bfree,
4606 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004607 }
4608 }
4609 cifs_buf_release(pSMB);
4610
4611 if (rc == -EAGAIN)
4612 goto oldQFSInfoRetry;
4613
4614 return rc;
4615}
4616
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617int
Steve French737b7582005-04-28 22:41:06 -07004618CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619{
4620/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4621 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4622 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4623 FILE_SYSTEM_INFO *response_data;
4624 int rc = 0;
4625 int bytes_returned = 0;
4626 __u16 params, byte_count;
4627
Joe Perchesb6b38f72010-04-21 03:50:45 +00004628 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629QFSInfoRetry:
4630 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4631 (void **) &pSMBr);
4632 if (rc)
4633 return rc;
4634
4635 params = 2; /* level */
4636 pSMB->TotalDataCount = 0;
4637 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004638 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 pSMB->MaxSetupCount = 0;
4640 pSMB->Reserved = 0;
4641 pSMB->Flags = 0;
4642 pSMB->Timeout = 0;
4643 pSMB->Reserved2 = 0;
4644 byte_count = params + 1 /* pad */ ;
4645 pSMB->TotalParameterCount = cpu_to_le16(params);
4646 pSMB->ParameterCount = pSMB->TotalParameterCount;
4647 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004648 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 pSMB->DataCount = 0;
4650 pSMB->DataOffset = 0;
4651 pSMB->SetupCount = 1;
4652 pSMB->Reserved3 = 0;
4653 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4654 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004655 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 pSMB->ByteCount = cpu_to_le16(byte_count);
4657
4658 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4659 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4660 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004661 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004663 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664
Jeff Layton820a8032011-05-04 08:05:26 -04004665 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 rc = -EIO; /* bad smb */
4667 else {
4668 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669
4670 response_data =
4671 (FILE_SYSTEM_INFO
4672 *) (((char *) &pSMBr->hdr.Protocol) +
4673 data_offset);
4674 FSData->f_bsize =
4675 le32_to_cpu(response_data->BytesPerSector) *
4676 le32_to_cpu(response_data->
4677 SectorsPerAllocationUnit);
4678 FSData->f_blocks =
4679 le64_to_cpu(response_data->TotalAllocationUnits);
4680 FSData->f_bfree = FSData->f_bavail =
4681 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004682 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4683 (unsigned long long)FSData->f_blocks,
4684 (unsigned long long)FSData->f_bfree,
4685 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686 }
4687 }
4688 cifs_buf_release(pSMB);
4689
4690 if (rc == -EAGAIN)
4691 goto QFSInfoRetry;
4692
4693 return rc;
4694}
4695
4696int
Steve French737b7582005-04-28 22:41:06 -07004697CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698{
4699/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4700 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4701 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4702 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4703 int rc = 0;
4704 int bytes_returned = 0;
4705 __u16 params, byte_count;
4706
Joe Perchesb6b38f72010-04-21 03:50:45 +00004707 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708QFSAttributeRetry:
4709 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4710 (void **) &pSMBr);
4711 if (rc)
4712 return rc;
4713
4714 params = 2; /* level */
4715 pSMB->TotalDataCount = 0;
4716 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004717 /* BB find exact max SMB PDU from sess structure BB */
4718 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 pSMB->MaxSetupCount = 0;
4720 pSMB->Reserved = 0;
4721 pSMB->Flags = 0;
4722 pSMB->Timeout = 0;
4723 pSMB->Reserved2 = 0;
4724 byte_count = params + 1 /* pad */ ;
4725 pSMB->TotalParameterCount = cpu_to_le16(params);
4726 pSMB->ParameterCount = pSMB->TotalParameterCount;
4727 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004728 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 pSMB->DataCount = 0;
4730 pSMB->DataOffset = 0;
4731 pSMB->SetupCount = 1;
4732 pSMB->Reserved3 = 0;
4733 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4734 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004735 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004736 pSMB->ByteCount = cpu_to_le16(byte_count);
4737
4738 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4739 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4740 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004741 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 } else { /* decode response */
4743 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4744
Jeff Layton820a8032011-05-04 08:05:26 -04004745 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004746 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747 rc = -EIO; /* bad smb */
4748 } else {
4749 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4750 response_data =
4751 (FILE_SYSTEM_ATTRIBUTE_INFO
4752 *) (((char *) &pSMBr->hdr.Protocol) +
4753 data_offset);
4754 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004755 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 }
4757 }
4758 cifs_buf_release(pSMB);
4759
4760 if (rc == -EAGAIN)
4761 goto QFSAttributeRetry;
4762
4763 return rc;
4764}
4765
4766int
Steve French737b7582005-04-28 22:41:06 -07004767CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
4769/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4770 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4771 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4772 FILE_SYSTEM_DEVICE_INFO *response_data;
4773 int rc = 0;
4774 int bytes_returned = 0;
4775 __u16 params, byte_count;
4776
Joe Perchesb6b38f72010-04-21 03:50:45 +00004777 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778QFSDeviceRetry:
4779 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4780 (void **) &pSMBr);
4781 if (rc)
4782 return rc;
4783
4784 params = 2; /* level */
4785 pSMB->TotalDataCount = 0;
4786 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004787 /* BB find exact max SMB PDU from sess structure BB */
4788 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 pSMB->MaxSetupCount = 0;
4790 pSMB->Reserved = 0;
4791 pSMB->Flags = 0;
4792 pSMB->Timeout = 0;
4793 pSMB->Reserved2 = 0;
4794 byte_count = params + 1 /* pad */ ;
4795 pSMB->TotalParameterCount = cpu_to_le16(params);
4796 pSMB->ParameterCount = pSMB->TotalParameterCount;
4797 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004798 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799
4800 pSMB->DataCount = 0;
4801 pSMB->DataOffset = 0;
4802 pSMB->SetupCount = 1;
4803 pSMB->Reserved3 = 0;
4804 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4805 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004806 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 pSMB->ByteCount = cpu_to_le16(byte_count);
4808
4809 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4811 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004812 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 } else { /* decode response */
4814 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4815
Jeff Layton820a8032011-05-04 08:05:26 -04004816 if (rc || get_bcc(&pSMBr->hdr) <
4817 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 rc = -EIO; /* bad smb */
4819 else {
4820 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4821 response_data =
Steve French737b7582005-04-28 22:41:06 -07004822 (FILE_SYSTEM_DEVICE_INFO *)
4823 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824 data_offset);
4825 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004826 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 }
4828 }
4829 cifs_buf_release(pSMB);
4830
4831 if (rc == -EAGAIN)
4832 goto QFSDeviceRetry;
4833
4834 return rc;
4835}
4836
4837int
Steve French737b7582005-04-28 22:41:06 -07004838CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839{
4840/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4841 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4842 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4843 FILE_SYSTEM_UNIX_INFO *response_data;
4844 int rc = 0;
4845 int bytes_returned = 0;
4846 __u16 params, byte_count;
4847
Joe Perchesb6b38f72010-04-21 03:50:45 +00004848 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004850 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4851 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 if (rc)
4853 return rc;
4854
4855 params = 2; /* level */
4856 pSMB->TotalDataCount = 0;
4857 pSMB->DataCount = 0;
4858 pSMB->DataOffset = 0;
4859 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004860 /* BB find exact max SMB PDU from sess structure BB */
4861 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 pSMB->MaxSetupCount = 0;
4863 pSMB->Reserved = 0;
4864 pSMB->Flags = 0;
4865 pSMB->Timeout = 0;
4866 pSMB->Reserved2 = 0;
4867 byte_count = params + 1 /* pad */ ;
4868 pSMB->ParameterCount = cpu_to_le16(params);
4869 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004870 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4871 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 pSMB->SetupCount = 1;
4873 pSMB->Reserved3 = 0;
4874 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4875 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004876 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004877 pSMB->ByteCount = cpu_to_le16(byte_count);
4878
4879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4881 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004882 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 } else { /* decode response */
4884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4885
Jeff Layton820a8032011-05-04 08:05:26 -04004886 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004887 rc = -EIO; /* bad smb */
4888 } else {
4889 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4890 response_data =
4891 (FILE_SYSTEM_UNIX_INFO
4892 *) (((char *) &pSMBr->hdr.Protocol) +
4893 data_offset);
4894 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004895 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 }
4897 }
4898 cifs_buf_release(pSMB);
4899
4900 if (rc == -EAGAIN)
4901 goto QFSUnixRetry;
4902
4903
4904 return rc;
4905}
4906
Jeremy Allisonac670552005-06-22 17:26:35 -07004907int
Steve French45abc6e2005-06-23 13:42:03 -05004908CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004909{
4910/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4911 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4912 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4913 int rc = 0;
4914 int bytes_returned = 0;
4915 __u16 params, param_offset, offset, byte_count;
4916
Joe Perchesb6b38f72010-04-21 03:50:45 +00004917 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004918SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004919 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004920 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4921 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004922 if (rc)
4923 return rc;
4924
4925 params = 4; /* 2 bytes zero followed by info level. */
4926 pSMB->MaxSetupCount = 0;
4927 pSMB->Reserved = 0;
4928 pSMB->Flags = 0;
4929 pSMB->Timeout = 0;
4930 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004931 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4932 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004933 offset = param_offset + params;
4934
4935 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004936 /* BB find exact max SMB PDU from sess structure BB */
4937 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004938 pSMB->SetupCount = 1;
4939 pSMB->Reserved3 = 0;
4940 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4941 byte_count = 1 /* pad */ + params + 12;
4942
4943 pSMB->DataCount = cpu_to_le16(12);
4944 pSMB->ParameterCount = cpu_to_le16(params);
4945 pSMB->TotalDataCount = pSMB->DataCount;
4946 pSMB->TotalParameterCount = pSMB->ParameterCount;
4947 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4948 pSMB->DataOffset = cpu_to_le16(offset);
4949
4950 /* Params. */
4951 pSMB->FileNum = 0;
4952 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4953
4954 /* Data. */
4955 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4956 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4957 pSMB->ClientUnixCap = cpu_to_le64(cap);
4958
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004959 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004960 pSMB->ByteCount = cpu_to_le16(byte_count);
4961
4962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4964 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004965 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004966 } else { /* decode response */
4967 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004968 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004969 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004970 }
4971 cifs_buf_release(pSMB);
4972
4973 if (rc == -EAGAIN)
4974 goto SETFSUnixRetry;
4975
4976 return rc;
4977}
4978
4979
Linus Torvalds1da177e2005-04-16 15:20:36 -07004980
4981int
4982CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004983 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004984{
4985/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4986 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4987 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4988 FILE_SYSTEM_POSIX_INFO *response_data;
4989 int rc = 0;
4990 int bytes_returned = 0;
4991 __u16 params, byte_count;
4992
Joe Perchesb6b38f72010-04-21 03:50:45 +00004993 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994QFSPosixRetry:
4995 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4996 (void **) &pSMBr);
4997 if (rc)
4998 return rc;
4999
5000 params = 2; /* level */
5001 pSMB->TotalDataCount = 0;
5002 pSMB->DataCount = 0;
5003 pSMB->DataOffset = 0;
5004 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005005 /* BB find exact max SMB PDU from sess structure BB */
5006 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 pSMB->MaxSetupCount = 0;
5008 pSMB->Reserved = 0;
5009 pSMB->Flags = 0;
5010 pSMB->Timeout = 0;
5011 pSMB->Reserved2 = 0;
5012 byte_count = params + 1 /* pad */ ;
5013 pSMB->ParameterCount = cpu_to_le16(params);
5014 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005015 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5016 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 pSMB->SetupCount = 1;
5018 pSMB->Reserved3 = 0;
5019 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5020 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005021 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022 pSMB->ByteCount = cpu_to_le16(byte_count);
5023
5024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5026 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005027 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 } else { /* decode response */
5029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5030
Jeff Layton820a8032011-05-04 08:05:26 -04005031 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005032 rc = -EIO; /* bad smb */
5033 } else {
5034 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5035 response_data =
5036 (FILE_SYSTEM_POSIX_INFO
5037 *) (((char *) &pSMBr->hdr.Protocol) +
5038 data_offset);
5039 FSData->f_bsize =
5040 le32_to_cpu(response_data->BlockSize);
5041 FSData->f_blocks =
5042 le64_to_cpu(response_data->TotalBlocks);
5043 FSData->f_bfree =
5044 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005045 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 FSData->f_bavail = FSData->f_bfree;
5047 } else {
5048 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005049 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 }
Steve French790fe572007-07-07 19:25:05 +00005051 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005053 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005054 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005056 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005057 }
5058 }
5059 cifs_buf_release(pSMB);
5060
5061 if (rc == -EAGAIN)
5062 goto QFSPosixRetry;
5063
5064 return rc;
5065}
5066
5067
Steve French50c2f752007-07-13 00:33:32 +00005068/* We can not use write of zero bytes trick to
5069 set file size due to need for large file support. Also note that
5070 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 routine which is only needed to work around a sharing violation bug
5072 in Samba which this routine can run into */
5073
5074int
5075CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005076 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005077 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078{
5079 struct smb_com_transaction2_spi_req *pSMB = NULL;
5080 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5081 struct file_end_of_file_info *parm_data;
5082 int name_len;
5083 int rc = 0;
5084 int bytes_returned = 0;
5085 __u16 params, byte_count, data_count, param_offset, offset;
5086
Joe Perchesb6b38f72010-04-21 03:50:45 +00005087 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088SetEOFRetry:
5089 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5090 (void **) &pSMBr);
5091 if (rc)
5092 return rc;
5093
5094 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5095 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005096 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005097 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 name_len++; /* trailing null */
5099 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005100 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 name_len = strnlen(fileName, PATH_MAX);
5102 name_len++; /* trailing null */
5103 strncpy(pSMB->FileName, fileName, name_len);
5104 }
5105 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005106 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005108 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005109 pSMB->MaxSetupCount = 0;
5110 pSMB->Reserved = 0;
5111 pSMB->Flags = 0;
5112 pSMB->Timeout = 0;
5113 pSMB->Reserved2 = 0;
5114 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005115 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005117 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005118 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5119 pSMB->InformationLevel =
5120 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5121 else
5122 pSMB->InformationLevel =
5123 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5124 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5126 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005127 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 else
5129 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005130 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 }
5132
5133 parm_data =
5134 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5135 offset);
5136 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5137 pSMB->DataOffset = cpu_to_le16(offset);
5138 pSMB->SetupCount = 1;
5139 pSMB->Reserved3 = 0;
5140 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5141 byte_count = 3 /* pad */ + params + data_count;
5142 pSMB->DataCount = cpu_to_le16(data_count);
5143 pSMB->TotalDataCount = pSMB->DataCount;
5144 pSMB->ParameterCount = cpu_to_le16(params);
5145 pSMB->TotalParameterCount = pSMB->ParameterCount;
5146 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005147 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005148 parm_data->FileSize = cpu_to_le64(size);
5149 pSMB->ByteCount = cpu_to_le16(byte_count);
5150 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5151 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005152 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005153 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154
5155 cifs_buf_release(pSMB);
5156
5157 if (rc == -EAGAIN)
5158 goto SetEOFRetry;
5159
5160 return rc;
5161}
5162
5163int
Steve French50c2f752007-07-13 00:33:32 +00005164CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005165 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166{
5167 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 struct file_end_of_file_info *parm_data;
5169 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005170 __u16 params, param_offset, offset, byte_count, count;
5171
Joe Perchesb6b38f72010-04-21 03:50:45 +00005172 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5173 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005174 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5175
Linus Torvalds1da177e2005-04-16 15:20:36 -07005176 if (rc)
5177 return rc;
5178
5179 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5180 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005181
Linus Torvalds1da177e2005-04-16 15:20:36 -07005182 params = 6;
5183 pSMB->MaxSetupCount = 0;
5184 pSMB->Reserved = 0;
5185 pSMB->Flags = 0;
5186 pSMB->Timeout = 0;
5187 pSMB->Reserved2 = 0;
5188 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5189 offset = param_offset + params;
5190
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 count = sizeof(struct file_end_of_file_info);
5192 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005193 /* BB find exact max SMB PDU from sess structure BB */
5194 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 pSMB->SetupCount = 1;
5196 pSMB->Reserved3 = 0;
5197 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5198 byte_count = 3 /* pad */ + params + count;
5199 pSMB->DataCount = cpu_to_le16(count);
5200 pSMB->ParameterCount = cpu_to_le16(params);
5201 pSMB->TotalDataCount = pSMB->DataCount;
5202 pSMB->TotalParameterCount = pSMB->ParameterCount;
5203 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5204 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005205 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5206 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pSMB->DataOffset = cpu_to_le16(offset);
5208 parm_data->FileSize = cpu_to_le64(size);
5209 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005210 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5212 pSMB->InformationLevel =
5213 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5214 else
5215 pSMB->InformationLevel =
5216 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005217 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5219 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005220 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 else
5222 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005223 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224 }
5225 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005226 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005228 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005230 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 }
5232
Steve French50c2f752007-07-13 00:33:32 +00005233 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 since file handle passed in no longer valid */
5235
5236 return rc;
5237}
5238
Steve French50c2f752007-07-13 00:33:32 +00005239/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 an open handle, rather than by pathname - this is awkward due to
5241 potential access conflicts on the open, but it is unavoidable for these
5242 old servers since the only other choice is to go from 100 nanosecond DCE
5243 time and resort to the original setpathinfo level which takes the ancient
5244 DOS time format with 2 second granularity */
5245int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005246CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5247 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248{
5249 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 char *data_offset;
5251 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 __u16 params, param_offset, offset, byte_count, count;
5253
Joe Perchesb6b38f72010-04-21 03:50:45 +00005254 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005255 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5256
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 if (rc)
5258 return rc;
5259
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005260 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5261 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005262
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 params = 6;
5264 pSMB->MaxSetupCount = 0;
5265 pSMB->Reserved = 0;
5266 pSMB->Flags = 0;
5267 pSMB->Timeout = 0;
5268 pSMB->Reserved2 = 0;
5269 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5270 offset = param_offset + params;
5271
Steve French50c2f752007-07-13 00:33:32 +00005272 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273
Steve French26f57362007-08-30 22:09:15 +00005274 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005276 /* BB find max SMB PDU from sess */
5277 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 pSMB->SetupCount = 1;
5279 pSMB->Reserved3 = 0;
5280 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5281 byte_count = 3 /* pad */ + params + count;
5282 pSMB->DataCount = cpu_to_le16(count);
5283 pSMB->ParameterCount = cpu_to_le16(params);
5284 pSMB->TotalDataCount = pSMB->DataCount;
5285 pSMB->TotalParameterCount = pSMB->ParameterCount;
5286 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5287 pSMB->DataOffset = cpu_to_le16(offset);
5288 pSMB->Fid = fid;
5289 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5290 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5291 else
5292 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5293 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005294 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005296 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005297 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005298 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005299 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005300
Steve French50c2f752007-07-13 00:33:32 +00005301 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005302 since file handle passed in no longer valid */
5303
5304 return rc;
5305}
5306
Jeff Layton6d22f092008-09-23 11:48:35 -04005307int
5308CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5309 bool delete_file, __u16 fid, __u32 pid_of_opener)
5310{
5311 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5312 char *data_offset;
5313 int rc = 0;
5314 __u16 params, param_offset, offset, byte_count, count;
5315
Joe Perchesb6b38f72010-04-21 03:50:45 +00005316 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005317 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5318
5319 if (rc)
5320 return rc;
5321
5322 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5323 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5324
5325 params = 6;
5326 pSMB->MaxSetupCount = 0;
5327 pSMB->Reserved = 0;
5328 pSMB->Flags = 0;
5329 pSMB->Timeout = 0;
5330 pSMB->Reserved2 = 0;
5331 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5332 offset = param_offset + params;
5333
5334 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5335
5336 count = 1;
5337 pSMB->MaxParameterCount = cpu_to_le16(2);
5338 /* BB find max SMB PDU from sess */
5339 pSMB->MaxDataCount = cpu_to_le16(1000);
5340 pSMB->SetupCount = 1;
5341 pSMB->Reserved3 = 0;
5342 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5343 byte_count = 3 /* pad */ + params + count;
5344 pSMB->DataCount = cpu_to_le16(count);
5345 pSMB->ParameterCount = cpu_to_le16(params);
5346 pSMB->TotalDataCount = pSMB->DataCount;
5347 pSMB->TotalParameterCount = pSMB->ParameterCount;
5348 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5349 pSMB->DataOffset = cpu_to_le16(offset);
5350 pSMB->Fid = fid;
5351 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5352 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005353 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005354 pSMB->ByteCount = cpu_to_le16(byte_count);
5355 *data_offset = delete_file ? 1 : 0;
5356 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5357 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005358 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005359
5360 return rc;
5361}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362
5363int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005364CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5365 const char *fileName, const FILE_BASIC_INFO *data,
5366 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367{
5368 TRANSACTION2_SPI_REQ *pSMB = NULL;
5369 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5370 int name_len;
5371 int rc = 0;
5372 int bytes_returned = 0;
5373 char *data_offset;
5374 __u16 params, param_offset, offset, byte_count, count;
5375
Joe Perchesb6b38f72010-04-21 03:50:45 +00005376 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377
5378SetTimesRetry:
5379 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5380 (void **) &pSMBr);
5381 if (rc)
5382 return rc;
5383
5384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5385 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005386 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005387 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 name_len++; /* trailing null */
5389 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005390 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 name_len = strnlen(fileName, PATH_MAX);
5392 name_len++; /* trailing null */
5393 strncpy(pSMB->FileName, fileName, name_len);
5394 }
5395
5396 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005397 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005398 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005399 /* BB find max SMB PDU from sess structure BB */
5400 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 pSMB->MaxSetupCount = 0;
5402 pSMB->Reserved = 0;
5403 pSMB->Flags = 0;
5404 pSMB->Timeout = 0;
5405 pSMB->Reserved2 = 0;
5406 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005407 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005408 offset = param_offset + params;
5409 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5410 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5411 pSMB->DataOffset = cpu_to_le16(offset);
5412 pSMB->SetupCount = 1;
5413 pSMB->Reserved3 = 0;
5414 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5415 byte_count = 3 /* pad */ + params + count;
5416
5417 pSMB->DataCount = cpu_to_le16(count);
5418 pSMB->ParameterCount = cpu_to_le16(params);
5419 pSMB->TotalDataCount = pSMB->DataCount;
5420 pSMB->TotalParameterCount = pSMB->ParameterCount;
5421 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5422 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5423 else
5424 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5425 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005426 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005427 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005428 pSMB->ByteCount = cpu_to_le16(byte_count);
5429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005431 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005432 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433
5434 cifs_buf_release(pSMB);
5435
5436 if (rc == -EAGAIN)
5437 goto SetTimesRetry;
5438
5439 return rc;
5440}
5441
5442/* Can not be used to set time stamps yet (due to old DOS time format) */
5443/* Can be used to set attributes */
5444#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5445 handling it anyway and NT4 was what we thought it would be needed for
5446 Do not delete it until we prove whether needed for Win9x though */
5447int
5448CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5449 __u16 dos_attrs, const struct nls_table *nls_codepage)
5450{
5451 SETATTR_REQ *pSMB = NULL;
5452 SETATTR_RSP *pSMBr = NULL;
5453 int rc = 0;
5454 int bytes_returned;
5455 int name_len;
5456
Joe Perchesb6b38f72010-04-21 03:50:45 +00005457 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458
5459SetAttrLgcyRetry:
5460 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5461 (void **) &pSMBr);
5462 if (rc)
5463 return rc;
5464
5465 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5466 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005467 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005468 PATH_MAX, nls_codepage);
5469 name_len++; /* trailing null */
5470 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005471 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 name_len = strnlen(fileName, PATH_MAX);
5473 name_len++; /* trailing null */
5474 strncpy(pSMB->fileName, fileName, name_len);
5475 }
5476 pSMB->attr = cpu_to_le16(dos_attrs);
5477 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005478 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005482 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005483 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484
5485 cifs_buf_release(pSMB);
5486
5487 if (rc == -EAGAIN)
5488 goto SetAttrLgcyRetry;
5489
5490 return rc;
5491}
5492#endif /* temporarily unneeded SetAttr legacy function */
5493
Jeff Layton654cf142009-07-09 20:02:49 -04005494static void
5495cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5496 const struct cifs_unix_set_info_args *args)
5497{
5498 u64 mode = args->mode;
5499
5500 /*
5501 * Samba server ignores set of file size to zero due to bugs in some
5502 * older clients, but we should be precise - we use SetFileSize to
5503 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005504 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005505 * zero instead of -1 here
5506 */
5507 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5508 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5509 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5510 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5511 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5512 data_offset->Uid = cpu_to_le64(args->uid);
5513 data_offset->Gid = cpu_to_le64(args->gid);
5514 /* better to leave device as zero when it is */
5515 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5516 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5517 data_offset->Permissions = cpu_to_le64(mode);
5518
5519 if (S_ISREG(mode))
5520 data_offset->Type = cpu_to_le32(UNIX_FILE);
5521 else if (S_ISDIR(mode))
5522 data_offset->Type = cpu_to_le32(UNIX_DIR);
5523 else if (S_ISLNK(mode))
5524 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5525 else if (S_ISCHR(mode))
5526 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5527 else if (S_ISBLK(mode))
5528 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5529 else if (S_ISFIFO(mode))
5530 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5531 else if (S_ISSOCK(mode))
5532 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5533}
5534
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005536CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5537 const struct cifs_unix_set_info_args *args,
5538 u16 fid, u32 pid_of_opener)
5539{
5540 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5541 FILE_UNIX_BASIC_INFO *data_offset;
5542 int rc = 0;
5543 u16 params, param_offset, offset, byte_count, count;
5544
Joe Perchesb6b38f72010-04-21 03:50:45 +00005545 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005546 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5547
5548 if (rc)
5549 return rc;
5550
5551 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5552 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5553
5554 params = 6;
5555 pSMB->MaxSetupCount = 0;
5556 pSMB->Reserved = 0;
5557 pSMB->Flags = 0;
5558 pSMB->Timeout = 0;
5559 pSMB->Reserved2 = 0;
5560 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5561 offset = param_offset + params;
5562
5563 data_offset = (FILE_UNIX_BASIC_INFO *)
5564 ((char *)(&pSMB->hdr.Protocol) + offset);
5565 count = sizeof(FILE_UNIX_BASIC_INFO);
5566
5567 pSMB->MaxParameterCount = cpu_to_le16(2);
5568 /* BB find max SMB PDU from sess */
5569 pSMB->MaxDataCount = cpu_to_le16(1000);
5570 pSMB->SetupCount = 1;
5571 pSMB->Reserved3 = 0;
5572 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5573 byte_count = 3 /* pad */ + params + count;
5574 pSMB->DataCount = cpu_to_le16(count);
5575 pSMB->ParameterCount = cpu_to_le16(params);
5576 pSMB->TotalDataCount = pSMB->DataCount;
5577 pSMB->TotalParameterCount = pSMB->ParameterCount;
5578 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5579 pSMB->DataOffset = cpu_to_le16(offset);
5580 pSMB->Fid = fid;
5581 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5582 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005583 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005584 pSMB->ByteCount = cpu_to_le16(byte_count);
5585
5586 cifs_fill_unix_set_info(data_offset, args);
5587
5588 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5589 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005590 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005591
5592 /* Note: On -EAGAIN error only caller can retry on handle based calls
5593 since file handle passed in no longer valid */
5594
5595 return rc;
5596}
5597
5598int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005599CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5600 const struct cifs_unix_set_info_args *args,
5601 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602{
5603 TRANSACTION2_SPI_REQ *pSMB = NULL;
5604 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5605 int name_len;
5606 int rc = 0;
5607 int bytes_returned = 0;
5608 FILE_UNIX_BASIC_INFO *data_offset;
5609 __u16 params, param_offset, offset, count, byte_count;
5610
Joe Perchesb6b38f72010-04-21 03:50:45 +00005611 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005612setPermsRetry:
5613 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5614 (void **) &pSMBr);
5615 if (rc)
5616 return rc;
5617
5618 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5619 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005620 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005621 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622 name_len++; /* trailing null */
5623 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005624 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 name_len = strnlen(fileName, PATH_MAX);
5626 name_len++; /* trailing null */
5627 strncpy(pSMB->FileName, fileName, name_len);
5628 }
5629
5630 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005631 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005632 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005633 /* BB find max SMB PDU from sess structure BB */
5634 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635 pSMB->MaxSetupCount = 0;
5636 pSMB->Reserved = 0;
5637 pSMB->Flags = 0;
5638 pSMB->Timeout = 0;
5639 pSMB->Reserved2 = 0;
5640 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005641 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005642 offset = param_offset + params;
5643 data_offset =
5644 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5645 offset);
5646 memset(data_offset, 0, count);
5647 pSMB->DataOffset = cpu_to_le16(offset);
5648 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5649 pSMB->SetupCount = 1;
5650 pSMB->Reserved3 = 0;
5651 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5652 byte_count = 3 /* pad */ + params + count;
5653 pSMB->ParameterCount = cpu_to_le16(params);
5654 pSMB->DataCount = cpu_to_le16(count);
5655 pSMB->TotalParameterCount = pSMB->ParameterCount;
5656 pSMB->TotalDataCount = pSMB->DataCount;
5657 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5658 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005659 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005660
Jeff Layton654cf142009-07-09 20:02:49 -04005661 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005662
5663 pSMB->ByteCount = cpu_to_le16(byte_count);
5664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005666 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005667 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668
Steve French0d817bc2008-05-22 02:02:03 +00005669 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005670 if (rc == -EAGAIN)
5671 goto setPermsRetry;
5672 return rc;
5673}
5674
Linus Torvalds1da177e2005-04-16 15:20:36 -07005675#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005676/*
5677 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5678 * function used by listxattr and getxattr type calls. When ea_name is set,
5679 * it looks for that attribute name and stuffs that value into the EAData
5680 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5681 * buffer. In both cases, the return value is either the length of the
5682 * resulting data or a negative error code. If EAData is a NULL pointer then
5683 * the data isn't copied to it, but the length is returned.
5684 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005685ssize_t
5686CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005687 const unsigned char *searchName, const unsigned char *ea_name,
5688 char *EAData, size_t buf_size,
5689 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005690{
5691 /* BB assumes one setup word */
5692 TRANSACTION2_QPI_REQ *pSMB = NULL;
5693 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5694 int rc = 0;
5695 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005696 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005697 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005698 struct fea *temp_fea;
5699 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005700 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005701 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005702
Joe Perchesb6b38f72010-04-21 03:50:45 +00005703 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704QAllEAsRetry:
5705 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5706 (void **) &pSMBr);
5707 if (rc)
5708 return rc;
5709
5710 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005711 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005712 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005713 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005714 list_len++; /* trailing null */
5715 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005717 list_len = strnlen(searchName, PATH_MAX);
5718 list_len++; /* trailing null */
5719 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005720 }
5721
Jeff Layton6e462b92010-02-10 16:18:26 -05005722 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723 pSMB->TotalDataCount = 0;
5724 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005725 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005726 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005727 pSMB->MaxSetupCount = 0;
5728 pSMB->Reserved = 0;
5729 pSMB->Flags = 0;
5730 pSMB->Timeout = 0;
5731 pSMB->Reserved2 = 0;
5732 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005733 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005734 pSMB->DataCount = 0;
5735 pSMB->DataOffset = 0;
5736 pSMB->SetupCount = 1;
5737 pSMB->Reserved3 = 0;
5738 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5739 byte_count = params + 1 /* pad */ ;
5740 pSMB->TotalParameterCount = cpu_to_le16(params);
5741 pSMB->ParameterCount = pSMB->TotalParameterCount;
5742 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5743 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005744 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005745 pSMB->ByteCount = cpu_to_le16(byte_count);
5746
5747 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5748 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5749 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005750 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005751 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005752 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005753
5754
5755 /* BB also check enough total bytes returned */
5756 /* BB we need to improve the validity checking
5757 of these trans2 responses */
5758
5759 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005760 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005761 rc = -EIO; /* bad smb */
5762 goto QAllEAsOut;
5763 }
5764
5765 /* check that length of list is not more than bcc */
5766 /* check that each entry does not go beyond length
5767 of list */
5768 /* check that each element of each entry does not
5769 go beyond end of list */
5770 /* validate_trans2_offsets() */
5771 /* BB check if start of smb + data_offset > &bcc+ bcc */
5772
5773 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5774 ea_response_data = (struct fealist *)
5775 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5776
Jeff Layton6e462b92010-02-10 16:18:26 -05005777 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005778 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005779 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005780 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005781 goto QAllEAsOut;
5782 }
5783
Jeff Layton0cd126b2010-02-10 16:18:26 -05005784 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005785 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005786 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005787 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005788 rc = -EIO;
5789 goto QAllEAsOut;
5790 }
5791
Jeff Laytonf0d38682010-02-10 16:18:26 -05005792 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005793 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005794 temp_fea = ea_response_data->list;
5795 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005796 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005797 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005798 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005799
Jeff Layton6e462b92010-02-10 16:18:26 -05005800 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005801 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005802 /* make sure we can read name_len and value_len */
5803 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005804 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005805 rc = -EIO;
5806 goto QAllEAsOut;
5807 }
5808
5809 name_len = temp_fea->name_len;
5810 value_len = le16_to_cpu(temp_fea->value_len);
5811 list_len -= name_len + 1 + value_len;
5812 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005813 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005814 rc = -EIO;
5815 goto QAllEAsOut;
5816 }
5817
Jeff Layton31c05192010-02-10 16:18:26 -05005818 if (ea_name) {
5819 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5820 temp_ptr += name_len + 1;
5821 rc = value_len;
5822 if (buf_size == 0)
5823 goto QAllEAsOut;
5824 if ((size_t)value_len > buf_size) {
5825 rc = -ERANGE;
5826 goto QAllEAsOut;
5827 }
5828 memcpy(EAData, temp_ptr, value_len);
5829 goto QAllEAsOut;
5830 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005831 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005832 /* account for prefix user. and trailing null */
5833 rc += (5 + 1 + name_len);
5834 if (rc < (int) buf_size) {
5835 memcpy(EAData, "user.", 5);
5836 EAData += 5;
5837 memcpy(EAData, temp_ptr, name_len);
5838 EAData += name_len;
5839 /* null terminate name */
5840 *EAData = 0;
5841 ++EAData;
5842 } else if (buf_size == 0) {
5843 /* skip copy - calc size only */
5844 } else {
5845 /* stop before overrun buffer */
5846 rc = -ERANGE;
5847 break;
5848 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005849 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005850 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005851 temp_fea = (struct fea *)temp_ptr;
5852 }
5853
Jeff Layton31c05192010-02-10 16:18:26 -05005854 /* didn't find the named attribute */
5855 if (ea_name)
5856 rc = -ENODATA;
5857
Jeff Laytonf0d38682010-02-10 16:18:26 -05005858QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005859 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005860 if (rc == -EAGAIN)
5861 goto QAllEAsRetry;
5862
5863 return (ssize_t)rc;
5864}
5865
Linus Torvalds1da177e2005-04-16 15:20:36 -07005866int
5867CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005868 const char *ea_name, const void *ea_value,
5869 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5870 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005871{
5872 struct smb_com_transaction2_spi_req *pSMB = NULL;
5873 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5874 struct fealist *parm_data;
5875 int name_len;
5876 int rc = 0;
5877 int bytes_returned = 0;
5878 __u16 params, param_offset, byte_count, offset, count;
5879
Joe Perchesb6b38f72010-04-21 03:50:45 +00005880 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005881SetEARetry:
5882 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5883 (void **) &pSMBr);
5884 if (rc)
5885 return rc;
5886
5887 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5888 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005889 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005890 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891 name_len++; /* trailing null */
5892 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005893 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 name_len = strnlen(fileName, PATH_MAX);
5895 name_len++; /* trailing null */
5896 strncpy(pSMB->FileName, fileName, name_len);
5897 }
5898
5899 params = 6 + name_len;
5900
5901 /* done calculating parms using name_len of file name,
5902 now use name_len to calculate length of ea name
5903 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005904 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005905 name_len = 0;
5906 else
Steve French50c2f752007-07-13 00:33:32 +00005907 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005908
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00005909 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005911 /* BB find max SMB PDU from sess */
5912 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 pSMB->MaxSetupCount = 0;
5914 pSMB->Reserved = 0;
5915 pSMB->Flags = 0;
5916 pSMB->Timeout = 0;
5917 pSMB->Reserved2 = 0;
5918 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005919 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 offset = param_offset + params;
5921 pSMB->InformationLevel =
5922 cpu_to_le16(SMB_SET_FILE_EA);
5923
5924 parm_data =
5925 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5926 offset);
5927 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5928 pSMB->DataOffset = cpu_to_le16(offset);
5929 pSMB->SetupCount = 1;
5930 pSMB->Reserved3 = 0;
5931 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5932 byte_count = 3 /* pad */ + params + count;
5933 pSMB->DataCount = cpu_to_le16(count);
5934 parm_data->list_len = cpu_to_le32(count);
5935 parm_data->list[0].EA_flags = 0;
5936 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005937 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005938 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005939 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005940 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005941 parm_data->list[0].name[name_len] = 0;
5942 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5943 /* caller ensures that ea_value_len is less than 64K but
5944 we need to ensure that it fits within the smb */
5945
Steve French50c2f752007-07-13 00:33:32 +00005946 /*BB add length check to see if it would fit in
5947 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005948 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5949 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005950 memcpy(parm_data->list[0].name+name_len+1,
5951 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005952
5953 pSMB->TotalDataCount = pSMB->DataCount;
5954 pSMB->ParameterCount = cpu_to_le16(params);
5955 pSMB->TotalParameterCount = pSMB->ParameterCount;
5956 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005957 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005958 pSMB->ByteCount = cpu_to_le16(byte_count);
5959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005961 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005962 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005963
5964 cifs_buf_release(pSMB);
5965
5966 if (rc == -EAGAIN)
5967 goto SetEARetry;
5968
5969 return rc;
5970}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971#endif
Steve French0eff0e22011-02-24 05:39:23 +00005972
5973#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5974/*
5975 * Years ago the kernel added a "dnotify" function for Samba server,
5976 * to allow network clients (such as Windows) to display updated
5977 * lists of files in directory listings automatically when
5978 * files are added by one user when another user has the
5979 * same directory open on their desktop. The Linux cifs kernel
5980 * client hooked into the kernel side of this interface for
5981 * the same reason, but ironically when the VFS moved from
5982 * "dnotify" to "inotify" it became harder to plug in Linux
5983 * network file system clients (the most obvious use case
5984 * for notify interfaces is when multiple users can update
5985 * the contents of the same directory - exactly what network
5986 * file systems can do) although the server (Samba) could
5987 * still use it. For the short term we leave the worker
5988 * function ifdeffed out (below) until inotify is fixed
5989 * in the VFS to make it easier to plug in network file
5990 * system clients. If inotify turns out to be permanently
5991 * incompatible for network fs clients, we could instead simply
5992 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
5993 */
5994int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
5995 const int notify_subdirs, const __u16 netfid,
5996 __u32 filter, struct file *pfile, int multishot,
5997 const struct nls_table *nls_codepage)
5998{
5999 int rc = 0;
6000 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6001 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6002 struct dir_notify_req *dnotify_req;
6003 int bytes_returned;
6004
6005 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6006 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6007 (void **) &pSMBr);
6008 if (rc)
6009 return rc;
6010
6011 pSMB->TotalParameterCount = 0 ;
6012 pSMB->TotalDataCount = 0;
6013 pSMB->MaxParameterCount = cpu_to_le32(2);
6014 /* BB find exact data count max from sess structure BB */
6015 pSMB->MaxDataCount = 0; /* same in little endian or be */
6016/* BB VERIFY verify which is correct for above BB */
6017 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
6018 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
6019
6020 pSMB->MaxSetupCount = 4;
6021 pSMB->Reserved = 0;
6022 pSMB->ParameterOffset = 0;
6023 pSMB->DataCount = 0;
6024 pSMB->DataOffset = 0;
6025 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6026 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6027 pSMB->ParameterCount = pSMB->TotalParameterCount;
6028 if (notify_subdirs)
6029 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6030 pSMB->Reserved2 = 0;
6031 pSMB->CompletionFilter = cpu_to_le32(filter);
6032 pSMB->Fid = netfid; /* file handle always le */
6033 pSMB->ByteCount = 0;
6034
6035 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6036 (struct smb_hdr *)pSMBr, &bytes_returned,
6037 CIFS_ASYNC_OP);
6038 if (rc) {
6039 cFYI(1, "Error in Notify = %d", rc);
6040 } else {
6041 /* Add file to outstanding requests */
6042 /* BB change to kmem cache alloc */
6043 dnotify_req = kmalloc(
6044 sizeof(struct dir_notify_req),
6045 GFP_KERNEL);
6046 if (dnotify_req) {
6047 dnotify_req->Pid = pSMB->hdr.Pid;
6048 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6049 dnotify_req->Mid = pSMB->hdr.Mid;
6050 dnotify_req->Tid = pSMB->hdr.Tid;
6051 dnotify_req->Uid = pSMB->hdr.Uid;
6052 dnotify_req->netfid = netfid;
6053 dnotify_req->pfile = pfile;
6054 dnotify_req->filter = filter;
6055 dnotify_req->multishot = multishot;
6056 spin_lock(&GlobalMid_Lock);
6057 list_add_tail(&dnotify_req->lhead,
6058 &GlobalDnotifyReqList);
6059 spin_unlock(&GlobalMid_Lock);
6060 } else
6061 rc = -ENOMEM;
6062 }
6063 cifs_buf_release(pSMB);
6064 return rc;
6065}
6066#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */