blob: f39fa08b9b0eaf4cd321c1c0879d50d352b377c4 [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 Frenchb815f1e2006-10-02 05:53:29 +0000442 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000443 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000444
Steve French790fe572007-07-07 19:25:05 +0000445 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000446 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000447 server->secType = LANMAN;
448 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000449 cERROR(1, "mount failed weak security disabled"
450 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000453 }
Steve 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 Frenchb815f1e2006-10-02 05:53:29 +0000468 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000469 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000470 /* OS/2 often does not set timezone therefore
471 * we must use server time to calc time zone.
Steve Frenchb815f1e2006-10-02 05:53:29 +0000472 * Could deviate slightly from the right zone.
473 * Smallest defined timezone difference is 15 minutes
474 * (i.e. Nepal). Rounding up/down is done to match
475 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000476 */
Steve Frenchb815f1e2006-10-02 05:53:29 +0000477 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000478 struct timespec ts, utc;
479 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400480 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
481 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000482 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000483 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000484 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e2006-10-02 05:53:29 +0000485 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000486 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000487 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000488 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000489 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e2006-10-02 05:53:29 +0000490 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000491 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000492 result = -result;
Steve Frenchb815f1e2006-10-02 05:53:29 +0000493 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000494 } else {
Steve Frenchb815f1e2006-10-02 05:53:29 +0000495 server->timeAdj = (int)tmp;
496 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000497 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000498 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000499
Steve French39798772006-05-31 22:40:51 +0000500
Steve French254e55e2006-06-04 05:53:15 +0000501 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000502 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000503
Steve French50c2f752007-07-13 00:33:32 +0000504 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500506 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000507 CIFS_CRYPTO_KEY_SIZE);
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 Frenchb815f1e2006-10-02 05:53:29 +0000569 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
570 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000571 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500572 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000573 CIFS_CRYPTO_KEY_SIZE);
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 Frencheda3c022005-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 Frencheda3c022005-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 Frencheda3c022005-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
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001490CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1491 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001492 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001497 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 __u32 bytes_sent;
1499 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001500 __u32 pid = io_parms->pid;
1501 __u16 netfid = io_parms->netfid;
1502 __u64 offset = io_parms->offset;
1503 struct cifsTconInfo *tcon = io_parms->tcon;
1504 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505
Steve Frencha24e2d72010-04-03 17:20:21 +00001506 *nbytes = 0;
1507
Joe Perchesb6b38f72010-04-21 03:50:45 +00001508 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001509 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001510 return -ECONNABORTED;
1511
Steve French790fe572007-07-07 19:25:05 +00001512 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001513 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001514 else {
Steve French1c955182005-08-30 20:58:07 -07001515 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001516 if ((offset >> 32) > 0) {
1517 /* can not handle big offset for old srv */
1518 return -EIO;
1519 }
1520 }
Steve French1c955182005-08-30 20:58:07 -07001521
1522 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 (void **) &pSMBr);
1524 if (rc)
1525 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001526
1527 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1528 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1529
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 /* tcon and ses pointer are checked in smb_init */
1531 if (tcon->ses->server == NULL)
1532 return -ECONNABORTED;
1533
1534 pSMB->AndXCommand = 0xFF; /* none */
1535 pSMB->Fid = netfid;
1536 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001537 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001538 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001539
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 pSMB->Reserved = 0xFFFFFFFF;
1541 pSMB->WriteMode = 0;
1542 pSMB->Remaining = 0;
1543
Steve French50c2f752007-07-13 00:33:32 +00001544 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545 can send more if LARGE_WRITE_X capability returned by the server and if
1546 our buffer is big enough or if we convert to iovecs on socket writes
1547 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001548 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1550 } else {
1551 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1552 & ~0xFF;
1553 }
1554
1555 if (bytes_sent > count)
1556 bytes_sent = count;
1557 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001558 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001559 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001560 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001561 else if (ubuf) {
1562 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563 cifs_buf_release(pSMB);
1564 return -EFAULT;
1565 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001566 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567 /* No buffer */
1568 cifs_buf_release(pSMB);
1569 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001570 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001571 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001572 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001573 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001574 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1577 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001578 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001579
Steve French790fe572007-07-07 19:25:05 +00001580 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001581 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001582 else { /* old style write has byte count 4 bytes earlier
1583 so 4 bytes pad */
1584 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001585 (struct smb_com_writex_req *)pSMB;
1586 pSMBW->ByteCount = cpu_to_le16(byte_count);
1587 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
1589 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1590 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001591 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001593 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 } else {
1595 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1596 *nbytes = (*nbytes) << 16;
1597 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301598
1599 /*
1600 * Mask off high 16 bits when bytes written as returned by the
1601 * server is greater than bytes requested by the client. Some
1602 * OS/2 servers are known to set incorrect CountHigh values.
1603 */
1604 if (*nbytes > count)
1605 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 }
1607
1608 cifs_buf_release(pSMB);
1609
Steve French50c2f752007-07-13 00:33:32 +00001610 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 since file handle passed in no longer valid */
1612
1613 return rc;
1614}
1615
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001616void
1617cifs_writedata_release(struct kref *refcount)
1618{
1619 struct cifs_writedata *wdata = container_of(refcount,
1620 struct cifs_writedata, refcount);
1621
1622 if (wdata->cfile)
1623 cifsFileInfo_put(wdata->cfile);
1624
1625 kfree(wdata);
1626}
1627
1628/*
1629 * Write failed with a retryable error. Resend the write request. It's also
1630 * possible that the page was redirtied so re-clean the page.
1631 */
1632static void
1633cifs_writev_requeue(struct cifs_writedata *wdata)
1634{
1635 int i, rc;
1636 struct inode *inode = wdata->cfile->dentry->d_inode;
1637
1638 for (i = 0; i < wdata->nr_pages; i++) {
1639 lock_page(wdata->pages[i]);
1640 clear_page_dirty_for_io(wdata->pages[i]);
1641 }
1642
1643 do {
1644 rc = cifs_async_writev(wdata);
1645 } while (rc == -EAGAIN);
1646
1647 for (i = 0; i < wdata->nr_pages; i++) {
1648 if (rc != 0)
1649 SetPageError(wdata->pages[i]);
1650 unlock_page(wdata->pages[i]);
1651 }
1652
1653 mapping_set_error(inode->i_mapping, rc);
1654 kref_put(&wdata->refcount, cifs_writedata_release);
1655}
1656
1657static void
1658cifs_writev_complete(struct work_struct *work)
1659{
1660 struct cifs_writedata *wdata = container_of(work,
1661 struct cifs_writedata, work);
1662 struct inode *inode = wdata->cfile->dentry->d_inode;
1663 int i = 0;
1664
1665 if (wdata->result == 0) {
1666 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1667 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1668 wdata->bytes);
1669 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1670 return cifs_writev_requeue(wdata);
1671
1672 for (i = 0; i < wdata->nr_pages; i++) {
1673 struct page *page = wdata->pages[i];
1674 if (wdata->result == -EAGAIN)
1675 __set_page_dirty_nobuffers(page);
1676 else if (wdata->result < 0)
1677 SetPageError(page);
1678 end_page_writeback(page);
1679 page_cache_release(page);
1680 }
1681 if (wdata->result != -EAGAIN)
1682 mapping_set_error(inode->i_mapping, wdata->result);
1683 kref_put(&wdata->refcount, cifs_writedata_release);
1684}
1685
1686struct cifs_writedata *
1687cifs_writedata_alloc(unsigned int nr_pages)
1688{
1689 struct cifs_writedata *wdata;
1690
1691 /* this would overflow */
1692 if (nr_pages == 0) {
1693 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1694 return NULL;
1695 }
1696
1697 /* writedata + number of page pointers */
1698 wdata = kzalloc(sizeof(*wdata) +
1699 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1700 if (wdata != NULL) {
1701 INIT_WORK(&wdata->work, cifs_writev_complete);
1702 kref_init(&wdata->refcount);
1703 }
1704 return wdata;
1705}
1706
1707/*
1708 * Check the midState and signature on received buffer (if any), and queue the
1709 * workqueue completion task.
1710 */
1711static void
1712cifs_writev_callback(struct mid_q_entry *mid)
1713{
1714 struct cifs_writedata *wdata = mid->callback_data;
1715 struct cifsTconInfo *tcon = tlink_tcon(wdata->cfile->tlink);
1716 unsigned int written;
1717 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1718
1719 switch (mid->midState) {
1720 case MID_RESPONSE_RECEIVED:
1721 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1722 if (wdata->result != 0)
1723 break;
1724
1725 written = le16_to_cpu(smb->CountHigh);
1726 written <<= 16;
1727 written += le16_to_cpu(smb->Count);
1728 /*
1729 * Mask off high 16 bits when bytes written as returned
1730 * by the server is greater than bytes requested by the
1731 * client. OS/2 servers are known to set incorrect
1732 * CountHigh values.
1733 */
1734 if (written > wdata->bytes)
1735 written &= 0xFFFF;
1736
1737 if (written < wdata->bytes)
1738 wdata->result = -ENOSPC;
1739 else
1740 wdata->bytes = written;
1741 break;
1742 case MID_REQUEST_SUBMITTED:
1743 case MID_RETRY_NEEDED:
1744 wdata->result = -EAGAIN;
1745 break;
1746 default:
1747 wdata->result = -EIO;
1748 break;
1749 }
1750
1751 queue_work(system_nrt_wq, &wdata->work);
1752 DeleteMidQEntry(mid);
1753 atomic_dec(&tcon->ses->server->inFlight);
1754 wake_up(&tcon->ses->server->request_q);
1755}
1756
1757/* cifs_async_writev - send an async write, and set up mid to handle result */
1758int
1759cifs_async_writev(struct cifs_writedata *wdata)
1760{
1761 int i, rc = -EACCES;
1762 WRITE_REQ *smb = NULL;
1763 int wct;
1764 struct cifsTconInfo *tcon = tlink_tcon(wdata->cfile->tlink);
1765 struct inode *inode = wdata->cfile->dentry->d_inode;
1766 struct kvec *iov = NULL;
1767
1768 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1769 wct = 14;
1770 } else {
1771 wct = 12;
1772 if (wdata->offset >> 32 > 0) {
1773 /* can not handle big offset for old srv */
1774 return -EIO;
1775 }
1776 }
1777
1778 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
1779 if (rc)
1780 goto async_writev_out;
1781
1782 /* 1 iov per page + 1 for header */
1783 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
1784 if (iov == NULL) {
1785 rc = -ENOMEM;
1786 goto async_writev_out;
1787 }
1788
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001789 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
1790 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
1791
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001792 smb->AndXCommand = 0xFF; /* none */
1793 smb->Fid = wdata->cfile->netfid;
1794 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
1795 if (wct == 14)
1796 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
1797 smb->Reserved = 0xFFFFFFFF;
1798 smb->WriteMode = 0;
1799 smb->Remaining = 0;
1800
1801 smb->DataOffset =
1802 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1803
1804 /* 4 for RFC1001 length + 1 for BCC */
1805 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
1806 iov[0].iov_base = smb;
1807
1808 /* marshal up the pages into iov array */
1809 wdata->bytes = 0;
1810 for (i = 0; i < wdata->nr_pages; i++) {
1811 iov[i + 1].iov_len = min(inode->i_size -
1812 page_offset(wdata->pages[i]),
1813 (loff_t)PAGE_CACHE_SIZE);
1814 iov[i + 1].iov_base = kmap(wdata->pages[i]);
1815 wdata->bytes += iov[i + 1].iov_len;
1816 }
1817
1818 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
1819
1820 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
1821 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
1822
1823 if (wct == 14) {
1824 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
1825 put_bcc(wdata->bytes + 1, &smb->hdr);
1826 } else {
1827 /* wct == 12 */
1828 struct smb_com_writex_req *smbw =
1829 (struct smb_com_writex_req *)smb;
1830 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
1831 put_bcc(wdata->bytes + 5, &smbw->hdr);
1832 iov[0].iov_len += 4; /* pad bigger by four bytes */
1833 }
1834
1835 kref_get(&wdata->refcount);
1836 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
1837 cifs_writev_callback, wdata, false);
1838
1839 if (rc == 0)
1840 cifs_stats_inc(&tcon->num_writes);
1841 else
1842 kref_put(&wdata->refcount, cifs_writedata_release);
1843
1844 /* send is done, unmap pages */
1845 for (i = 0; i < wdata->nr_pages; i++)
1846 kunmap(wdata->pages[i]);
1847
1848async_writev_out:
1849 cifs_small_buf_release(smb);
1850 kfree(iov);
1851 return rc;
1852}
1853
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001854int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001855CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
1856 unsigned int *nbytes, struct kvec *iov, int n_vec,
1857 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858{
1859 int rc = -EACCES;
1860 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001861 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001862 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001863 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001864 __u32 pid = io_parms->pid;
1865 __u16 netfid = io_parms->netfid;
1866 __u64 offset = io_parms->offset;
1867 struct cifsTconInfo *tcon = io_parms->tcon;
1868 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001870 *nbytes = 0;
1871
Joe Perchesb6b38f72010-04-21 03:50:45 +00001872 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001873
Steve French4c3130e2008-12-09 00:28:16 +00001874 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001875 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001876 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001877 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001878 if ((offset >> 32) > 0) {
1879 /* can not handle big offset for old srv */
1880 return -EIO;
1881 }
1882 }
Steve French8cc64c62005-10-03 13:49:43 -07001883 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (rc)
1885 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001886
1887 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1888 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 /* tcon and ses pointer are checked in smb_init */
1891 if (tcon->ses->server == NULL)
1892 return -ECONNABORTED;
1893
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001894 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 pSMB->Fid = netfid;
1896 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001897 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001898 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 pSMB->Reserved = 0xFFFFFFFF;
1900 pSMB->WriteMode = 0;
1901 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001904 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905
Steve French3e844692005-10-03 13:37:24 -07001906 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1907 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001908 /* header + 1 byte pad */
1909 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001910 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001911 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001912 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001913 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001914 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001915 pSMB->ByteCount = cpu_to_le16(count + 1);
1916 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001917 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001918 (struct smb_com_writex_req *)pSMB;
1919 pSMBW->ByteCount = cpu_to_le16(count + 5);
1920 }
Steve French3e844692005-10-03 13:37:24 -07001921 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001922 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001923 iov[0].iov_len = smb_hdr_len + 4;
1924 else /* wct == 12 pad bigger by four bytes */
1925 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001926
Steve French3e844692005-10-03 13:37:24 -07001927
Steve Frenchec637e32005-12-12 20:53:18 -08001928 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001929 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001930 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001932 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001933 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001934 /* presumably this can not happen, but best to be safe */
1935 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001936 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001937 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001938 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1939 *nbytes = (*nbytes) << 16;
1940 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301941
1942 /*
1943 * Mask off high 16 bits when bytes written as returned by the
1944 * server is greater than bytes requested by the client. OS/2
1945 * servers are known to set incorrect CountHigh values.
1946 */
1947 if (*nbytes > count)
1948 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001949 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
Steve French4b8f9302006-02-26 16:41:18 +00001951/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001952 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001953 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001954 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001955 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956
Steve French50c2f752007-07-13 00:33:32 +00001957 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 since file handle passed in no longer valid */
1959
1960 return rc;
1961}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001962
1963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964int
1965CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1966 const __u16 smb_file_id, const __u64 len,
1967 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001968 const __u32 numLock, const __u8 lockType,
1969 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{
1971 int rc = 0;
1972 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001973/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 int bytes_returned;
1975 int timeout = 0;
1976 __u16 count;
1977
Joe Perchesb6b38f72010-04-21 03:50:45 +00001978 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001979 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if (rc)
1982 return rc;
1983
Steve French790fe572007-07-07 19:25:05 +00001984 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001985 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001987 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001988 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1990 } else {
1991 pSMB->Timeout = 0;
1992 }
1993
1994 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1995 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1996 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001997 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 pSMB->AndXCommand = 0xFF; /* none */
1999 pSMB->Fid = smb_file_id; /* netfid stays le */
2000
Steve French790fe572007-07-07 19:25:05 +00002001 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
2003 /* BB where to store pid high? */
2004 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2005 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2006 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2007 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2008 count = sizeof(LOCKING_ANDX_RANGE);
2009 } else {
2010 /* oplock break */
2011 count = 0;
2012 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002013 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014 pSMB->ByteCount = cpu_to_le16(count);
2015
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002016 if (waitFlag) {
2017 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002018 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002019 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002020 } else {
Steve French133672e2007-11-13 22:41:37 +00002021 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2022 timeout);
2023 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002024 }
Steve Frencha4544342005-08-24 13:59:35 -07002025 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002026 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002027 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028
Steve French50c2f752007-07-13 00:33:32 +00002029 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 since file handle passed in no longer valid */
2031 return rc;
2032}
2033
2034int
Steve French08547b02006-02-28 22:39:25 +00002035CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
2036 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00002037 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00002038 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002039{
2040 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2041 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002042 struct cifs_posix_lock *parm_data;
2043 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002044 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002045 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002046 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002047 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002048 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002049
Joe Perchesb6b38f72010-04-21 03:50:45 +00002050 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002051
Steve French790fe572007-07-07 19:25:05 +00002052 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002053 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002054
Steve French08547b02006-02-28 22:39:25 +00002055 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2056
2057 if (rc)
2058 return rc;
2059
2060 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2061
Steve French50c2f752007-07-13 00:33:32 +00002062 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002063 pSMB->MaxSetupCount = 0;
2064 pSMB->Reserved = 0;
2065 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002066 pSMB->Reserved2 = 0;
2067 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2068 offset = param_offset + params;
2069
Steve French08547b02006-02-28 22:39:25 +00002070 count = sizeof(struct cifs_posix_lock);
2071 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002072 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002073 pSMB->SetupCount = 1;
2074 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002075 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002076 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2077 else
2078 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2079 byte_count = 3 /* pad */ + params + count;
2080 pSMB->DataCount = cpu_to_le16(count);
2081 pSMB->ParameterCount = cpu_to_le16(params);
2082 pSMB->TotalDataCount = pSMB->DataCount;
2083 pSMB->TotalParameterCount = pSMB->ParameterCount;
2084 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002085 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002086 (((char *) &pSMB->hdr.Protocol) + offset);
2087
2088 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002089 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002090 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002091 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002092 pSMB->Timeout = cpu_to_le32(-1);
2093 } else
2094 pSMB->Timeout = 0;
2095
Steve French08547b02006-02-28 22:39:25 +00002096 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002097 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002098 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002099
2100 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002101 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002102 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2103 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002104 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002105 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002106 if (waitFlag) {
2107 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2108 (struct smb_hdr *) pSMBr, &bytes_returned);
2109 } else {
Steve French133672e2007-11-13 22:41:37 +00002110 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002111 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002112 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2113 &resp_buf_type, timeout);
2114 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2115 not try to free it twice below on exit */
2116 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002117 }
2118
Steve French08547b02006-02-28 22:39:25 +00002119 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002120 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002121 } else if (get_flag) {
2122 /* lock structure can be returned on get */
2123 __u16 data_offset;
2124 __u16 data_count;
2125 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002126
Jeff Layton820a8032011-05-04 08:05:26 -04002127 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002128 rc = -EIO; /* bad smb */
2129 goto plk_err_exit;
2130 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002131 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2132 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002133 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002134 rc = -EIO;
2135 goto plk_err_exit;
2136 }
2137 parm_data = (struct cifs_posix_lock *)
2138 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002139 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002140 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002141 else {
2142 if (parm_data->lock_type ==
2143 __constant_cpu_to_le16(CIFS_RDLCK))
2144 pLockData->fl_type = F_RDLCK;
2145 else if (parm_data->lock_type ==
2146 __constant_cpu_to_le16(CIFS_WRLCK))
2147 pLockData->fl_type = F_WRLCK;
2148
Steve French5443d132011-03-13 05:08:25 +00002149 pLockData->fl_start = le64_to_cpu(parm_data->start);
2150 pLockData->fl_end = pLockData->fl_start +
2151 le64_to_cpu(parm_data->length) - 1;
2152 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002153 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002154 }
Steve French50c2f752007-07-13 00:33:32 +00002155
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002156plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002157 if (pSMB)
2158 cifs_small_buf_release(pSMB);
2159
Steve French133672e2007-11-13 22:41:37 +00002160 if (resp_buf_type == CIFS_SMALL_BUFFER)
2161 cifs_small_buf_release(iov[0].iov_base);
2162 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2163 cifs_buf_release(iov[0].iov_base);
2164
Steve French08547b02006-02-28 22:39:25 +00002165 /* Note: On -EAGAIN error only caller can retry on handle based calls
2166 since file handle passed in no longer valid */
2167
2168 return rc;
2169}
2170
2171
2172int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
2174{
2175 int rc = 0;
2176 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002177 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
2179/* do not retry on dead session on close */
2180 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002181 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return 0;
2183 if (rc)
2184 return rc;
2185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00002187 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002189 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002190 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002192 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002194 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 }
2196 }
2197
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002199 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 rc = 0;
2201
2202 return rc;
2203}
2204
2205int
Steve Frenchb298f222009-02-21 21:17:43 +00002206CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
2207{
2208 int rc = 0;
2209 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002210 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002211
2212 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2213 if (rc)
2214 return rc;
2215
2216 pSMB->FileID = (__u16) smb_file_id;
2217 pSMB->ByteCount = 0;
2218 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2219 cifs_stats_inc(&tcon->num_flushes);
2220 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002221 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002222
2223 return rc;
2224}
2225
2226int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
2228 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002229 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230{
2231 int rc = 0;
2232 RENAME_REQ *pSMB = NULL;
2233 RENAME_RSP *pSMBr = NULL;
2234 int bytes_returned;
2235 int name_len, name_len2;
2236 __u16 count;
2237
Joe Perchesb6b38f72010-04-21 03:50:45 +00002238 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239renameRetry:
2240 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2241 (void **) &pSMBr);
2242 if (rc)
2243 return rc;
2244
2245 pSMB->BufferFormat = 0x04;
2246 pSMB->SearchAttributes =
2247 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2248 ATTR_DIRECTORY);
2249
2250 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2251 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002252 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002253 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 name_len++; /* trailing null */
2255 name_len *= 2;
2256 pSMB->OldFileName[name_len] = 0x04; /* pad */
2257 /* protocol requires ASCII signature byte on Unicode string */
2258 pSMB->OldFileName[name_len + 1] = 0x00;
2259 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002260 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002261 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2263 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002264 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265 name_len = strnlen(fromName, PATH_MAX);
2266 name_len++; /* trailing null */
2267 strncpy(pSMB->OldFileName, fromName, name_len);
2268 name_len2 = strnlen(toName, PATH_MAX);
2269 name_len2++; /* trailing null */
2270 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2271 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2272 name_len2++; /* trailing null */
2273 name_len2++; /* signature byte */
2274 }
2275
2276 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002277 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 pSMB->ByteCount = cpu_to_le16(count);
2279
2280 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2281 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002282 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002283 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002284 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286 cifs_buf_release(pSMB);
2287
2288 if (rc == -EAGAIN)
2289 goto renameRetry;
2290
2291 return rc;
2292}
2293
Steve French50c2f752007-07-13 00:33:32 +00002294int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002295 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002296 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297{
2298 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2299 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002300 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 char *data_offset;
2302 char dummy_string[30];
2303 int rc = 0;
2304 int bytes_returned = 0;
2305 int len_of_str;
2306 __u16 params, param_offset, offset, count, byte_count;
2307
Joe Perchesb6b38f72010-04-21 03:50:45 +00002308 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2310 (void **) &pSMBr);
2311 if (rc)
2312 return rc;
2313
2314 params = 6;
2315 pSMB->MaxSetupCount = 0;
2316 pSMB->Reserved = 0;
2317 pSMB->Flags = 0;
2318 pSMB->Timeout = 0;
2319 pSMB->Reserved2 = 0;
2320 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2321 offset = param_offset + params;
2322
2323 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2324 rename_info = (struct set_file_rename *) data_offset;
2325 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002326 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 pSMB->SetupCount = 1;
2328 pSMB->Reserved3 = 0;
2329 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2330 byte_count = 3 /* pad */ + params;
2331 pSMB->ParameterCount = cpu_to_le16(params);
2332 pSMB->TotalParameterCount = pSMB->ParameterCount;
2333 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2334 pSMB->DataOffset = cpu_to_le16(offset);
2335 /* construct random name ".cifs_tmp<inodenum><mid>" */
2336 rename_info->overwrite = cpu_to_le32(1);
2337 rename_info->root_fid = 0;
2338 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002339 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002340 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2341 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002342 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002344 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002345 target_name, PATH_MAX, nls_codepage,
2346 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 }
2348 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002349 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 byte_count += count;
2351 pSMB->DataCount = cpu_to_le16(count);
2352 pSMB->TotalDataCount = pSMB->DataCount;
2353 pSMB->Fid = netfid;
2354 pSMB->InformationLevel =
2355 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2356 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002357 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 pSMB->ByteCount = cpu_to_le16(byte_count);
2359 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002361 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002362 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002363 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002364
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 cifs_buf_release(pSMB);
2366
2367 /* Note: On -EAGAIN error only caller can retry on handle based calls
2368 since file handle passed in no longer valid */
2369
2370 return rc;
2371}
2372
2373int
Steve French50c2f752007-07-13 00:33:32 +00002374CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2375 const __u16 target_tid, const char *toName, const int flags,
2376 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377{
2378 int rc = 0;
2379 COPY_REQ *pSMB = NULL;
2380 COPY_RSP *pSMBr = NULL;
2381 int bytes_returned;
2382 int name_len, name_len2;
2383 __u16 count;
2384
Joe Perchesb6b38f72010-04-21 03:50:45 +00002385 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386copyRetry:
2387 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2388 (void **) &pSMBr);
2389 if (rc)
2390 return rc;
2391
2392 pSMB->BufferFormat = 0x04;
2393 pSMB->Tid2 = target_tid;
2394
2395 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2396
2397 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002398 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002399 fromName, PATH_MAX, nls_codepage,
2400 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002401 name_len++; /* trailing null */
2402 name_len *= 2;
2403 pSMB->OldFileName[name_len] = 0x04; /* pad */
2404 /* protocol requires ASCII signature byte on Unicode string */
2405 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002406 name_len2 =
2407 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002408 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2410 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002411 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 name_len = strnlen(fromName, PATH_MAX);
2413 name_len++; /* trailing null */
2414 strncpy(pSMB->OldFileName, fromName, name_len);
2415 name_len2 = strnlen(toName, PATH_MAX);
2416 name_len2++; /* trailing null */
2417 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2418 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2419 name_len2++; /* trailing null */
2420 name_len2++; /* signature byte */
2421 }
2422
2423 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002424 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 pSMB->ByteCount = cpu_to_le16(count);
2426
2427 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2428 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2429 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002430 cFYI(1, "Send error in copy = %d with %d files copied",
2431 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 }
Steve French0d817bc2008-05-22 02:02:03 +00002433 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
2435 if (rc == -EAGAIN)
2436 goto copyRetry;
2437
2438 return rc;
2439}
2440
2441int
2442CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2443 const char *fromName, const char *toName,
2444 const struct nls_table *nls_codepage)
2445{
2446 TRANSACTION2_SPI_REQ *pSMB = NULL;
2447 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2448 char *data_offset;
2449 int name_len;
2450 int name_len_target;
2451 int rc = 0;
2452 int bytes_returned = 0;
2453 __u16 params, param_offset, offset, byte_count;
2454
Joe Perchesb6b38f72010-04-21 03:50:45 +00002455 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456createSymLinkRetry:
2457 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2458 (void **) &pSMBr);
2459 if (rc)
2460 return rc;
2461
2462 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2463 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002464 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 /* find define for this maxpathcomponent */
2466 , nls_codepage);
2467 name_len++; /* trailing null */
2468 name_len *= 2;
2469
Steve French50c2f752007-07-13 00:33:32 +00002470 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 name_len = strnlen(fromName, PATH_MAX);
2472 name_len++; /* trailing null */
2473 strncpy(pSMB->FileName, fromName, name_len);
2474 }
2475 params = 6 + name_len;
2476 pSMB->MaxSetupCount = 0;
2477 pSMB->Reserved = 0;
2478 pSMB->Flags = 0;
2479 pSMB->Timeout = 0;
2480 pSMB->Reserved2 = 0;
2481 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002482 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 offset = param_offset + params;
2484
2485 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2486 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2487 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002488 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 /* find define for this maxpathcomponent */
2490 , nls_codepage);
2491 name_len_target++; /* trailing null */
2492 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002493 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 name_len_target = strnlen(toName, PATH_MAX);
2495 name_len_target++; /* trailing null */
2496 strncpy(data_offset, toName, name_len_target);
2497 }
2498
2499 pSMB->MaxParameterCount = cpu_to_le16(2);
2500 /* BB find exact max on data count below from sess */
2501 pSMB->MaxDataCount = cpu_to_le16(1000);
2502 pSMB->SetupCount = 1;
2503 pSMB->Reserved3 = 0;
2504 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2505 byte_count = 3 /* pad */ + params + name_len_target;
2506 pSMB->DataCount = cpu_to_le16(name_len_target);
2507 pSMB->ParameterCount = cpu_to_le16(params);
2508 pSMB->TotalDataCount = pSMB->DataCount;
2509 pSMB->TotalParameterCount = pSMB->ParameterCount;
2510 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2511 pSMB->DataOffset = cpu_to_le16(offset);
2512 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2513 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002514 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515 pSMB->ByteCount = cpu_to_le16(byte_count);
2516 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2517 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002518 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002519 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002520 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
Steve French0d817bc2008-05-22 02:02:03 +00002522 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
2524 if (rc == -EAGAIN)
2525 goto createSymLinkRetry;
2526
2527 return rc;
2528}
2529
2530int
2531CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2532 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002533 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534{
2535 TRANSACTION2_SPI_REQ *pSMB = NULL;
2536 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2537 char *data_offset;
2538 int name_len;
2539 int name_len_target;
2540 int rc = 0;
2541 int bytes_returned = 0;
2542 __u16 params, param_offset, offset, byte_count;
2543
Joe Perchesb6b38f72010-04-21 03:50:45 +00002544 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545createHardLinkRetry:
2546 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2547 (void **) &pSMBr);
2548 if (rc)
2549 return rc;
2550
2551 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002552 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002553 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 name_len++; /* trailing null */
2555 name_len *= 2;
2556
Steve French50c2f752007-07-13 00:33:32 +00002557 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558 name_len = strnlen(toName, PATH_MAX);
2559 name_len++; /* trailing null */
2560 strncpy(pSMB->FileName, toName, name_len);
2561 }
2562 params = 6 + name_len;
2563 pSMB->MaxSetupCount = 0;
2564 pSMB->Reserved = 0;
2565 pSMB->Flags = 0;
2566 pSMB->Timeout = 0;
2567 pSMB->Reserved2 = 0;
2568 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002569 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 offset = param_offset + params;
2571
2572 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2573 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2574 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002575 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002576 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 name_len_target++; /* trailing null */
2578 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002579 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 name_len_target = strnlen(fromName, PATH_MAX);
2581 name_len_target++; /* trailing null */
2582 strncpy(data_offset, fromName, name_len_target);
2583 }
2584
2585 pSMB->MaxParameterCount = cpu_to_le16(2);
2586 /* BB find exact max on data count below from sess*/
2587 pSMB->MaxDataCount = cpu_to_le16(1000);
2588 pSMB->SetupCount = 1;
2589 pSMB->Reserved3 = 0;
2590 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2591 byte_count = 3 /* pad */ + params + name_len_target;
2592 pSMB->ParameterCount = cpu_to_le16(params);
2593 pSMB->TotalParameterCount = pSMB->ParameterCount;
2594 pSMB->DataCount = cpu_to_le16(name_len_target);
2595 pSMB->TotalDataCount = pSMB->DataCount;
2596 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2597 pSMB->DataOffset = cpu_to_le16(offset);
2598 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2599 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002600 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 pSMB->ByteCount = cpu_to_le16(byte_count);
2602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002604 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002605 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002606 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 cifs_buf_release(pSMB);
2609 if (rc == -EAGAIN)
2610 goto createHardLinkRetry;
2611
2612 return rc;
2613}
2614
2615int
2616CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2617 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002618 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619{
2620 int rc = 0;
2621 NT_RENAME_REQ *pSMB = NULL;
2622 RENAME_RSP *pSMBr = NULL;
2623 int bytes_returned;
2624 int name_len, name_len2;
2625 __u16 count;
2626
Joe Perchesb6b38f72010-04-21 03:50:45 +00002627 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628winCreateHardLinkRetry:
2629
2630 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2631 (void **) &pSMBr);
2632 if (rc)
2633 return rc;
2634
2635 pSMB->SearchAttributes =
2636 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2637 ATTR_DIRECTORY);
2638 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2639 pSMB->ClusterCount = 0;
2640
2641 pSMB->BufferFormat = 0x04;
2642
2643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2644 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002645 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002646 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 name_len++; /* trailing null */
2648 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002649
2650 /* protocol specifies ASCII buffer format (0x04) for unicode */
2651 pSMB->OldFileName[name_len] = 0x04;
2652 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002654 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002655 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2657 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002658 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 name_len = strnlen(fromName, PATH_MAX);
2660 name_len++; /* trailing null */
2661 strncpy(pSMB->OldFileName, fromName, name_len);
2662 name_len2 = strnlen(toName, PATH_MAX);
2663 name_len2++; /* trailing null */
2664 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2665 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2666 name_len2++; /* trailing null */
2667 name_len2++; /* signature byte */
2668 }
2669
2670 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002671 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 pSMB->ByteCount = cpu_to_le16(count);
2673
2674 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2675 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002676 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002677 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002678 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002679
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 cifs_buf_release(pSMB);
2681 if (rc == -EAGAIN)
2682 goto winCreateHardLinkRetry;
2683
2684 return rc;
2685}
2686
2687int
2688CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002689 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 const struct nls_table *nls_codepage)
2691{
2692/* SMB_QUERY_FILE_UNIX_LINK */
2693 TRANSACTION2_QPI_REQ *pSMB = NULL;
2694 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2695 int rc = 0;
2696 int bytes_returned;
2697 int name_len;
2698 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002699 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Joe Perchesb6b38f72010-04-21 03:50:45 +00002701 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
2703querySymLinkRetry:
2704 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2705 (void **) &pSMBr);
2706 if (rc)
2707 return rc;
2708
2709 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2710 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002711 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2712 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 name_len++; /* trailing null */
2714 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002715 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 name_len = strnlen(searchName, PATH_MAX);
2717 name_len++; /* trailing null */
2718 strncpy(pSMB->FileName, searchName, name_len);
2719 }
2720
2721 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2722 pSMB->TotalDataCount = 0;
2723 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002724 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 pSMB->MaxSetupCount = 0;
2726 pSMB->Reserved = 0;
2727 pSMB->Flags = 0;
2728 pSMB->Timeout = 0;
2729 pSMB->Reserved2 = 0;
2730 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002731 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 pSMB->DataCount = 0;
2733 pSMB->DataOffset = 0;
2734 pSMB->SetupCount = 1;
2735 pSMB->Reserved3 = 0;
2736 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2737 byte_count = params + 1 /* pad */ ;
2738 pSMB->TotalParameterCount = cpu_to_le16(params);
2739 pSMB->ParameterCount = pSMB->TotalParameterCount;
2740 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2741 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002742 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 pSMB->ByteCount = cpu_to_le16(byte_count);
2744
2745 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2746 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2747 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002748 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 } else {
2750 /* decode response */
2751
2752 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002754 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002755 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002757 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002758 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759
Jeff Layton460b9692009-04-30 07:17:56 -04002760 data_start = ((char *) &pSMBr->hdr.Protocol) +
2761 le16_to_cpu(pSMBr->t2.DataOffset);
2762
Steve French0e0d2cf2009-05-01 05:27:32 +00002763 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2764 is_unicode = true;
2765 else
2766 is_unicode = false;
2767
Steve French737b7582005-04-28 22:41:06 -07002768 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002769 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002770 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002771 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002772 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 }
2774 }
2775 cifs_buf_release(pSMB);
2776 if (rc == -EAGAIN)
2777 goto querySymLinkRetry;
2778 return rc;
2779}
2780
Steve Frenchc52a9552011-02-24 06:16:22 +00002781#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2782/*
2783 * Recent Windows versions now create symlinks more frequently
2784 * and they use the "reparse point" mechanism below. We can of course
2785 * do symlinks nicely to Samba and other servers which support the
2786 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2787 * "MF" symlinks optionally, but for recent Windows we really need to
2788 * reenable the code below and fix the cifs_symlink callers to handle this.
2789 * In the interim this code has been moved to its own config option so
2790 * it is not compiled in by default until callers fixed up and more tested.
2791 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792int
2793CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2794 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002795 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 const struct nls_table *nls_codepage)
2797{
2798 int rc = 0;
2799 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002800 struct smb_com_transaction_ioctl_req *pSMB;
2801 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
Joe Perchesb6b38f72010-04-21 03:50:45 +00002803 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2805 (void **) &pSMBr);
2806 if (rc)
2807 return rc;
2808
2809 pSMB->TotalParameterCount = 0 ;
2810 pSMB->TotalDataCount = 0;
2811 pSMB->MaxParameterCount = cpu_to_le32(2);
2812 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002813 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2814 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 pSMB->MaxSetupCount = 4;
2816 pSMB->Reserved = 0;
2817 pSMB->ParameterOffset = 0;
2818 pSMB->DataCount = 0;
2819 pSMB->DataOffset = 0;
2820 pSMB->SetupCount = 4;
2821 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2822 pSMB->ParameterCount = pSMB->TotalParameterCount;
2823 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2824 pSMB->IsFsctl = 1; /* FSCTL */
2825 pSMB->IsRootFlag = 0;
2826 pSMB->Fid = fid; /* file handle always le */
2827 pSMB->ByteCount = 0;
2828
2829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2831 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002832 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 } else { /* decode response */
2834 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2835 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002836 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2837 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002839 goto qreparse_out;
2840 }
2841 if (data_count && (data_count < 2048)) {
2842 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002843 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844
Steve Frenchafe48c32009-05-02 05:25:46 +00002845 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002846 (struct reparse_data *)
2847 ((char *)&pSMBr->hdr.Protocol
2848 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002849 if ((char *)reparse_buf >= end_of_smb) {
2850 rc = -EIO;
2851 goto qreparse_out;
2852 }
2853 if ((reparse_buf->LinkNamesBuf +
2854 reparse_buf->TargetNameOffset +
2855 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002856 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002857 rc = -EIO;
2858 goto qreparse_out;
2859 }
Steve French50c2f752007-07-13 00:33:32 +00002860
Steve Frenchafe48c32009-05-02 05:25:46 +00002861 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2862 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002863 (reparse_buf->LinkNamesBuf +
2864 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002865 buflen,
2866 reparse_buf->TargetNameLen,
2867 nls_codepage, 0);
2868 } else { /* ASCII names */
2869 strncpy(symlinkinfo,
2870 reparse_buf->LinkNamesBuf +
2871 reparse_buf->TargetNameOffset,
2872 min_t(const int, buflen,
2873 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002875 } else {
2876 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002877 cFYI(1, "Invalid return data count on "
2878 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002880 symlinkinfo[buflen] = 0; /* just in case so the caller
2881 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002882 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 }
Steve French989c7e52009-05-02 05:32:20 +00002884
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002886 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887
2888 /* Note: On -EAGAIN error only caller can retry on handle based calls
2889 since file handle passed in no longer valid */
2890
2891 return rc;
2892}
Steve Frenchc52a9552011-02-24 06:16:22 +00002893#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895#ifdef CONFIG_CIFS_POSIX
2896
2897/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002898static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2899 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900{
2901 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002902 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2903 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2904 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002905 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
2907 return;
2908}
2909
2910/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002911static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2912 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913{
2914 int size = 0;
2915 int i;
2916 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002917 struct cifs_posix_ace *pACE;
2918 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2919 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920
2921 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2922 return -EOPNOTSUPP;
2923
Steve French790fe572007-07-07 19:25:05 +00002924 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 count = le16_to_cpu(cifs_acl->access_entry_count);
2926 pACE = &cifs_acl->ace_array[0];
2927 size = sizeof(struct cifs_posix_acl);
2928 size += sizeof(struct cifs_posix_ace) * count;
2929 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002930 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002931 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2932 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 return -EINVAL;
2934 }
Steve French790fe572007-07-07 19:25:05 +00002935 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 count = le16_to_cpu(cifs_acl->access_entry_count);
2937 size = sizeof(struct cifs_posix_acl);
2938 size += sizeof(struct cifs_posix_ace) * count;
2939/* skip past access ACEs to get to default ACEs */
2940 pACE = &cifs_acl->ace_array[count];
2941 count = le16_to_cpu(cifs_acl->default_entry_count);
2942 size += sizeof(struct cifs_posix_ace) * count;
2943 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002944 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 return -EINVAL;
2946 } else {
2947 /* illegal type */
2948 return -EINVAL;
2949 }
2950
2951 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002952 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002953 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002954 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 return -ERANGE;
2956 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002957 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002958 for (i = 0; i < count ; i++) {
2959 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2960 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 }
2962 }
2963 return size;
2964}
2965
Steve French50c2f752007-07-13 00:33:32 +00002966static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2967 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968{
2969 __u16 rc = 0; /* 0 = ACL converted ok */
2970
Steve Frenchff7feac2005-11-15 16:45:16 -08002971 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2972 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002974 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 /* Probably no need to le convert -1 on any arch but can not hurt */
2976 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002977 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002978 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002979 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 return rc;
2981}
2982
2983/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002984static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2985 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986{
2987 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002988 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2989 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 int count;
2991 int i;
2992
Steve French790fe572007-07-07 19:25:05 +00002993 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 return 0;
2995
2996 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002997 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002998 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002999 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003000 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003001 cFYI(1, "unknown POSIX ACL version %d",
3002 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 return 0;
3004 }
3005 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003006 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003007 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003008 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003009 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003011 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 return 0;
3013 }
Steve French50c2f752007-07-13 00:33:32 +00003014 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3016 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003017 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 /* ACE not converted */
3019 break;
3020 }
3021 }
Steve French790fe572007-07-07 19:25:05 +00003022 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3024 rc += sizeof(struct cifs_posix_acl);
3025 /* BB add check to make sure ACL does not overflow SMB */
3026 }
3027 return rc;
3028}
3029
3030int
3031CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003032 const unsigned char *searchName,
3033 char *acl_inf, const int buflen, const int acl_type,
3034 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035{
3036/* SMB_QUERY_POSIX_ACL */
3037 TRANSACTION2_QPI_REQ *pSMB = NULL;
3038 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3039 int rc = 0;
3040 int bytes_returned;
3041 int name_len;
3042 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003043
Joe Perchesb6b38f72010-04-21 03:50:45 +00003044 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
3046queryAclRetry:
3047 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3048 (void **) &pSMBr);
3049 if (rc)
3050 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003051
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3053 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003054 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003055 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 name_len++; /* trailing null */
3057 name_len *= 2;
3058 pSMB->FileName[name_len] = 0;
3059 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003060 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 name_len = strnlen(searchName, PATH_MAX);
3062 name_len++; /* trailing null */
3063 strncpy(pSMB->FileName, searchName, name_len);
3064 }
3065
3066 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3067 pSMB->TotalDataCount = 0;
3068 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003069 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 pSMB->MaxDataCount = cpu_to_le16(4000);
3071 pSMB->MaxSetupCount = 0;
3072 pSMB->Reserved = 0;
3073 pSMB->Flags = 0;
3074 pSMB->Timeout = 0;
3075 pSMB->Reserved2 = 0;
3076 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003077 offsetof(struct smb_com_transaction2_qpi_req,
3078 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003079 pSMB->DataCount = 0;
3080 pSMB->DataOffset = 0;
3081 pSMB->SetupCount = 1;
3082 pSMB->Reserved3 = 0;
3083 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3084 byte_count = params + 1 /* pad */ ;
3085 pSMB->TotalParameterCount = cpu_to_le16(params);
3086 pSMB->ParameterCount = pSMB->TotalParameterCount;
3087 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3088 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003089 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 pSMB->ByteCount = cpu_to_le16(byte_count);
3091
3092 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3093 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003094 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003096 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 } else {
3098 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003099
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003102 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 rc = -EIO; /* bad smb */
3104 else {
3105 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3106 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3107 rc = cifs_copy_posix_acl(acl_inf,
3108 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003109 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 }
3111 }
3112 cifs_buf_release(pSMB);
3113 if (rc == -EAGAIN)
3114 goto queryAclRetry;
3115 return rc;
3116}
3117
3118int
3119CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003120 const unsigned char *fileName,
3121 const char *local_acl, const int buflen,
3122 const int acl_type,
3123 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124{
3125 struct smb_com_transaction2_spi_req *pSMB = NULL;
3126 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3127 char *parm_data;
3128 int name_len;
3129 int rc = 0;
3130 int bytes_returned = 0;
3131 __u16 params, byte_count, data_count, param_offset, offset;
3132
Joe Perchesb6b38f72010-04-21 03:50:45 +00003133 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134setAclRetry:
3135 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003136 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 if (rc)
3138 return rc;
3139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3140 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003141 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003142 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 name_len++; /* trailing null */
3144 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003145 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 name_len = strnlen(fileName, PATH_MAX);
3147 name_len++; /* trailing null */
3148 strncpy(pSMB->FileName, fileName, name_len);
3149 }
3150 params = 6 + name_len;
3151 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003152 /* BB find max SMB size from sess */
3153 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003154 pSMB->MaxSetupCount = 0;
3155 pSMB->Reserved = 0;
3156 pSMB->Flags = 0;
3157 pSMB->Timeout = 0;
3158 pSMB->Reserved2 = 0;
3159 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003160 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 offset = param_offset + params;
3162 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3163 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3164
3165 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003166 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167
Steve French790fe572007-07-07 19:25:05 +00003168 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169 rc = -EOPNOTSUPP;
3170 goto setACLerrorExit;
3171 }
3172 pSMB->DataOffset = cpu_to_le16(offset);
3173 pSMB->SetupCount = 1;
3174 pSMB->Reserved3 = 0;
3175 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3176 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3177 byte_count = 3 /* pad */ + params + data_count;
3178 pSMB->DataCount = cpu_to_le16(data_count);
3179 pSMB->TotalDataCount = pSMB->DataCount;
3180 pSMB->ParameterCount = cpu_to_le16(params);
3181 pSMB->TotalParameterCount = pSMB->ParameterCount;
3182 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003183 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 pSMB->ByteCount = cpu_to_le16(byte_count);
3185 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003186 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003187 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003188 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189
3190setACLerrorExit:
3191 cifs_buf_release(pSMB);
3192 if (rc == -EAGAIN)
3193 goto setAclRetry;
3194 return rc;
3195}
3196
Steve Frenchf654bac2005-04-28 22:41:04 -07003197/* BB fix tabs in this function FIXME BB */
3198int
3199CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003200 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003201{
Steve French50c2f752007-07-13 00:33:32 +00003202 int rc = 0;
3203 struct smb_t2_qfi_req *pSMB = NULL;
3204 struct smb_t2_qfi_rsp *pSMBr = NULL;
3205 int bytes_returned;
3206 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003207
Joe Perchesb6b38f72010-04-21 03:50:45 +00003208 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003209 if (tcon == NULL)
3210 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003211
3212GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003213 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3214 (void **) &pSMBr);
3215 if (rc)
3216 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003217
Steve Frenchad7a2922008-02-07 23:25:02 +00003218 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003219 pSMB->t2.TotalDataCount = 0;
3220 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3221 /* BB find exact max data count below from sess structure BB */
3222 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3223 pSMB->t2.MaxSetupCount = 0;
3224 pSMB->t2.Reserved = 0;
3225 pSMB->t2.Flags = 0;
3226 pSMB->t2.Timeout = 0;
3227 pSMB->t2.Reserved2 = 0;
3228 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3229 Fid) - 4);
3230 pSMB->t2.DataCount = 0;
3231 pSMB->t2.DataOffset = 0;
3232 pSMB->t2.SetupCount = 1;
3233 pSMB->t2.Reserved3 = 0;
3234 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3235 byte_count = params + 1 /* pad */ ;
3236 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3237 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3238 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3239 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003240 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003241 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003242 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003243
Steve French790fe572007-07-07 19:25:05 +00003244 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3245 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3246 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003247 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003248 } else {
3249 /* decode response */
3250 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003251 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003252 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003253 /* If rc should we check for EOPNOSUPP and
3254 disable the srvino flag? or in caller? */
3255 rc = -EIO; /* bad smb */
3256 else {
3257 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3258 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3259 struct file_chattr_info *pfinfo;
3260 /* BB Do we need a cast or hash here ? */
3261 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003262 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003263 rc = -EIO;
3264 goto GetExtAttrOut;
3265 }
3266 pfinfo = (struct file_chattr_info *)
3267 (data_offset + (char *) &pSMBr->hdr.Protocol);
3268 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003269 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003270 }
3271 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003272GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003273 cifs_buf_release(pSMB);
3274 if (rc == -EAGAIN)
3275 goto GetExtAttrRetry;
3276 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003277}
3278
Steve Frenchf654bac2005-04-28 22:41:04 -07003279#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
Jeff Layton79df1ba2010-12-06 12:52:08 -05003281#ifdef CONFIG_CIFS_ACL
3282/*
3283 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3284 * all NT TRANSACTS that we init here have total parm and data under about 400
3285 * bytes (to fit in small cifs buffer size), which is the case so far, it
3286 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3287 * returned setup area) and MaxParameterCount (returned parms size) must be set
3288 * by caller
3289 */
3290static int
3291smb_init_nttransact(const __u16 sub_command, const int setup_count,
3292 const int parm_len, struct cifsTconInfo *tcon,
3293 void **ret_buf)
3294{
3295 int rc;
3296 __u32 temp_offset;
3297 struct smb_com_ntransact_req *pSMB;
3298
3299 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3300 (void **)&pSMB);
3301 if (rc)
3302 return rc;
3303 *ret_buf = (void *)pSMB;
3304 pSMB->Reserved = 0;
3305 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3306 pSMB->TotalDataCount = 0;
3307 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3308 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3309 pSMB->ParameterCount = pSMB->TotalParameterCount;
3310 pSMB->DataCount = pSMB->TotalDataCount;
3311 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3312 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3313 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3314 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3315 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3316 pSMB->SubCommand = cpu_to_le16(sub_command);
3317 return 0;
3318}
3319
3320static int
3321validate_ntransact(char *buf, char **ppparm, char **ppdata,
3322 __u32 *pparmlen, __u32 *pdatalen)
3323{
3324 char *end_of_smb;
3325 __u32 data_count, data_offset, parm_count, parm_offset;
3326 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003327 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003328
3329 *pdatalen = 0;
3330 *pparmlen = 0;
3331
3332 if (buf == NULL)
3333 return -EINVAL;
3334
3335 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3336
Jeff Layton820a8032011-05-04 08:05:26 -04003337 bcc = get_bcc(&pSMBr->hdr);
3338 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003339 (char *)&pSMBr->ByteCount;
3340
3341 data_offset = le32_to_cpu(pSMBr->DataOffset);
3342 data_count = le32_to_cpu(pSMBr->DataCount);
3343 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3344 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3345
3346 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3347 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3348
3349 /* should we also check that parm and data areas do not overlap? */
3350 if (*ppparm > end_of_smb) {
3351 cFYI(1, "parms start after end of smb");
3352 return -EINVAL;
3353 } else if (parm_count + *ppparm > end_of_smb) {
3354 cFYI(1, "parm end after end of smb");
3355 return -EINVAL;
3356 } else if (*ppdata > end_of_smb) {
3357 cFYI(1, "data starts after end of smb");
3358 return -EINVAL;
3359 } else if (data_count + *ppdata > end_of_smb) {
3360 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3361 *ppdata, data_count, (data_count + *ppdata),
3362 end_of_smb, pSMBr);
3363 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003364 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003365 cFYI(1, "parm count and data count larger than SMB");
3366 return -EINVAL;
3367 }
3368 *pdatalen = data_count;
3369 *pparmlen = parm_count;
3370 return 0;
3371}
3372
Steve French0a4b92c2006-01-12 15:44:21 -08003373/* Get Security Descriptor (by handle) from remote server for a file or dir */
3374int
3375CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f02007-10-25 21:17:17 +00003376 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003377{
3378 int rc = 0;
3379 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003380 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003381 struct kvec iov[1];
3382
Joe Perchesb6b38f72010-04-21 03:50:45 +00003383 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003384
Steve French630f3f02007-10-25 21:17:17 +00003385 *pbuflen = 0;
3386 *acl_inf = NULL;
3387
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003388 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003389 8 /* parm len */, tcon, (void **) &pSMB);
3390 if (rc)
3391 return rc;
3392
3393 pSMB->MaxParameterCount = cpu_to_le32(4);
3394 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3395 pSMB->MaxSetupCount = 0;
3396 pSMB->Fid = fid; /* file handle always le */
3397 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3398 CIFS_ACL_DACL);
3399 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003400 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003401 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003402 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003403
Steve Frencha761ac52007-10-18 21:45:27 +00003404 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003405 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003406 cifs_stats_inc(&tcon->num_acl_get);
3407 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003408 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003409 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003410 __le32 *parm;
Steve French630f3f02007-10-25 21:17:17 +00003411 __u32 parm_len;
3412 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003413 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f02007-10-25 21:17:17 +00003414 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003415
3416/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003417 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f02007-10-25 21:17:17 +00003418 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003419 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003420 goto qsec_out;
3421 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3422
Joe Perchesb6b38f72010-04-21 03:50:45 +00003423 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003424
3425 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3426 rc = -EIO; /* bad smb */
Steve French630f3f02007-10-25 21:17:17 +00003427 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003428 goto qsec_out;
3429 }
3430
3431/* BB check that data area is minimum length and as big as acl_len */
3432
Steve Frenchaf6f4612007-10-16 18:40:37 +00003433 acl_len = le32_to_cpu(*parm);
Steve French630f3f02007-10-25 21:17:17 +00003434 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003435 cERROR(1, "acl length %d does not match %d",
3436 acl_len, *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003437 if (*pbuflen > acl_len)
3438 *pbuflen = acl_len;
3439 }
Steve French0a4b92c2006-01-12 15:44:21 -08003440
Steve French630f3f02007-10-25 21:17:17 +00003441 /* check if buffer is big enough for the acl
3442 header followed by the smallest SID */
3443 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3444 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003445 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f02007-10-25 21:17:17 +00003446 rc = -EINVAL;
3447 *pbuflen = 0;
3448 } else {
3449 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3450 if (*acl_inf == NULL) {
3451 *pbuflen = 0;
3452 rc = -ENOMEM;
3453 }
3454 memcpy(*acl_inf, pdata, *pbuflen);
3455 }
Steve French0a4b92c2006-01-12 15:44:21 -08003456 }
3457qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003458 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003459 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003460 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003461 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003462/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003463 return rc;
3464}
Steve French97837582007-12-31 07:47:21 +00003465
3466int
3467CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3468 struct cifs_ntsd *pntsd, __u32 acllen)
3469{
3470 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3471 int rc = 0;
3472 int bytes_returned = 0;
3473 SET_SEC_DESC_REQ *pSMB = NULL;
3474 NTRANSACT_RSP *pSMBr = NULL;
3475
3476setCifsAclRetry:
3477 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3478 (void **) &pSMBr);
3479 if (rc)
3480 return (rc);
3481
3482 pSMB->MaxSetupCount = 0;
3483 pSMB->Reserved = 0;
3484
3485 param_count = 8;
3486 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3487 data_count = acllen;
3488 data_offset = param_offset + param_count;
3489 byte_count = 3 /* pad */ + param_count;
3490
3491 pSMB->DataCount = cpu_to_le32(data_count);
3492 pSMB->TotalDataCount = pSMB->DataCount;
3493 pSMB->MaxParameterCount = cpu_to_le32(4);
3494 pSMB->MaxDataCount = cpu_to_le32(16384);
3495 pSMB->ParameterCount = cpu_to_le32(param_count);
3496 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3497 pSMB->TotalParameterCount = pSMB->ParameterCount;
3498 pSMB->DataOffset = cpu_to_le32(data_offset);
3499 pSMB->SetupCount = 0;
3500 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3501 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3502
3503 pSMB->Fid = fid; /* file handle always le */
3504 pSMB->Reserved2 = 0;
3505 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3506
3507 if (pntsd && acllen) {
3508 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3509 (char *) pntsd,
3510 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003511 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003512 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003513 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003514
3515 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3516 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3517
Joe Perchesb6b38f72010-04-21 03:50:45 +00003518 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003519 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003520 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003521 cifs_buf_release(pSMB);
3522
3523 if (rc == -EAGAIN)
3524 goto setCifsAclRetry;
3525
3526 return (rc);
3527}
3528
Jeff Layton79df1ba2010-12-06 12:52:08 -05003529#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003530
Steve French6b8edfe2005-08-23 20:26:03 -07003531/* Legacy Query Path Information call for lookup to old servers such
3532 as Win9x/WinME */
3533int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003534 const unsigned char *searchName,
3535 FILE_ALL_INFO *pFinfo,
3536 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003537{
Steve Frenchad7a2922008-02-07 23:25:02 +00003538 QUERY_INFORMATION_REQ *pSMB;
3539 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003540 int rc = 0;
3541 int bytes_returned;
3542 int name_len;
3543
Joe Perchesb6b38f72010-04-21 03:50:45 +00003544 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003545QInfRetry:
3546 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003547 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003548 if (rc)
3549 return rc;
3550
3551 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3552 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003553 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3554 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003555 name_len++; /* trailing null */
3556 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003557 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003558 name_len = strnlen(searchName, PATH_MAX);
3559 name_len++; /* trailing null */
3560 strncpy(pSMB->FileName, searchName, name_len);
3561 }
3562 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003563 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003564 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003565 pSMB->ByteCount = cpu_to_le16(name_len);
3566
3567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003569 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003570 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003571 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003572 struct timespec ts;
3573 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003574
3575 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003576 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003577 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003578 ts.tv_nsec = 0;
3579 ts.tv_sec = time;
3580 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003581 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003582 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3583 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003584 pFinfo->AllocationSize =
3585 cpu_to_le64(le32_to_cpu(pSMBr->size));
3586 pFinfo->EndOfFile = pFinfo->AllocationSize;
3587 pFinfo->Attributes =
3588 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003589 } else
3590 rc = -EIO; /* bad buffer passed in */
3591
3592 cifs_buf_release(pSMB);
3593
3594 if (rc == -EAGAIN)
3595 goto QInfRetry;
3596
3597 return rc;
3598}
3599
Jeff Laytonbcd53572010-02-12 07:44:16 -05003600int
3601CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3602 u16 netfid, FILE_ALL_INFO *pFindData)
3603{
3604 struct smb_t2_qfi_req *pSMB = NULL;
3605 struct smb_t2_qfi_rsp *pSMBr = NULL;
3606 int rc = 0;
3607 int bytes_returned;
3608 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003609
Jeff Laytonbcd53572010-02-12 07:44:16 -05003610QFileInfoRetry:
3611 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3612 (void **) &pSMBr);
3613 if (rc)
3614 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003615
Jeff Laytonbcd53572010-02-12 07:44:16 -05003616 params = 2 /* level */ + 2 /* fid */;
3617 pSMB->t2.TotalDataCount = 0;
3618 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3619 /* BB find exact max data count below from sess structure BB */
3620 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3621 pSMB->t2.MaxSetupCount = 0;
3622 pSMB->t2.Reserved = 0;
3623 pSMB->t2.Flags = 0;
3624 pSMB->t2.Timeout = 0;
3625 pSMB->t2.Reserved2 = 0;
3626 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3627 Fid) - 4);
3628 pSMB->t2.DataCount = 0;
3629 pSMB->t2.DataOffset = 0;
3630 pSMB->t2.SetupCount = 1;
3631 pSMB->t2.Reserved3 = 0;
3632 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3633 byte_count = params + 1 /* pad */ ;
3634 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3635 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3636 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3637 pSMB->Pad = 0;
3638 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003639 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003640
3641 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3642 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3643 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003644 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003645 } else { /* decode response */
3646 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3647
3648 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3649 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003650 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003651 rc = -EIO; /* bad smb */
3652 else if (pFindData) {
3653 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3654 memcpy((char *) pFindData,
3655 (char *) &pSMBr->hdr.Protocol +
3656 data_offset, sizeof(FILE_ALL_INFO));
3657 } else
3658 rc = -ENOMEM;
3659 }
3660 cifs_buf_release(pSMB);
3661 if (rc == -EAGAIN)
3662 goto QFileInfoRetry;
3663
3664 return rc;
3665}
Steve French6b8edfe2005-08-23 20:26:03 -07003666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667int
3668CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3669 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003670 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003671 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003672 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673{
3674/* level 263 SMB_QUERY_FILE_ALL_INFO */
3675 TRANSACTION2_QPI_REQ *pSMB = NULL;
3676 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3677 int rc = 0;
3678 int bytes_returned;
3679 int name_len;
3680 __u16 params, byte_count;
3681
Joe Perchesb6b38f72010-04-21 03:50:45 +00003682/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683QPathInfoRetry:
3684 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3685 (void **) &pSMBr);
3686 if (rc)
3687 return rc;
3688
3689 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3690 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003691 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003692 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693 name_len++; /* trailing null */
3694 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003695 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 name_len = strnlen(searchName, PATH_MAX);
3697 name_len++; /* trailing null */
3698 strncpy(pSMB->FileName, searchName, name_len);
3699 }
3700
Steve French50c2f752007-07-13 00:33:32 +00003701 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 pSMB->TotalDataCount = 0;
3703 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003704 /* BB find exact max SMB PDU from sess structure BB */
3705 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 pSMB->MaxSetupCount = 0;
3707 pSMB->Reserved = 0;
3708 pSMB->Flags = 0;
3709 pSMB->Timeout = 0;
3710 pSMB->Reserved2 = 0;
3711 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003712 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 pSMB->DataCount = 0;
3714 pSMB->DataOffset = 0;
3715 pSMB->SetupCount = 1;
3716 pSMB->Reserved3 = 0;
3717 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3718 byte_count = params + 1 /* pad */ ;
3719 pSMB->TotalParameterCount = cpu_to_le16(params);
3720 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003721 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003722 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3723 else
3724 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003726 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003727 pSMB->ByteCount = cpu_to_le16(byte_count);
3728
3729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3731 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003732 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 } else { /* decode response */
3734 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3735
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003736 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3737 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003738 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003740 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003741 rc = -EIO; /* 24 or 26 expected but we do not read
3742 last field */
3743 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003744 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003746
3747 /* On legacy responses we do not read the last field,
3748 EAsize, fortunately since it varies by subdialect and
3749 also note it differs on Set vs. Get, ie two bytes or 4
3750 bytes depending but we don't care here */
3751 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003752 size = sizeof(FILE_INFO_STANDARD);
3753 else
3754 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 memcpy((char *) pFindData,
3756 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003757 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 } else
3759 rc = -ENOMEM;
3760 }
3761 cifs_buf_release(pSMB);
3762 if (rc == -EAGAIN)
3763 goto QPathInfoRetry;
3764
3765 return rc;
3766}
3767
3768int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003769CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3770 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3771{
3772 struct smb_t2_qfi_req *pSMB = NULL;
3773 struct smb_t2_qfi_rsp *pSMBr = NULL;
3774 int rc = 0;
3775 int bytes_returned;
3776 __u16 params, byte_count;
3777
3778UnixQFileInfoRetry:
3779 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3780 (void **) &pSMBr);
3781 if (rc)
3782 return rc;
3783
3784 params = 2 /* level */ + 2 /* fid */;
3785 pSMB->t2.TotalDataCount = 0;
3786 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3787 /* BB find exact max data count below from sess structure BB */
3788 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3789 pSMB->t2.MaxSetupCount = 0;
3790 pSMB->t2.Reserved = 0;
3791 pSMB->t2.Flags = 0;
3792 pSMB->t2.Timeout = 0;
3793 pSMB->t2.Reserved2 = 0;
3794 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3795 Fid) - 4);
3796 pSMB->t2.DataCount = 0;
3797 pSMB->t2.DataOffset = 0;
3798 pSMB->t2.SetupCount = 1;
3799 pSMB->t2.Reserved3 = 0;
3800 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3801 byte_count = params + 1 /* pad */ ;
3802 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3803 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3804 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3805 pSMB->Pad = 0;
3806 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003807 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003808
3809 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3811 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003812 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003813 } else { /* decode response */
3814 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3815
Jeff Layton820a8032011-05-04 08:05:26 -04003816 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003817 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003818 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003819 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003820 rc = -EIO; /* bad smb */
3821 } else {
3822 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3823 memcpy((char *) pFindData,
3824 (char *) &pSMBr->hdr.Protocol +
3825 data_offset,
3826 sizeof(FILE_UNIX_BASIC_INFO));
3827 }
3828 }
3829
3830 cifs_buf_release(pSMB);
3831 if (rc == -EAGAIN)
3832 goto UnixQFileInfoRetry;
3833
3834 return rc;
3835}
3836
3837int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3839 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003840 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003841 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003842{
3843/* SMB_QUERY_FILE_UNIX_BASIC */
3844 TRANSACTION2_QPI_REQ *pSMB = NULL;
3845 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3846 int rc = 0;
3847 int bytes_returned = 0;
3848 int name_len;
3849 __u16 params, byte_count;
3850
Joe Perchesb6b38f72010-04-21 03:50:45 +00003851 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852UnixQPathInfoRetry:
3853 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3854 (void **) &pSMBr);
3855 if (rc)
3856 return rc;
3857
3858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3859 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003860 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003861 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 name_len++; /* trailing null */
3863 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003864 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 name_len = strnlen(searchName, PATH_MAX);
3866 name_len++; /* trailing null */
3867 strncpy(pSMB->FileName, searchName, name_len);
3868 }
3869
Steve French50c2f752007-07-13 00:33:32 +00003870 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871 pSMB->TotalDataCount = 0;
3872 pSMB->MaxParameterCount = cpu_to_le16(2);
3873 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003874 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 pSMB->MaxSetupCount = 0;
3876 pSMB->Reserved = 0;
3877 pSMB->Flags = 0;
3878 pSMB->Timeout = 0;
3879 pSMB->Reserved2 = 0;
3880 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003881 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 pSMB->DataCount = 0;
3883 pSMB->DataOffset = 0;
3884 pSMB->SetupCount = 1;
3885 pSMB->Reserved3 = 0;
3886 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3887 byte_count = params + 1 /* pad */ ;
3888 pSMB->TotalParameterCount = cpu_to_le16(params);
3889 pSMB->ParameterCount = pSMB->TotalParameterCount;
3890 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3891 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003892 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 pSMB->ByteCount = cpu_to_le16(byte_count);
3894
3895 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3896 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3897 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003898 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 } else { /* decode response */
3900 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3901
Jeff Layton820a8032011-05-04 08:05:26 -04003902 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003903 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003904 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003905 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 rc = -EIO; /* bad smb */
3907 } else {
3908 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3909 memcpy((char *) pFindData,
3910 (char *) &pSMBr->hdr.Protocol +
3911 data_offset,
Steve French630f3f02007-10-25 21:17:17 +00003912 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 }
3914 }
3915 cifs_buf_release(pSMB);
3916 if (rc == -EAGAIN)
3917 goto UnixQPathInfoRetry;
3918
3919 return rc;
3920}
3921
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922/* xid, tcon, searchName and codepage are input parms, rest are returned */
3923int
3924CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003925 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003927 __u16 *pnetfid,
3928 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929{
3930/* level 257 SMB_ */
3931 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3932 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003933 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003934 int rc = 0;
3935 int bytes_returned = 0;
3936 int name_len;
3937 __u16 params, byte_count;
3938
Joe Perchesb6b38f72010-04-21 03:50:45 +00003939 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003940
3941findFirstRetry:
3942 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3943 (void **) &pSMBr);
3944 if (rc)
3945 return rc;
3946
3947 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3948 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003949 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003950 PATH_MAX, nls_codepage, remap);
3951 /* We can not add the asterik earlier in case
3952 it got remapped to 0xF03A as if it were part of the
3953 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003955 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003956 pSMB->FileName[name_len+1] = 0;
3957 pSMB->FileName[name_len+2] = '*';
3958 pSMB->FileName[name_len+3] = 0;
3959 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3961 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003962 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963 } else { /* BB add check for overrun of SMB buf BB */
3964 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003966 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 free buffer exit; BB */
3968 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003969 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003970 pSMB->FileName[name_len+1] = '*';
3971 pSMB->FileName[name_len+2] = 0;
3972 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 }
3974
3975 params = 12 + name_len /* includes null */ ;
3976 pSMB->TotalDataCount = 0; /* no EAs */
3977 pSMB->MaxParameterCount = cpu_to_le16(10);
3978 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3979 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3980 pSMB->MaxSetupCount = 0;
3981 pSMB->Reserved = 0;
3982 pSMB->Flags = 0;
3983 pSMB->Timeout = 0;
3984 pSMB->Reserved2 = 0;
3985 byte_count = params + 1 /* pad */ ;
3986 pSMB->TotalParameterCount = cpu_to_le16(params);
3987 pSMB->ParameterCount = pSMB->TotalParameterCount;
3988 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003989 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3990 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 pSMB->DataCount = 0;
3992 pSMB->DataOffset = 0;
3993 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3994 pSMB->Reserved3 = 0;
3995 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3996 pSMB->SearchAttributes =
3997 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3998 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003999 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4000 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 CIFS_SEARCH_RETURN_RESUME);
4002 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4003
4004 /* BB what should we set StorageType to? Does it matter? BB */
4005 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004006 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 pSMB->ByteCount = cpu_to_le16(byte_count);
4008
4009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004011 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012
Steve French88274812006-03-09 22:21:45 +00004013 if (rc) {/* BB add logic to retry regular search if Unix search
4014 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004016 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004017
Steve French88274812006-03-09 22:21:45 +00004018 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019
4020 /* BB eventually could optimize out free and realloc of buf */
4021 /* for this case */
4022 if (rc == -EAGAIN)
4023 goto findFirstRetry;
4024 } else { /* decode response */
4025 /* BB remember to free buffer if error BB */
4026 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004027 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004028 unsigned int lnoff;
4029
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004031 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 else
Steve French4b18f2a2008-04-29 00:06:05 +00004033 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034
4035 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004036 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004037 psrch_inf->srch_entries_start =
4038 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4041 le16_to_cpu(pSMBr->t2.ParameterOffset));
4042
Steve French790fe572007-07-07 19:25:05 +00004043 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004044 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 else
Steve French4b18f2a2008-04-29 00:06:05 +00004046 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047
Steve French50c2f752007-07-13 00:33:32 +00004048 psrch_inf->entries_in_buffer =
4049 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004050 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004052 lnoff = le16_to_cpu(parms->LastNameOffset);
4053 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4054 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004055 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004056 psrch_inf->last_entry = NULL;
4057 return rc;
4058 }
4059
Steve French0752f152008-10-07 20:03:33 +00004060 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004061 lnoff;
4062
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 *pnetfid = parms->SearchHandle;
4064 } else {
4065 cifs_buf_release(pSMB);
4066 }
4067 }
4068
4069 return rc;
4070}
4071
4072int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004073 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074{
4075 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4076 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004077 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 char *response_data;
4079 int rc = 0;
4080 int bytes_returned, name_len;
4081 __u16 params, byte_count;
4082
Joe Perchesb6b38f72010-04-21 03:50:45 +00004083 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084
Steve French4b18f2a2008-04-29 00:06:05 +00004085 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 return -ENOENT;
4087
4088 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4089 (void **) &pSMBr);
4090 if (rc)
4091 return rc;
4092
Steve French50c2f752007-07-13 00:33:32 +00004093 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 byte_count = 0;
4095 pSMB->TotalDataCount = 0; /* no EAs */
4096 pSMB->MaxParameterCount = cpu_to_le16(8);
4097 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00004098 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
4099 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 pSMB->MaxSetupCount = 0;
4101 pSMB->Reserved = 0;
4102 pSMB->Flags = 0;
4103 pSMB->Timeout = 0;
4104 pSMB->Reserved2 = 0;
4105 pSMB->ParameterOffset = cpu_to_le16(
4106 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4107 pSMB->DataCount = 0;
4108 pSMB->DataOffset = 0;
4109 pSMB->SetupCount = 1;
4110 pSMB->Reserved3 = 0;
4111 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4112 pSMB->SearchHandle = searchHandle; /* always kept as le */
4113 pSMB->SearchCount =
Steve French630f3f02007-10-25 21:17:17 +00004114 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4116 pSMB->ResumeKey = psrch_inf->resume_key;
4117 pSMB->SearchFlags =
4118 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4119
4120 name_len = psrch_inf->resume_name_len;
4121 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004122 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4124 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004125 /* 14 byte parm len above enough for 2 byte null terminator */
4126 pSMB->ResumeFileName[name_len] = 0;
4127 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 } else {
4129 rc = -EINVAL;
4130 goto FNext2_err_exit;
4131 }
4132 byte_count = params + 1 /* pad */ ;
4133 pSMB->TotalParameterCount = cpu_to_le16(params);
4134 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004135 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004137
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4139 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004140 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004141 if (rc) {
4142 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004143 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004144 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004145 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004147 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 } else { /* decode response */
4149 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004150
Steve French790fe572007-07-07 19:25:05 +00004151 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004152 unsigned int lnoff;
4153
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 /* BB fixme add lock for file (srch_info) struct here */
4155 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004156 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157 else
Steve French4b18f2a2008-04-29 00:06:05 +00004158 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 response_data = (char *) &pSMBr->hdr.Protocol +
4160 le16_to_cpu(pSMBr->t2.ParameterOffset);
4161 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4162 response_data = (char *)&pSMBr->hdr.Protocol +
4163 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004164 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004165 cifs_small_buf_release(
4166 psrch_inf->ntwrk_buf_start);
4167 else
4168 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 psrch_inf->srch_entries_start = response_data;
4170 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004171 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004172 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004173 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 else
Steve French4b18f2a2008-04-29 00:06:05 +00004175 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004176 psrch_inf->entries_in_buffer =
4177 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 psrch_inf->index_of_last_entry +=
4179 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004180 lnoff = le16_to_cpu(parms->LastNameOffset);
4181 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4182 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004183 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004184 psrch_inf->last_entry = NULL;
4185 return rc;
4186 } else
4187 psrch_inf->last_entry =
4188 psrch_inf->srch_entries_start + lnoff;
4189
Joe Perchesb6b38f72010-04-21 03:50:45 +00004190/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4191 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
4193 /* BB fixme add unlock here */
4194 }
4195
4196 }
4197
4198 /* BB On error, should we leave previous search buf (and count and
4199 last entry fields) intact or free the previous one? */
4200
4201 /* Note: On -EAGAIN error only caller can retry on handle based calls
4202 since file handle passed in no longer valid */
4203FNext2_err_exit:
4204 if (rc != 0)
4205 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 return rc;
4207}
4208
4209int
Steve French50c2f752007-07-13 00:33:32 +00004210CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
4211 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212{
4213 int rc = 0;
4214 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Joe Perchesb6b38f72010-04-21 03:50:45 +00004216 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4218
4219 /* no sense returning error if session restarted
4220 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004221 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222 return 0;
4223 if (rc)
4224 return rc;
4225
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 pSMB->FileID = searchHandle;
4227 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004228 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004229 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004230 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004231
Steve Frencha4544342005-08-24 13:59:35 -07004232 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233
4234 /* Since session is dead, search handle closed on server already */
4235 if (rc == -EAGAIN)
4236 rc = 0;
4237
4238 return rc;
4239}
4240
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241int
4242CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004243 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004244 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004245 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246{
4247 int rc = 0;
4248 TRANSACTION2_QPI_REQ *pSMB = NULL;
4249 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4250 int name_len, bytes_returned;
4251 __u16 params, byte_count;
4252
Joe Perchesb6b38f72010-04-21 03:50:45 +00004253 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004254 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004255 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256
4257GetInodeNumberRetry:
4258 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004259 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 if (rc)
4261 return rc;
4262
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4264 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004265 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004266 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 name_len++; /* trailing null */
4268 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004269 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 name_len = strnlen(searchName, PATH_MAX);
4271 name_len++; /* trailing null */
4272 strncpy(pSMB->FileName, searchName, name_len);
4273 }
4274
4275 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4276 pSMB->TotalDataCount = 0;
4277 pSMB->MaxParameterCount = cpu_to_le16(2);
4278 /* BB find exact max data count below from sess structure BB */
4279 pSMB->MaxDataCount = cpu_to_le16(4000);
4280 pSMB->MaxSetupCount = 0;
4281 pSMB->Reserved = 0;
4282 pSMB->Flags = 0;
4283 pSMB->Timeout = 0;
4284 pSMB->Reserved2 = 0;
4285 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004286 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 pSMB->DataCount = 0;
4288 pSMB->DataOffset = 0;
4289 pSMB->SetupCount = 1;
4290 pSMB->Reserved3 = 0;
4291 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4292 byte_count = params + 1 /* pad */ ;
4293 pSMB->TotalParameterCount = cpu_to_le16(params);
4294 pSMB->ParameterCount = pSMB->TotalParameterCount;
4295 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4296 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004297 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 pSMB->ByteCount = cpu_to_le16(byte_count);
4299
4300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4302 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004303 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 } else {
4305 /* decode response */
4306 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004308 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 /* If rc should we check for EOPNOSUPP and
4310 disable the srvino flag? or in caller? */
4311 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004312 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4314 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004315 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004317 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004318 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 rc = -EIO;
4320 goto GetInodeNumOut;
4321 }
4322 pfinfo = (struct file_internal_info *)
4323 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004324 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 }
4326 }
4327GetInodeNumOut:
4328 cifs_buf_release(pSMB);
4329 if (rc == -EAGAIN)
4330 goto GetInodeNumberRetry;
4331 return rc;
4332}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333
Igor Mammedovfec45852008-05-16 13:06:30 +04004334/* parses DFS refferal V3 structure
4335 * caller is responsible for freeing target_nodes
4336 * returns:
4337 * on success - 0
4338 * on failure - errno
4339 */
4340static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004341parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004342 unsigned int *num_of_nodes,
4343 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004344 const struct nls_table *nls_codepage, int remap,
4345 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004346{
4347 int i, rc = 0;
4348 char *data_end;
4349 bool is_unicode;
4350 struct dfs_referral_level_3 *ref;
4351
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004352 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4353 is_unicode = true;
4354 else
4355 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004356 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4357
4358 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004359 cERROR(1, "num_referrals: must be at least > 0,"
4360 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004361 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004362 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004363 }
4364
4365 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004366 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004367 cERROR(1, "Referrals of V%d version are not supported,"
4368 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004369 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004370 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004371 }
4372
4373 /* get the upper boundary of the resp buffer */
4374 data_end = (char *)(&(pSMBr->PathConsumed)) +
4375 le16_to_cpu(pSMBr->t2.DataCount);
4376
Steve Frenchf19159d2010-04-21 04:12:10 +00004377 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004378 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004379 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004380
4381 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4382 *num_of_nodes, GFP_KERNEL);
4383 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004384 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004385 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004386 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004387 }
4388
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004389 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004390 for (i = 0; i < *num_of_nodes; i++) {
4391 char *temp;
4392 int max_len;
4393 struct dfs_info3_param *node = (*target_nodes)+i;
4394
Steve French0e0d2cf2009-05-01 05:27:32 +00004395 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004396 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004397 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4398 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004399 if (tmp == NULL) {
4400 rc = -ENOMEM;
4401 goto parse_DFS_referrals_exit;
4402 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004403 cifsConvertToUCS((__le16 *) tmp, searchName,
4404 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004405 node->path_consumed = cifs_ucs2_bytes(tmp,
4406 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004407 nls_codepage);
4408 kfree(tmp);
4409 } else
4410 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4411
Igor Mammedovfec45852008-05-16 13:06:30 +04004412 node->server_type = le16_to_cpu(ref->ServerType);
4413 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4414
4415 /* copy DfsPath */
4416 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4417 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004418 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4419 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004420 if (!node->path_name) {
4421 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004422 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004423 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004424
4425 /* copy link target UNC */
4426 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4427 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004428 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4429 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004430 if (!node->node_name)
4431 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004432 }
4433
Steve Frencha1fe78f2008-05-16 18:48:38 +00004434parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004435 if (rc) {
4436 free_dfs_info_array(*target_nodes, *num_of_nodes);
4437 *target_nodes = NULL;
4438 *num_of_nodes = 0;
4439 }
4440 return rc;
4441}
4442
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443int
4444CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4445 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004446 struct dfs_info3_param **target_nodes,
4447 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004448 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449{
4450/* TRANS2_GET_DFS_REFERRAL */
4451 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4452 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 int rc = 0;
4454 int bytes_returned;
4455 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004457 *num_of_nodes = 0;
4458 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
Joe Perchesb6b38f72010-04-21 03:50:45 +00004460 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 if (ses == NULL)
4462 return -ENODEV;
4463getDFSRetry:
4464 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4465 (void **) &pSMBr);
4466 if (rc)
4467 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004468
4469 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004470 but should never be null here anyway */
4471 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 pSMB->hdr.Tid = ses->ipc_tid;
4473 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004474 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004476 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478
4479 if (ses->capabilities & CAP_UNICODE) {
4480 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4481 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004482 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004483 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 name_len++; /* trailing null */
4485 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004486 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 name_len = strnlen(searchName, PATH_MAX);
4488 name_len++; /* trailing null */
4489 strncpy(pSMB->RequestFileName, searchName, name_len);
4490 }
4491
Steve French790fe572007-07-07 19:25:05 +00004492 if (ses->server) {
4493 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004494 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4495 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4496 }
4497
Steve French50c2f752007-07-13 00:33:32 +00004498 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004499
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 params = 2 /* level */ + name_len /*includes null */ ;
4501 pSMB->TotalDataCount = 0;
4502 pSMB->DataCount = 0;
4503 pSMB->DataOffset = 0;
4504 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004505 /* BB find exact max SMB PDU from sess structure BB */
4506 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 pSMB->MaxSetupCount = 0;
4508 pSMB->Reserved = 0;
4509 pSMB->Flags = 0;
4510 pSMB->Timeout = 0;
4511 pSMB->Reserved2 = 0;
4512 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004513 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 pSMB->SetupCount = 1;
4515 pSMB->Reserved3 = 0;
4516 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4517 byte_count = params + 3 /* pad */ ;
4518 pSMB->ParameterCount = cpu_to_le16(params);
4519 pSMB->TotalParameterCount = pSMB->ParameterCount;
4520 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004521 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 pSMB->ByteCount = cpu_to_le16(byte_count);
4523
4524 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4525 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4526 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004527 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004528 goto GetDFSRefExit;
4529 }
4530 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004532 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004533 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004534 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004535 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004537
Joe Perchesb6b38f72010-04-21 03:50:45 +00004538 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004539 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004540 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004541
4542 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004543 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004544 target_nodes, nls_codepage, remap,
4545 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004546
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004548 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549
4550 if (rc == -EAGAIN)
4551 goto getDFSRetry;
4552
4553 return rc;
4554}
4555
Steve French20962432005-09-21 22:05:57 -07004556/* Query File System Info such as free space to old servers such as Win 9x */
4557int
4558SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4559{
4560/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4561 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4562 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4563 FILE_SYSTEM_ALLOC_INFO *response_data;
4564 int rc = 0;
4565 int bytes_returned = 0;
4566 __u16 params, byte_count;
4567
Joe Perchesb6b38f72010-04-21 03:50:45 +00004568 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004569oldQFSInfoRetry:
4570 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4571 (void **) &pSMBr);
4572 if (rc)
4573 return rc;
Steve French20962432005-09-21 22:05:57 -07004574
4575 params = 2; /* level */
4576 pSMB->TotalDataCount = 0;
4577 pSMB->MaxParameterCount = cpu_to_le16(2);
4578 pSMB->MaxDataCount = cpu_to_le16(1000);
4579 pSMB->MaxSetupCount = 0;
4580 pSMB->Reserved = 0;
4581 pSMB->Flags = 0;
4582 pSMB->Timeout = 0;
4583 pSMB->Reserved2 = 0;
4584 byte_count = params + 1 /* pad */ ;
4585 pSMB->TotalParameterCount = cpu_to_le16(params);
4586 pSMB->ParameterCount = pSMB->TotalParameterCount;
4587 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4588 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4589 pSMB->DataCount = 0;
4590 pSMB->DataOffset = 0;
4591 pSMB->SetupCount = 1;
4592 pSMB->Reserved3 = 0;
4593 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4594 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004595 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004596 pSMB->ByteCount = cpu_to_le16(byte_count);
4597
4598 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4599 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4600 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004601 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004602 } else { /* decode response */
4603 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4604
Jeff Layton820a8032011-05-04 08:05:26 -04004605 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004606 rc = -EIO; /* bad smb */
4607 else {
4608 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004609 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004610 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004611
Steve French50c2f752007-07-13 00:33:32 +00004612 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004613 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4614 FSData->f_bsize =
4615 le16_to_cpu(response_data->BytesPerSector) *
4616 le32_to_cpu(response_data->
4617 SectorsPerAllocationUnit);
4618 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004619 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004620 FSData->f_bfree = FSData->f_bavail =
4621 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004622 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4623 (unsigned long long)FSData->f_blocks,
4624 (unsigned long long)FSData->f_bfree,
4625 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004626 }
4627 }
4628 cifs_buf_release(pSMB);
4629
4630 if (rc == -EAGAIN)
4631 goto oldQFSInfoRetry;
4632
4633 return rc;
4634}
4635
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636int
Steve French737b7582005-04-28 22:41:06 -07004637CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638{
4639/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4640 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4641 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4642 FILE_SYSTEM_INFO *response_data;
4643 int rc = 0;
4644 int bytes_returned = 0;
4645 __u16 params, byte_count;
4646
Joe Perchesb6b38f72010-04-21 03:50:45 +00004647 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648QFSInfoRetry:
4649 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4650 (void **) &pSMBr);
4651 if (rc)
4652 return rc;
4653
4654 params = 2; /* level */
4655 pSMB->TotalDataCount = 0;
4656 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004657 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 pSMB->MaxSetupCount = 0;
4659 pSMB->Reserved = 0;
4660 pSMB->Flags = 0;
4661 pSMB->Timeout = 0;
4662 pSMB->Reserved2 = 0;
4663 byte_count = params + 1 /* pad */ ;
4664 pSMB->TotalParameterCount = cpu_to_le16(params);
4665 pSMB->ParameterCount = pSMB->TotalParameterCount;
4666 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004667 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 pSMB->DataCount = 0;
4669 pSMB->DataOffset = 0;
4670 pSMB->SetupCount = 1;
4671 pSMB->Reserved3 = 0;
4672 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4673 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004674 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 pSMB->ByteCount = cpu_to_le16(byte_count);
4676
4677 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4678 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4679 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004680 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004682 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683
Jeff Layton820a8032011-05-04 08:05:26 -04004684 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 rc = -EIO; /* bad smb */
4686 else {
4687 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688
4689 response_data =
4690 (FILE_SYSTEM_INFO
4691 *) (((char *) &pSMBr->hdr.Protocol) +
4692 data_offset);
4693 FSData->f_bsize =
4694 le32_to_cpu(response_data->BytesPerSector) *
4695 le32_to_cpu(response_data->
4696 SectorsPerAllocationUnit);
4697 FSData->f_blocks =
4698 le64_to_cpu(response_data->TotalAllocationUnits);
4699 FSData->f_bfree = FSData->f_bavail =
4700 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004701 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4702 (unsigned long long)FSData->f_blocks,
4703 (unsigned long long)FSData->f_bfree,
4704 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 }
4706 }
4707 cifs_buf_release(pSMB);
4708
4709 if (rc == -EAGAIN)
4710 goto QFSInfoRetry;
4711
4712 return rc;
4713}
4714
4715int
Steve French737b7582005-04-28 22:41:06 -07004716CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717{
4718/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4719 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4720 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4721 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4722 int rc = 0;
4723 int bytes_returned = 0;
4724 __u16 params, byte_count;
4725
Joe Perchesb6b38f72010-04-21 03:50:45 +00004726 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727QFSAttributeRetry:
4728 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4729 (void **) &pSMBr);
4730 if (rc)
4731 return rc;
4732
4733 params = 2; /* level */
4734 pSMB->TotalDataCount = 0;
4735 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004736 /* BB find exact max SMB PDU from sess structure BB */
4737 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 pSMB->MaxSetupCount = 0;
4739 pSMB->Reserved = 0;
4740 pSMB->Flags = 0;
4741 pSMB->Timeout = 0;
4742 pSMB->Reserved2 = 0;
4743 byte_count = params + 1 /* pad */ ;
4744 pSMB->TotalParameterCount = cpu_to_le16(params);
4745 pSMB->ParameterCount = pSMB->TotalParameterCount;
4746 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004747 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 pSMB->DataCount = 0;
4749 pSMB->DataOffset = 0;
4750 pSMB->SetupCount = 1;
4751 pSMB->Reserved3 = 0;
4752 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4753 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004754 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 pSMB->ByteCount = cpu_to_le16(byte_count);
4756
4757 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4758 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4759 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004760 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 } else { /* decode response */
4762 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4763
Jeff Layton820a8032011-05-04 08:05:26 -04004764 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004765 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 rc = -EIO; /* bad smb */
4767 } else {
4768 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4769 response_data =
4770 (FILE_SYSTEM_ATTRIBUTE_INFO
4771 *) (((char *) &pSMBr->hdr.Protocol) +
4772 data_offset);
4773 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004774 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775 }
4776 }
4777 cifs_buf_release(pSMB);
4778
4779 if (rc == -EAGAIN)
4780 goto QFSAttributeRetry;
4781
4782 return rc;
4783}
4784
4785int
Steve French737b7582005-04-28 22:41:06 -07004786CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787{
4788/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4789 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4790 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4791 FILE_SYSTEM_DEVICE_INFO *response_data;
4792 int rc = 0;
4793 int bytes_returned = 0;
4794 __u16 params, byte_count;
4795
Joe Perchesb6b38f72010-04-21 03:50:45 +00004796 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797QFSDeviceRetry:
4798 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4799 (void **) &pSMBr);
4800 if (rc)
4801 return rc;
4802
4803 params = 2; /* level */
4804 pSMB->TotalDataCount = 0;
4805 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004806 /* BB find exact max SMB PDU from sess structure BB */
4807 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 pSMB->MaxSetupCount = 0;
4809 pSMB->Reserved = 0;
4810 pSMB->Flags = 0;
4811 pSMB->Timeout = 0;
4812 pSMB->Reserved2 = 0;
4813 byte_count = params + 1 /* pad */ ;
4814 pSMB->TotalParameterCount = cpu_to_le16(params);
4815 pSMB->ParameterCount = pSMB->TotalParameterCount;
4816 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004817 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818
4819 pSMB->DataCount = 0;
4820 pSMB->DataOffset = 0;
4821 pSMB->SetupCount = 1;
4822 pSMB->Reserved3 = 0;
4823 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4824 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004825 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 pSMB->ByteCount = cpu_to_le16(byte_count);
4827
4828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4830 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004831 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 } else { /* decode response */
4833 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4834
Jeff Layton820a8032011-05-04 08:05:26 -04004835 if (rc || get_bcc(&pSMBr->hdr) <
4836 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 rc = -EIO; /* bad smb */
4838 else {
4839 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4840 response_data =
Steve French737b7582005-04-28 22:41:06 -07004841 (FILE_SYSTEM_DEVICE_INFO *)
4842 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843 data_offset);
4844 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004845 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846 }
4847 }
4848 cifs_buf_release(pSMB);
4849
4850 if (rc == -EAGAIN)
4851 goto QFSDeviceRetry;
4852
4853 return rc;
4854}
4855
4856int
Steve French737b7582005-04-28 22:41:06 -07004857CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858{
4859/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4860 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4861 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4862 FILE_SYSTEM_UNIX_INFO *response_data;
4863 int rc = 0;
4864 int bytes_returned = 0;
4865 __u16 params, byte_count;
4866
Joe Perchesb6b38f72010-04-21 03:50:45 +00004867 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004869 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4870 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 if (rc)
4872 return rc;
4873
4874 params = 2; /* level */
4875 pSMB->TotalDataCount = 0;
4876 pSMB->DataCount = 0;
4877 pSMB->DataOffset = 0;
4878 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004879 /* BB find exact max SMB PDU from sess structure BB */
4880 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 pSMB->MaxSetupCount = 0;
4882 pSMB->Reserved = 0;
4883 pSMB->Flags = 0;
4884 pSMB->Timeout = 0;
4885 pSMB->Reserved2 = 0;
4886 byte_count = params + 1 /* pad */ ;
4887 pSMB->ParameterCount = cpu_to_le16(params);
4888 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004889 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4890 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891 pSMB->SetupCount = 1;
4892 pSMB->Reserved3 = 0;
4893 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4894 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004895 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004896 pSMB->ByteCount = cpu_to_le16(byte_count);
4897
4898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4900 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004901 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 } else { /* decode response */
4903 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4904
Jeff Layton820a8032011-05-04 08:05:26 -04004905 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004906 rc = -EIO; /* bad smb */
4907 } else {
4908 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4909 response_data =
4910 (FILE_SYSTEM_UNIX_INFO
4911 *) (((char *) &pSMBr->hdr.Protocol) +
4912 data_offset);
4913 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004914 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 }
4916 }
4917 cifs_buf_release(pSMB);
4918
4919 if (rc == -EAGAIN)
4920 goto QFSUnixRetry;
4921
4922
4923 return rc;
4924}
4925
Jeremy Allisonac670552005-06-22 17:26:35 -07004926int
Steve French45abc6e2005-06-23 13:42:03 -05004927CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004928{
4929/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4930 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4931 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4932 int rc = 0;
4933 int bytes_returned = 0;
4934 __u16 params, param_offset, offset, byte_count;
4935
Joe Perchesb6b38f72010-04-21 03:50:45 +00004936 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004937SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004938 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004939 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4940 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004941 if (rc)
4942 return rc;
4943
4944 params = 4; /* 2 bytes zero followed by info level. */
4945 pSMB->MaxSetupCount = 0;
4946 pSMB->Reserved = 0;
4947 pSMB->Flags = 0;
4948 pSMB->Timeout = 0;
4949 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004950 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4951 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004952 offset = param_offset + params;
4953
4954 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004955 /* BB find exact max SMB PDU from sess structure BB */
4956 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004957 pSMB->SetupCount = 1;
4958 pSMB->Reserved3 = 0;
4959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4960 byte_count = 1 /* pad */ + params + 12;
4961
4962 pSMB->DataCount = cpu_to_le16(12);
4963 pSMB->ParameterCount = cpu_to_le16(params);
4964 pSMB->TotalDataCount = pSMB->DataCount;
4965 pSMB->TotalParameterCount = pSMB->ParameterCount;
4966 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4967 pSMB->DataOffset = cpu_to_le16(offset);
4968
4969 /* Params. */
4970 pSMB->FileNum = 0;
4971 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4972
4973 /* Data. */
4974 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4975 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4976 pSMB->ClientUnixCap = cpu_to_le64(cap);
4977
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004978 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004979 pSMB->ByteCount = cpu_to_le16(byte_count);
4980
4981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4983 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004984 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004985 } else { /* decode response */
4986 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004987 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004988 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004989 }
4990 cifs_buf_release(pSMB);
4991
4992 if (rc == -EAGAIN)
4993 goto SETFSUnixRetry;
4994
4995 return rc;
4996}
4997
4998
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999
5000int
5001CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07005002 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003{
5004/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5005 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5006 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5007 FILE_SYSTEM_POSIX_INFO *response_data;
5008 int rc = 0;
5009 int bytes_returned = 0;
5010 __u16 params, byte_count;
5011
Joe Perchesb6b38f72010-04-21 03:50:45 +00005012 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013QFSPosixRetry:
5014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5015 (void **) &pSMBr);
5016 if (rc)
5017 return rc;
5018
5019 params = 2; /* level */
5020 pSMB->TotalDataCount = 0;
5021 pSMB->DataCount = 0;
5022 pSMB->DataOffset = 0;
5023 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005024 /* BB find exact max SMB PDU from sess structure BB */
5025 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005026 pSMB->MaxSetupCount = 0;
5027 pSMB->Reserved = 0;
5028 pSMB->Flags = 0;
5029 pSMB->Timeout = 0;
5030 pSMB->Reserved2 = 0;
5031 byte_count = params + 1 /* pad */ ;
5032 pSMB->ParameterCount = cpu_to_le16(params);
5033 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005034 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5035 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005036 pSMB->SetupCount = 1;
5037 pSMB->Reserved3 = 0;
5038 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5039 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005040 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005041 pSMB->ByteCount = cpu_to_le16(byte_count);
5042
5043 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5044 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5045 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005046 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 } else { /* decode response */
5048 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5049
Jeff Layton820a8032011-05-04 08:05:26 -04005050 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005051 rc = -EIO; /* bad smb */
5052 } else {
5053 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5054 response_data =
5055 (FILE_SYSTEM_POSIX_INFO
5056 *) (((char *) &pSMBr->hdr.Protocol) +
5057 data_offset);
5058 FSData->f_bsize =
5059 le32_to_cpu(response_data->BlockSize);
5060 FSData->f_blocks =
5061 le64_to_cpu(response_data->TotalBlocks);
5062 FSData->f_bfree =
5063 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005064 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065 FSData->f_bavail = FSData->f_bfree;
5066 } else {
5067 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005068 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005069 }
Steve French790fe572007-07-07 19:25:05 +00005070 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005072 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005073 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005075 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 }
5077 }
5078 cifs_buf_release(pSMB);
5079
5080 if (rc == -EAGAIN)
5081 goto QFSPosixRetry;
5082
5083 return rc;
5084}
5085
5086
Steve French50c2f752007-07-13 00:33:32 +00005087/* We can not use write of zero bytes trick to
5088 set file size due to need for large file support. Also note that
5089 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005090 routine which is only needed to work around a sharing violation bug
5091 in Samba which this routine can run into */
5092
5093int
5094CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005095 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005096 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097{
5098 struct smb_com_transaction2_spi_req *pSMB = NULL;
5099 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5100 struct file_end_of_file_info *parm_data;
5101 int name_len;
5102 int rc = 0;
5103 int bytes_returned = 0;
5104 __u16 params, byte_count, data_count, param_offset, offset;
5105
Joe Perchesb6b38f72010-04-21 03:50:45 +00005106 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005107SetEOFRetry:
5108 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5109 (void **) &pSMBr);
5110 if (rc)
5111 return rc;
5112
5113 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5114 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005115 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005116 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005117 name_len++; /* trailing null */
5118 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005119 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 name_len = strnlen(fileName, PATH_MAX);
5121 name_len++; /* trailing null */
5122 strncpy(pSMB->FileName, fileName, name_len);
5123 }
5124 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005125 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005127 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005128 pSMB->MaxSetupCount = 0;
5129 pSMB->Reserved = 0;
5130 pSMB->Flags = 0;
5131 pSMB->Timeout = 0;
5132 pSMB->Reserved2 = 0;
5133 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005134 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005136 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005137 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5138 pSMB->InformationLevel =
5139 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5140 else
5141 pSMB->InformationLevel =
5142 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5143 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005144 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5145 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005146 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147 else
5148 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005149 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005150 }
5151
5152 parm_data =
5153 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5154 offset);
5155 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5156 pSMB->DataOffset = cpu_to_le16(offset);
5157 pSMB->SetupCount = 1;
5158 pSMB->Reserved3 = 0;
5159 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5160 byte_count = 3 /* pad */ + params + data_count;
5161 pSMB->DataCount = cpu_to_le16(data_count);
5162 pSMB->TotalDataCount = pSMB->DataCount;
5163 pSMB->ParameterCount = cpu_to_le16(params);
5164 pSMB->TotalParameterCount = pSMB->ParameterCount;
5165 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005166 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167 parm_data->FileSize = cpu_to_le64(size);
5168 pSMB->ByteCount = cpu_to_le16(byte_count);
5169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005171 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005172 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173
5174 cifs_buf_release(pSMB);
5175
5176 if (rc == -EAGAIN)
5177 goto SetEOFRetry;
5178
5179 return rc;
5180}
5181
5182int
Steve French50c2f752007-07-13 00:33:32 +00005183CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005184 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185{
5186 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 struct file_end_of_file_info *parm_data;
5188 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005189 __u16 params, param_offset, offset, byte_count, count;
5190
Joe Perchesb6b38f72010-04-21 03:50:45 +00005191 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5192 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005193 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5194
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 if (rc)
5196 return rc;
5197
5198 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5199 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005200
Linus Torvalds1da177e2005-04-16 15:20:36 -07005201 params = 6;
5202 pSMB->MaxSetupCount = 0;
5203 pSMB->Reserved = 0;
5204 pSMB->Flags = 0;
5205 pSMB->Timeout = 0;
5206 pSMB->Reserved2 = 0;
5207 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5208 offset = param_offset + params;
5209
Linus Torvalds1da177e2005-04-16 15:20:36 -07005210 count = sizeof(struct file_end_of_file_info);
5211 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005212 /* BB find exact max SMB PDU from sess structure BB */
5213 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005214 pSMB->SetupCount = 1;
5215 pSMB->Reserved3 = 0;
5216 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5217 byte_count = 3 /* pad */ + params + count;
5218 pSMB->DataCount = cpu_to_le16(count);
5219 pSMB->ParameterCount = cpu_to_le16(params);
5220 pSMB->TotalDataCount = pSMB->DataCount;
5221 pSMB->TotalParameterCount = pSMB->ParameterCount;
5222 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5223 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005224 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5225 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226 pSMB->DataOffset = cpu_to_le16(offset);
5227 parm_data->FileSize = cpu_to_le64(size);
5228 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005229 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5231 pSMB->InformationLevel =
5232 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5233 else
5234 pSMB->InformationLevel =
5235 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005236 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5238 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005239 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 else
5241 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005242 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 }
5244 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005245 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005246 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005247 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005248 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005249 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 }
5251
Steve French50c2f752007-07-13 00:33:32 +00005252 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 since file handle passed in no longer valid */
5254
5255 return rc;
5256}
5257
Steve French50c2f752007-07-13 00:33:32 +00005258/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 an open handle, rather than by pathname - this is awkward due to
5260 potential access conflicts on the open, but it is unavoidable for these
5261 old servers since the only other choice is to go from 100 nanosecond DCE
5262 time and resort to the original setpathinfo level which takes the ancient
5263 DOS time format with 2 second granularity */
5264int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005265CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5266 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267{
5268 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269 char *data_offset;
5270 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 __u16 params, param_offset, offset, byte_count, count;
5272
Joe Perchesb6b38f72010-04-21 03:50:45 +00005273 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005274 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5275
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 if (rc)
5277 return rc;
5278
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005279 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5280 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005281
Linus Torvalds1da177e2005-04-16 15:20:36 -07005282 params = 6;
5283 pSMB->MaxSetupCount = 0;
5284 pSMB->Reserved = 0;
5285 pSMB->Flags = 0;
5286 pSMB->Timeout = 0;
5287 pSMB->Reserved2 = 0;
5288 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5289 offset = param_offset + params;
5290
Steve French50c2f752007-07-13 00:33:32 +00005291 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292
Steve French26f57362007-08-30 22:09:15 +00005293 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005294 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005295 /* BB find max SMB PDU from sess */
5296 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 pSMB->SetupCount = 1;
5298 pSMB->Reserved3 = 0;
5299 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5300 byte_count = 3 /* pad */ + params + count;
5301 pSMB->DataCount = cpu_to_le16(count);
5302 pSMB->ParameterCount = cpu_to_le16(params);
5303 pSMB->TotalDataCount = pSMB->DataCount;
5304 pSMB->TotalParameterCount = pSMB->ParameterCount;
5305 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5306 pSMB->DataOffset = cpu_to_le16(offset);
5307 pSMB->Fid = fid;
5308 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5309 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5310 else
5311 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5312 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005313 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005315 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005316 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005317 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005318 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319
Steve French50c2f752007-07-13 00:33:32 +00005320 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 since file handle passed in no longer valid */
5322
5323 return rc;
5324}
5325
Jeff Layton6d22f092008-09-23 11:48:35 -04005326int
5327CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5328 bool delete_file, __u16 fid, __u32 pid_of_opener)
5329{
5330 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5331 char *data_offset;
5332 int rc = 0;
5333 __u16 params, param_offset, offset, byte_count, count;
5334
Joe Perchesb6b38f72010-04-21 03:50:45 +00005335 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005336 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5337
5338 if (rc)
5339 return rc;
5340
5341 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5342 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5343
5344 params = 6;
5345 pSMB->MaxSetupCount = 0;
5346 pSMB->Reserved = 0;
5347 pSMB->Flags = 0;
5348 pSMB->Timeout = 0;
5349 pSMB->Reserved2 = 0;
5350 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5351 offset = param_offset + params;
5352
5353 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5354
5355 count = 1;
5356 pSMB->MaxParameterCount = cpu_to_le16(2);
5357 /* BB find max SMB PDU from sess */
5358 pSMB->MaxDataCount = cpu_to_le16(1000);
5359 pSMB->SetupCount = 1;
5360 pSMB->Reserved3 = 0;
5361 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5362 byte_count = 3 /* pad */ + params + count;
5363 pSMB->DataCount = cpu_to_le16(count);
5364 pSMB->ParameterCount = cpu_to_le16(params);
5365 pSMB->TotalDataCount = pSMB->DataCount;
5366 pSMB->TotalParameterCount = pSMB->ParameterCount;
5367 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5368 pSMB->DataOffset = cpu_to_le16(offset);
5369 pSMB->Fid = fid;
5370 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5371 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005372 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005373 pSMB->ByteCount = cpu_to_le16(byte_count);
5374 *data_offset = delete_file ? 1 : 0;
5375 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5376 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005377 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005378
5379 return rc;
5380}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381
5382int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005383CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5384 const char *fileName, const FILE_BASIC_INFO *data,
5385 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386{
5387 TRANSACTION2_SPI_REQ *pSMB = NULL;
5388 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5389 int name_len;
5390 int rc = 0;
5391 int bytes_returned = 0;
5392 char *data_offset;
5393 __u16 params, param_offset, offset, byte_count, count;
5394
Joe Perchesb6b38f72010-04-21 03:50:45 +00005395 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005396
5397SetTimesRetry:
5398 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5399 (void **) &pSMBr);
5400 if (rc)
5401 return rc;
5402
5403 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5404 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005405 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005406 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 name_len++; /* trailing null */
5408 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005409 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005410 name_len = strnlen(fileName, PATH_MAX);
5411 name_len++; /* trailing null */
5412 strncpy(pSMB->FileName, fileName, name_len);
5413 }
5414
5415 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005416 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005418 /* BB find max SMB PDU from sess structure BB */
5419 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 pSMB->MaxSetupCount = 0;
5421 pSMB->Reserved = 0;
5422 pSMB->Flags = 0;
5423 pSMB->Timeout = 0;
5424 pSMB->Reserved2 = 0;
5425 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005426 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 offset = param_offset + params;
5428 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5429 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5430 pSMB->DataOffset = cpu_to_le16(offset);
5431 pSMB->SetupCount = 1;
5432 pSMB->Reserved3 = 0;
5433 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5434 byte_count = 3 /* pad */ + params + count;
5435
5436 pSMB->DataCount = cpu_to_le16(count);
5437 pSMB->ParameterCount = cpu_to_le16(params);
5438 pSMB->TotalDataCount = pSMB->DataCount;
5439 pSMB->TotalParameterCount = pSMB->ParameterCount;
5440 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5441 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5442 else
5443 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5444 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005445 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005446 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 pSMB->ByteCount = cpu_to_le16(byte_count);
5448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005450 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005451 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005452
5453 cifs_buf_release(pSMB);
5454
5455 if (rc == -EAGAIN)
5456 goto SetTimesRetry;
5457
5458 return rc;
5459}
5460
5461/* Can not be used to set time stamps yet (due to old DOS time format) */
5462/* Can be used to set attributes */
5463#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5464 handling it anyway and NT4 was what we thought it would be needed for
5465 Do not delete it until we prove whether needed for Win9x though */
5466int
5467CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5468 __u16 dos_attrs, const struct nls_table *nls_codepage)
5469{
5470 SETATTR_REQ *pSMB = NULL;
5471 SETATTR_RSP *pSMBr = NULL;
5472 int rc = 0;
5473 int bytes_returned;
5474 int name_len;
5475
Joe Perchesb6b38f72010-04-21 03:50:45 +00005476 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
5478SetAttrLgcyRetry:
5479 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5480 (void **) &pSMBr);
5481 if (rc)
5482 return rc;
5483
5484 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5485 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005486 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005487 PATH_MAX, nls_codepage);
5488 name_len++; /* trailing null */
5489 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005490 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 name_len = strnlen(fileName, PATH_MAX);
5492 name_len++; /* trailing null */
5493 strncpy(pSMB->fileName, fileName, name_len);
5494 }
5495 pSMB->attr = cpu_to_le16(dos_attrs);
5496 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005497 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005501 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005502 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503
5504 cifs_buf_release(pSMB);
5505
5506 if (rc == -EAGAIN)
5507 goto SetAttrLgcyRetry;
5508
5509 return rc;
5510}
5511#endif /* temporarily unneeded SetAttr legacy function */
5512
Jeff Layton654cf142009-07-09 20:02:49 -04005513static void
5514cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5515 const struct cifs_unix_set_info_args *args)
5516{
5517 u64 mode = args->mode;
5518
5519 /*
5520 * Samba server ignores set of file size to zero due to bugs in some
5521 * older clients, but we should be precise - we use SetFileSize to
5522 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005523 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005524 * zero instead of -1 here
5525 */
5526 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5527 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5528 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5529 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5530 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5531 data_offset->Uid = cpu_to_le64(args->uid);
5532 data_offset->Gid = cpu_to_le64(args->gid);
5533 /* better to leave device as zero when it is */
5534 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5535 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5536 data_offset->Permissions = cpu_to_le64(mode);
5537
5538 if (S_ISREG(mode))
5539 data_offset->Type = cpu_to_le32(UNIX_FILE);
5540 else if (S_ISDIR(mode))
5541 data_offset->Type = cpu_to_le32(UNIX_DIR);
5542 else if (S_ISLNK(mode))
5543 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5544 else if (S_ISCHR(mode))
5545 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5546 else if (S_ISBLK(mode))
5547 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5548 else if (S_ISFIFO(mode))
5549 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5550 else if (S_ISSOCK(mode))
5551 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5552}
5553
Linus Torvalds1da177e2005-04-16 15:20:36 -07005554int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005555CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5556 const struct cifs_unix_set_info_args *args,
5557 u16 fid, u32 pid_of_opener)
5558{
5559 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5560 FILE_UNIX_BASIC_INFO *data_offset;
5561 int rc = 0;
5562 u16 params, param_offset, offset, byte_count, count;
5563
Joe Perchesb6b38f72010-04-21 03:50:45 +00005564 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005565 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5566
5567 if (rc)
5568 return rc;
5569
5570 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5571 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5572
5573 params = 6;
5574 pSMB->MaxSetupCount = 0;
5575 pSMB->Reserved = 0;
5576 pSMB->Flags = 0;
5577 pSMB->Timeout = 0;
5578 pSMB->Reserved2 = 0;
5579 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5580 offset = param_offset + params;
5581
5582 data_offset = (FILE_UNIX_BASIC_INFO *)
5583 ((char *)(&pSMB->hdr.Protocol) + offset);
5584 count = sizeof(FILE_UNIX_BASIC_INFO);
5585
5586 pSMB->MaxParameterCount = cpu_to_le16(2);
5587 /* BB find max SMB PDU from sess */
5588 pSMB->MaxDataCount = cpu_to_le16(1000);
5589 pSMB->SetupCount = 1;
5590 pSMB->Reserved3 = 0;
5591 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5592 byte_count = 3 /* pad */ + params + count;
5593 pSMB->DataCount = cpu_to_le16(count);
5594 pSMB->ParameterCount = cpu_to_le16(params);
5595 pSMB->TotalDataCount = pSMB->DataCount;
5596 pSMB->TotalParameterCount = pSMB->ParameterCount;
5597 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5598 pSMB->DataOffset = cpu_to_le16(offset);
5599 pSMB->Fid = fid;
5600 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5601 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005602 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005603 pSMB->ByteCount = cpu_to_le16(byte_count);
5604
5605 cifs_fill_unix_set_info(data_offset, args);
5606
5607 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5608 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005609 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005610
5611 /* Note: On -EAGAIN error only caller can retry on handle based calls
5612 since file handle passed in no longer valid */
5613
5614 return rc;
5615}
5616
5617int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005618CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5619 const struct cifs_unix_set_info_args *args,
5620 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005621{
5622 TRANSACTION2_SPI_REQ *pSMB = NULL;
5623 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5624 int name_len;
5625 int rc = 0;
5626 int bytes_returned = 0;
5627 FILE_UNIX_BASIC_INFO *data_offset;
5628 __u16 params, param_offset, offset, count, byte_count;
5629
Joe Perchesb6b38f72010-04-21 03:50:45 +00005630 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005631setPermsRetry:
5632 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5633 (void **) &pSMBr);
5634 if (rc)
5635 return rc;
5636
5637 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5638 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005639 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005640 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005641 name_len++; /* trailing null */
5642 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005643 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005644 name_len = strnlen(fileName, PATH_MAX);
5645 name_len++; /* trailing null */
5646 strncpy(pSMB->FileName, fileName, name_len);
5647 }
5648
5649 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005650 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005652 /* BB find max SMB PDU from sess structure BB */
5653 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005654 pSMB->MaxSetupCount = 0;
5655 pSMB->Reserved = 0;
5656 pSMB->Flags = 0;
5657 pSMB->Timeout = 0;
5658 pSMB->Reserved2 = 0;
5659 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005660 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 offset = param_offset + params;
5662 data_offset =
5663 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5664 offset);
5665 memset(data_offset, 0, count);
5666 pSMB->DataOffset = cpu_to_le16(offset);
5667 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5668 pSMB->SetupCount = 1;
5669 pSMB->Reserved3 = 0;
5670 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5671 byte_count = 3 /* pad */ + params + count;
5672 pSMB->ParameterCount = cpu_to_le16(params);
5673 pSMB->DataCount = cpu_to_le16(count);
5674 pSMB->TotalParameterCount = pSMB->ParameterCount;
5675 pSMB->TotalDataCount = pSMB->DataCount;
5676 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5677 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005678 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005679
Jeff Layton654cf142009-07-09 20:02:49 -04005680 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005681
5682 pSMB->ByteCount = cpu_to_le16(byte_count);
5683 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005685 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005686 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005687
Steve French0d817bc2008-05-22 02:02:03 +00005688 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005689 if (rc == -EAGAIN)
5690 goto setPermsRetry;
5691 return rc;
5692}
5693
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005695/*
5696 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5697 * function used by listxattr and getxattr type calls. When ea_name is set,
5698 * it looks for that attribute name and stuffs that value into the EAData
5699 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5700 * buffer. In both cases, the return value is either the length of the
5701 * resulting data or a negative error code. If EAData is a NULL pointer then
5702 * the data isn't copied to it, but the length is returned.
5703 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005704ssize_t
5705CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005706 const unsigned char *searchName, const unsigned char *ea_name,
5707 char *EAData, size_t buf_size,
5708 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005709{
5710 /* BB assumes one setup word */
5711 TRANSACTION2_QPI_REQ *pSMB = NULL;
5712 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5713 int rc = 0;
5714 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005715 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005716 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005717 struct fea *temp_fea;
5718 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005719 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005720 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005721
Joe Perchesb6b38f72010-04-21 03:50:45 +00005722 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005723QAllEAsRetry:
5724 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5725 (void **) &pSMBr);
5726 if (rc)
5727 return rc;
5728
5729 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005730 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005731 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005732 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005733 list_len++; /* trailing null */
5734 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005735 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005736 list_len = strnlen(searchName, PATH_MAX);
5737 list_len++; /* trailing null */
5738 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005739 }
5740
Jeff Layton6e462b92010-02-10 16:18:26 -05005741 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 pSMB->TotalDataCount = 0;
5743 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005744 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005745 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 pSMB->MaxSetupCount = 0;
5747 pSMB->Reserved = 0;
5748 pSMB->Flags = 0;
5749 pSMB->Timeout = 0;
5750 pSMB->Reserved2 = 0;
5751 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005752 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 pSMB->DataCount = 0;
5754 pSMB->DataOffset = 0;
5755 pSMB->SetupCount = 1;
5756 pSMB->Reserved3 = 0;
5757 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5758 byte_count = params + 1 /* pad */ ;
5759 pSMB->TotalParameterCount = cpu_to_le16(params);
5760 pSMB->ParameterCount = pSMB->TotalParameterCount;
5761 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5762 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005763 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005764 pSMB->ByteCount = cpu_to_le16(byte_count);
5765
5766 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5767 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5768 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005769 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005770 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005772
5773
5774 /* BB also check enough total bytes returned */
5775 /* BB we need to improve the validity checking
5776 of these trans2 responses */
5777
5778 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005779 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005780 rc = -EIO; /* bad smb */
5781 goto QAllEAsOut;
5782 }
5783
5784 /* check that length of list is not more than bcc */
5785 /* check that each entry does not go beyond length
5786 of list */
5787 /* check that each element of each entry does not
5788 go beyond end of list */
5789 /* validate_trans2_offsets() */
5790 /* BB check if start of smb + data_offset > &bcc+ bcc */
5791
5792 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5793 ea_response_data = (struct fealist *)
5794 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5795
Jeff Layton6e462b92010-02-10 16:18:26 -05005796 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005797 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005798 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005799 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005800 goto QAllEAsOut;
5801 }
5802
Jeff Layton0cd126b2010-02-10 16:18:26 -05005803 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005804 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005805 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005806 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005807 rc = -EIO;
5808 goto QAllEAsOut;
5809 }
5810
Jeff Laytonf0d38682010-02-10 16:18:26 -05005811 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005812 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005813 temp_fea = ea_response_data->list;
5814 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005815 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005816 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005817 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005818
Jeff Layton6e462b92010-02-10 16:18:26 -05005819 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005820 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005821 /* make sure we can read name_len and value_len */
5822 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005823 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005824 rc = -EIO;
5825 goto QAllEAsOut;
5826 }
5827
5828 name_len = temp_fea->name_len;
5829 value_len = le16_to_cpu(temp_fea->value_len);
5830 list_len -= name_len + 1 + value_len;
5831 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005832 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005833 rc = -EIO;
5834 goto QAllEAsOut;
5835 }
5836
Jeff Layton31c05192010-02-10 16:18:26 -05005837 if (ea_name) {
5838 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5839 temp_ptr += name_len + 1;
5840 rc = value_len;
5841 if (buf_size == 0)
5842 goto QAllEAsOut;
5843 if ((size_t)value_len > buf_size) {
5844 rc = -ERANGE;
5845 goto QAllEAsOut;
5846 }
5847 memcpy(EAData, temp_ptr, value_len);
5848 goto QAllEAsOut;
5849 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005850 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005851 /* account for prefix user. and trailing null */
5852 rc += (5 + 1 + name_len);
5853 if (rc < (int) buf_size) {
5854 memcpy(EAData, "user.", 5);
5855 EAData += 5;
5856 memcpy(EAData, temp_ptr, name_len);
5857 EAData += name_len;
5858 /* null terminate name */
5859 *EAData = 0;
5860 ++EAData;
5861 } else if (buf_size == 0) {
5862 /* skip copy - calc size only */
5863 } else {
5864 /* stop before overrun buffer */
5865 rc = -ERANGE;
5866 break;
5867 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005868 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005869 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005870 temp_fea = (struct fea *)temp_ptr;
5871 }
5872
Jeff Layton31c05192010-02-10 16:18:26 -05005873 /* didn't find the named attribute */
5874 if (ea_name)
5875 rc = -ENODATA;
5876
Jeff Laytonf0d38682010-02-10 16:18:26 -05005877QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005878 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005879 if (rc == -EAGAIN)
5880 goto QAllEAsRetry;
5881
5882 return (ssize_t)rc;
5883}
5884
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885int
5886CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005887 const char *ea_name, const void *ea_value,
5888 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5889 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005890{
5891 struct smb_com_transaction2_spi_req *pSMB = NULL;
5892 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5893 struct fealist *parm_data;
5894 int name_len;
5895 int rc = 0;
5896 int bytes_returned = 0;
5897 __u16 params, param_offset, byte_count, offset, count;
5898
Joe Perchesb6b38f72010-04-21 03:50:45 +00005899 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900SetEARetry:
5901 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5902 (void **) &pSMBr);
5903 if (rc)
5904 return rc;
5905
5906 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5907 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005908 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005909 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005910 name_len++; /* trailing null */
5911 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005912 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913 name_len = strnlen(fileName, PATH_MAX);
5914 name_len++; /* trailing null */
5915 strncpy(pSMB->FileName, fileName, name_len);
5916 }
5917
5918 params = 6 + name_len;
5919
5920 /* done calculating parms using name_len of file name,
5921 now use name_len to calculate length of ea name
5922 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005923 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005924 name_len = 0;
5925 else
Steve French50c2f752007-07-13 00:33:32 +00005926 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005927
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005928 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005929 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005930 /* BB find max SMB PDU from sess */
5931 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005932 pSMB->MaxSetupCount = 0;
5933 pSMB->Reserved = 0;
5934 pSMB->Flags = 0;
5935 pSMB->Timeout = 0;
5936 pSMB->Reserved2 = 0;
5937 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005938 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 offset = param_offset + params;
5940 pSMB->InformationLevel =
5941 cpu_to_le16(SMB_SET_FILE_EA);
5942
5943 parm_data =
5944 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5945 offset);
5946 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5947 pSMB->DataOffset = cpu_to_le16(offset);
5948 pSMB->SetupCount = 1;
5949 pSMB->Reserved3 = 0;
5950 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5951 byte_count = 3 /* pad */ + params + count;
5952 pSMB->DataCount = cpu_to_le16(count);
5953 parm_data->list_len = cpu_to_le32(count);
5954 parm_data->list[0].EA_flags = 0;
5955 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005956 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005957 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005958 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005959 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005960 parm_data->list[0].name[name_len] = 0;
5961 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5962 /* caller ensures that ea_value_len is less than 64K but
5963 we need to ensure that it fits within the smb */
5964
Steve French50c2f752007-07-13 00:33:32 +00005965 /*BB add length check to see if it would fit in
5966 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005967 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5968 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005969 memcpy(parm_data->list[0].name+name_len+1,
5970 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005971
5972 pSMB->TotalDataCount = pSMB->DataCount;
5973 pSMB->ParameterCount = cpu_to_le16(params);
5974 pSMB->TotalParameterCount = pSMB->ParameterCount;
5975 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005976 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005977 pSMB->ByteCount = cpu_to_le16(byte_count);
5978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005980 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005981 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005982
5983 cifs_buf_release(pSMB);
5984
5985 if (rc == -EAGAIN)
5986 goto SetEARetry;
5987
5988 return rc;
5989}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005990#endif
Steve French0eff0e22011-02-24 05:39:23 +00005991
5992#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
5993/*
5994 * Years ago the kernel added a "dnotify" function for Samba server,
5995 * to allow network clients (such as Windows) to display updated
5996 * lists of files in directory listings automatically when
5997 * files are added by one user when another user has the
5998 * same directory open on their desktop. The Linux cifs kernel
5999 * client hooked into the kernel side of this interface for
6000 * the same reason, but ironically when the VFS moved from
6001 * "dnotify" to "inotify" it became harder to plug in Linux
6002 * network file system clients (the most obvious use case
6003 * for notify interfaces is when multiple users can update
6004 * the contents of the same directory - exactly what network
6005 * file systems can do) although the server (Samba) could
6006 * still use it. For the short term we leave the worker
6007 * function ifdeffed out (below) until inotify is fixed
6008 * in the VFS to make it easier to plug in network file
6009 * system clients. If inotify turns out to be permanently
6010 * incompatible for network fs clients, we could instead simply
6011 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6012 */
6013int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
6014 const int notify_subdirs, const __u16 netfid,
6015 __u32 filter, struct file *pfile, int multishot,
6016 const struct nls_table *nls_codepage)
6017{
6018 int rc = 0;
6019 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6020 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6021 struct dir_notify_req *dnotify_req;
6022 int bytes_returned;
6023
6024 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6025 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6026 (void **) &pSMBr);
6027 if (rc)
6028 return rc;
6029
6030 pSMB->TotalParameterCount = 0 ;
6031 pSMB->TotalDataCount = 0;
6032 pSMB->MaxParameterCount = cpu_to_le32(2);
6033 /* BB find exact data count max from sess structure BB */
6034 pSMB->MaxDataCount = 0; /* same in little endian or be */
6035/* BB VERIFY verify which is correct for above BB */
6036 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
6037 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
6038
6039 pSMB->MaxSetupCount = 4;
6040 pSMB->Reserved = 0;
6041 pSMB->ParameterOffset = 0;
6042 pSMB->DataCount = 0;
6043 pSMB->DataOffset = 0;
6044 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6045 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6046 pSMB->ParameterCount = pSMB->TotalParameterCount;
6047 if (notify_subdirs)
6048 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6049 pSMB->Reserved2 = 0;
6050 pSMB->CompletionFilter = cpu_to_le32(filter);
6051 pSMB->Fid = netfid; /* file handle always le */
6052 pSMB->ByteCount = 0;
6053
6054 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6055 (struct smb_hdr *)pSMBr, &bytes_returned,
6056 CIFS_ASYNC_OP);
6057 if (rc) {
6058 cFYI(1, "Error in Notify = %d", rc);
6059 } else {
6060 /* Add file to outstanding requests */
6061 /* BB change to kmem cache alloc */
6062 dnotify_req = kmalloc(
6063 sizeof(struct dir_notify_req),
6064 GFP_KERNEL);
6065 if (dnotify_req) {
6066 dnotify_req->Pid = pSMB->hdr.Pid;
6067 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6068 dnotify_req->Mid = pSMB->hdr.Mid;
6069 dnotify_req->Tid = pSMB->hdr.Tid;
6070 dnotify_req->Uid = pSMB->hdr.Uid;
6071 dnotify_req->netfid = netfid;
6072 dnotify_req->pfile = pfile;
6073 dnotify_req->filter = filter;
6074 dnotify_req->multishot = multishot;
6075 spin_lock(&GlobalMid_Lock);
6076 list_add_tail(&dnotify_req->lhead,
6077 &GlobalDnotifyReqList);
6078 spin_unlock(&GlobalMid_Lock);
6079 } else
6080 rc = -ENOMEM;
6081 }
6082 cifs_buf_release(pSMB);
6083 return rc;
6084}
6085#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */