blob: 19fd8158bb470351f326f456e857accf09295af7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchf19159d2010-04-21 04:12:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2010
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/posix_acl_xattr.h>
Jeff Laytonc28c89f2011-05-19 16:22:56 -040035#include <linux/pagemap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/uaccess.h>
37#include "cifspdu.h"
38#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000039#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "cifsproto.h"
41#include "cifs_unicode.h"
42#include "cifs_debug.h"
43
44#ifdef CONFIG_CIFS_POSIX
45static struct {
46 int index;
47 char *name;
48} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000049#ifdef CONFIG_CIFS_WEAK_PW_HASH
50 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000051 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000052#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000053 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000054 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 {BAD_PROT, "\2"}
56};
57#else
58static struct {
59 int index;
60 char *name;
61} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000062#ifdef CONFIG_CIFS_WEAK_PW_HASH
63 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000064 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000065#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000066 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 {BAD_PROT, "\2"}
68};
69#endif
70
Steve French39798772006-05-31 22:40:51 +000071/* define the number of elements in the cifs dialect array */
72#ifdef CONFIG_CIFS_POSIX
73#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000074#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000075#else
76#define CIFS_NUM_PROT 2
77#endif /* CIFS_WEAK_PW_HASH */
78#else /* not posix */
79#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000080#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000081#else
82#define CIFS_NUM_PROT 1
83#endif /* CONFIG_CIFS_WEAK_PW_HASH */
84#endif /* CIFS_POSIX */
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086/* Mark as invalid, all open files on tree connections since they
87 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000088static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
90 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000091 struct list_head *tmp;
92 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94/* list all files open on tree connection and mark them invalid */
Jeff Layton44772882010-10-15 15:34:03 -040095 spin_lock(&cifs_file_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000097 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000098 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040099 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 }
Jeff Layton44772882010-10-15 15:34:03 -0400101 spin_unlock(&cifs_file_list_lock);
Steve French09d1db52005-04-28 22:41:08 -0700102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
Jeff Layton9162ab22009-09-03 12:07:17 -0400106/* reconnect the socket, tcon, and smb session if needed */
107static int
108cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
109{
110 int rc = 0;
111 struct cifsSesInfo *ses;
112 struct TCP_Server_Info *server;
113 struct nls_table *nls_codepage;
114
115 /*
116 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
117 * tcp and smb session status done differently for those three - in the
118 * calling routine
119 */
120 if (!tcon)
121 return 0;
122
123 ses = tcon->ses;
124 server = ses->server;
125
126 /*
127 * only tree disconnect, open, and write, (and ulogoff which does not
128 * have tcon) are allowed as we start force umount
129 */
130 if (tcon->tidStatus == CifsExiting) {
131 if (smb_command != SMB_COM_WRITE_ANDX &&
132 smb_command != SMB_COM_OPEN_ANDX &&
133 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000134 cFYI(1, "can not send cmd %d while umounting",
135 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400136 return -ENODEV;
137 }
138 }
139
Jeff Layton9162ab22009-09-03 12:07:17 -0400140 /*
141 * Give demultiplex thread up to 10 seconds to reconnect, should be
142 * greater than cifs socket timeout which is 7 seconds
143 */
144 while (server->tcpStatus == CifsNeedReconnect) {
145 wait_event_interruptible_timeout(server->response_q,
Steve Frenchfd88ce92011-04-12 01:01:14 +0000146 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
Jeff Layton9162ab22009-09-03 12:07:17 -0400147
Steve Frenchfd88ce92011-04-12 01:01:14 +0000148 /* are we still trying to reconnect? */
Jeff Layton9162ab22009-09-03 12:07:17 -0400149 if (server->tcpStatus != CifsNeedReconnect)
150 break;
151
152 /*
153 * on "soft" mounts we wait once. Hard mounts keep
154 * retrying until process is killed or server comes
155 * back on-line
156 */
Jeff Laytond4025392011-02-07 08:54:35 -0500157 if (!tcon->retry) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000158 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400159 return -EHOSTDOWN;
160 }
161 }
162
163 if (!ses->need_reconnect && !tcon->need_reconnect)
164 return 0;
165
166 nls_codepage = load_nls_default();
167
168 /*
169 * need to prevent multiple threads trying to simultaneously
170 * reconnect the same SMB session
171 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000172 mutex_lock(&ses->session_mutex);
Jeff Layton198b5682010-04-24 07:57:48 -0400173 rc = cifs_negotiate_protocol(0, ses);
174 if (rc == 0 && ses->need_reconnect)
Jeff Layton9162ab22009-09-03 12:07:17 -0400175 rc = cifs_setup_session(0, ses, nls_codepage);
176
177 /* do we need to reconnect tcon? */
178 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000179 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400180 goto out;
181 }
182
183 mark_open_files_invalid(tcon);
184 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000185 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000186 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400187
188 if (rc)
189 goto out;
190
191 /*
192 * FIXME: check if wsize needs updated due to negotiated smb buffer
193 * size shrinking
194 */
195 atomic_inc(&tconInfoReconnectCount);
196
197 /* tell server Unix caps we support */
198 if (ses->capabilities & CAP_UNIX)
199 reset_cifs_unix_caps(0, tcon, NULL, NULL);
200
201 /*
202 * Removed call to reopen open files here. It is safer (and faster) to
203 * reopen files one at a time as needed in read and write.
204 *
205 * FIXME: what about file locks? don't we need to reclaim them ASAP?
206 */
207
208out:
209 /*
210 * Check if handle based operation so we know whether we can continue
211 * or not without returning to caller to reset file handle
212 */
213 switch (smb_command) {
214 case SMB_COM_READ_ANDX:
215 case SMB_COM_WRITE_ANDX:
216 case SMB_COM_CLOSE:
217 case SMB_COM_FIND_CLOSE2:
218 case SMB_COM_LOCKING_ANDX:
219 rc = -EAGAIN;
220 }
221
222 unload_nls(nls_codepage);
223 return rc;
224}
225
Steve Frenchad7a2922008-02-07 23:25:02 +0000226/* Allocate and return pointer to an SMB request buffer, and set basic
227 SMB information in the SMB header. If the return code is zero, this
228 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229static int
230small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000231 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232{
Jeff Laytonf5695992010-09-29 15:27:08 -0400233 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Jeff Layton9162ab22009-09-03 12:07:17 -0400235 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000236 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return rc;
238
239 *request_buf = cifs_small_buf_get();
240 if (*request_buf == NULL) {
241 /* BB should we add a retry in here if not a writepage? */
242 return -ENOMEM;
243 }
244
Steve French63135e02007-07-17 17:34:02 +0000245 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000246 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Steve French790fe572007-07-07 19:25:05 +0000248 if (tcon != NULL)
249 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700250
Jeff Laytonf5695992010-09-29 15:27:08 -0400251 return 0;
Steve French5815449d2006-02-14 01:36:20 +0000252}
253
Steve French12b3b8f2006-02-09 21:12:47 +0000254int
Steve French50c2f752007-07-13 00:33:32 +0000255small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000256 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000257{
258 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000259 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000260
Steve French5815449d2006-02-14 01:36:20 +0000261 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000262 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000263 return rc;
264
Steve French04fdabe2006-02-10 05:52:50 +0000265 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000266 buffer->Mid = GetNextMid(ses->server);
267 if (ses->capabilities & CAP_UNICODE)
268 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000269 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000270 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
271
272 /* uid, tid can stay at zero as set in header assemble */
273
Steve French50c2f752007-07-13 00:33:32 +0000274 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000275 this function is used after 1st of session setup requests */
276
277 return rc;
278}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
280/* If the return code is zero, this function must fill in request_buf pointer */
281static int
Jeff Laytonf5695992010-09-29 15:27:08 -0400282__smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
283 void **request_buf, void **response_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 *request_buf = cifs_buf_get();
286 if (*request_buf == NULL) {
287 /* BB should we add a retry in here if not a writepage? */
288 return -ENOMEM;
289 }
290 /* Although the original thought was we needed the response buf for */
291 /* potential retries of smb operations it turns out we can determine */
292 /* from the mid flags when the request buffer can be resent without */
293 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000294 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000295 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000298 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
Steve French790fe572007-07-07 19:25:05 +0000300 if (tcon != NULL)
301 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700302
Jeff Laytonf5695992010-09-29 15:27:08 -0400303 return 0;
304}
305
306/* If the return code is zero, this function must fill in request_buf pointer */
307static int
308smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
309 void **request_buf, void **response_buf)
310{
311 int rc;
312
313 rc = cifs_reconnect_tcon(tcon, smb_command);
314 if (rc)
315 return rc;
316
317 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
318}
319
320static int
321smb_init_no_reconnect(int smb_command, int wct, struct cifsTconInfo *tcon,
322 void **request_buf, void **response_buf)
323{
324 if (tcon->ses->need_reconnect || tcon->need_reconnect)
325 return -EHOSTDOWN;
326
327 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328}
329
Steve French50c2f752007-07-13 00:33:32 +0000330static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
Jeff Layton12df83c2011-01-20 13:36:51 -0500332 unsigned int total_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Jeff Layton12df83c2011-01-20 13:36:51 -0500334 /* check for plausible wct */
335 if (pSMB->hdr.WordCount < 10)
336 goto vt2_err;
337
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 /* check for parm and data offset going beyond end of smb */
Jeff Layton12df83c2011-01-20 13:36:51 -0500339 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
340 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
341 goto vt2_err;
342
Jeff Layton12df83c2011-01-20 13:36:51 -0500343 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
344 if (total_size >= 512)
345 goto vt2_err;
346
Jeff Laytonfd5707e2011-03-31 17:22:07 -0400347 /* check that bcc is at least as big as parms + data, and that it is
348 * less than negotiated smb buffer
349 */
Jeff Layton12df83c2011-01-20 13:36:51 -0500350 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
351 if (total_size > get_bcc(&pSMB->hdr) ||
352 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
353 goto vt2_err;
354
355 return 0;
356vt2_err:
Steve French50c2f752007-07-13 00:33:32 +0000357 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 sizeof(struct smb_t2_rsp) + 16);
Jeff Layton12df83c2011-01-20 13:36:51 -0500359 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
Jeff Layton690c5222011-01-20 13:36:51 -0500361
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000362static inline void inc_rfc1001_len(void *pSMB, int count)
363{
364 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
365
366 be32_add_cpu(&hdr->smb_buf_length, count);
367}
368
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369int
370CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
371{
372 NEGOTIATE_REQ *pSMB;
373 NEGOTIATE_RSP *pSMBr;
374 int rc = 0;
375 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000376 int i;
Steve French50c2f752007-07-13 00:33:32 +0000377 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000379 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
Steve French790fe572007-07-07 19:25:05 +0000381 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 server = ses->server;
383 else {
384 rc = -EIO;
385 return rc;
386 }
387 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
388 (void **) &pSMB, (void **) &pSMBr);
389 if (rc)
390 return rc;
Steve French750d1152006-06-27 06:28:30 +0000391
392 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000393 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000394 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000395 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400396 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000397
Joe Perchesb6b38f72010-04-21 03:50:45 +0000398 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000399
Steve French1982c342005-08-17 12:38:22 -0700400 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000401 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000402
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000403 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000404 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000405 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000406 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000407 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Jeff Laytonb4d6fcf2011-01-07 11:30:28 -0500408 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
Steve Frenchac683922009-05-06 04:16:04 +0000409 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
410 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000411 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000412 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
413 }
Steve French50c2f752007-07-13 00:33:32 +0000414
Steve French39798772006-05-31 22:40:51 +0000415 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000416 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000417 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
418 count += strlen(protocols[i].name) + 1;
419 /* null at end of source and target buffers anyway */
420 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000421 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 pSMB->ByteCount = cpu_to_le16(count);
423
424 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
425 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000426 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000427 goto neg_err_exit;
428
Jeff Layton9bf67e52010-04-24 07:57:46 -0400429 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
430 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000431 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400432 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000433 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000434 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000435 could not negotiate a common dialect */
436 rc = -EOPNOTSUPP;
437 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000438#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000439 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400440 && ((server->dialect == LANMAN_PROT)
441 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000442 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000443 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000444
Steve French790fe572007-07-07 19:25:05 +0000445 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000446 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000447 server->secType = LANMAN;
448 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000449 cERROR(1, "mount failed weak security disabled"
450 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000451 rc = -EOPNOTSUPP;
452 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000453 }
Steve French254e55e2006-06-04 05:53:15 +0000454 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
455 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
456 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000457 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000458 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000459 /* even though we do not use raw we might as well set this
460 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000461 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000462 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000463 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
464 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000465 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000466 server->capabilities = CAP_MPX_MODE;
467 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000468 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000469 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000470 /* OS/2 often does not set timezone therefore
471 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000472 * Could deviate slightly from the right zone.
473 * Smallest defined timezone difference is 15 minutes
474 * (i.e. Nepal). Rounding up/down is done to match
475 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000476 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000477 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000478 struct timespec ts, utc;
479 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400480 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
481 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000482 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000483 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000484 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000485 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000486 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000487 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000488 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000489 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000490 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000491 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000492 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000494 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000495 server->timeAdj = (int)tmp;
496 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000497 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000498 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000499
Steve French39798772006-05-31 22:40:51 +0000500
Steve French254e55e2006-06-04 05:53:15 +0000501 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000502 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000503
Steve French50c2f752007-07-13 00:33:32 +0000504 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000505 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500506 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000507 CIFS_CRYPTO_KEY_SIZE);
508 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
509 rc = -EIO; /* need cryptkey unless plain text */
510 goto neg_err_exit;
511 }
Steve French39798772006-05-31 22:40:51 +0000512
Steve Frenchf19159d2010-04-21 04:12:10 +0000513 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000514 /* we will not end up setting signing flags - as no signing
515 was in LANMAN and server did not return the flags on */
516 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000517#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000518 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000519 cERROR(1, "mount failed, cifs module not built "
520 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300521 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000522#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000523 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000524 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000525 /* unknown wct */
526 rc = -EOPNOTSUPP;
527 goto neg_err_exit;
528 }
529 /* else wct == 17 NTLM */
530 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000531 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000532 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000533
Steve French790fe572007-07-07 19:25:05 +0000534 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000535#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000536 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000537#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000538 cERROR(1, "Server requests plain text password"
539 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000540
Steve French790fe572007-07-07 19:25:05 +0000541 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000542 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000543 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000544 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000545 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000546 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000547 else if (secFlags & CIFSSEC_MAY_KRB5)
548 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000549 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000550 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000551 else if (secFlags & CIFSSEC_MAY_LANMAN)
552 server->secType = LANMAN;
Steve Frencha0136892007-10-04 20:05:09 +0000553 else {
554 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000555 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000556 goto neg_err_exit;
557 }
558 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000559
Steve French254e55e2006-06-04 05:53:15 +0000560 /* one byte, so no need to convert this or EncryptionKeyLen from
561 little endian */
562 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
563 /* probably no need to store and check maxvcs */
564 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000566 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000567 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000568 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000569 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
570 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000571 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
Shirish Pargaonkard3ba50b2010-10-27 15:20:36 -0500572 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
Steve French254e55e2006-06-04 05:53:15 +0000573 CIFS_CRYPTO_KEY_SIZE);
574 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
575 && (pSMBr->EncryptionKeyLength == 0)) {
576 /* decode security blob */
577 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
578 rc = -EIO; /* no crypt key only if plain text pwd */
579 goto neg_err_exit;
580 }
581
582 /* BB might be helpful to save off the domain of server here */
583
Steve French50c2f752007-07-13 00:33:32 +0000584 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000585 (server->capabilities & CAP_EXTENDED_SECURITY)) {
Jeff Layton820a8032011-05-04 08:05:26 -0400586 count = get_bcc(&pSMBr->hdr);
Jeff Laytone187e442007-10-16 17:10:44 +0000587 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000589 goto neg_err_exit;
590 }
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530591 spin_lock(&cifs_tcp_ses_lock);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500592 if (server->srv_count > 1) {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530593 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000594 if (memcmp(server->server_GUID,
595 pSMBr->u.extended_response.
596 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000597 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000598 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000599 pSMBr->u.extended_response.GUID,
600 16);
601 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500602 } else {
Suresh Jayaraman3f9bcca2010-10-18 23:29:37 +0530603 spin_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000604 memcpy(server->server_GUID,
605 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500606 }
Jeff Laytone187e442007-10-16 17:10:44 +0000607
608 if (count == 16) {
609 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000610 } else {
611 rc = decode_negTokenInit(pSMBr->u.extended_response.
Jeff Layton26efa0b2010-04-24 07:57:49 -0400612 SecurityBlob, count - 16,
613 server);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000614 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000615 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000616 else
Steve French254e55e2006-06-04 05:53:15 +0000617 rc = -EINVAL;
Shirish Pargaonkar2b149f12010-09-18 22:02:18 -0500618 if (server->secType == Kerberos) {
619 if (!server->sec_kerberos &&
620 !server->sec_mskerberos)
621 rc = -EOPNOTSUPP;
622 } else if (server->secType == RawNTLMSSP) {
623 if (!server->sec_ntlmssp)
624 rc = -EOPNOTSUPP;
625 } else
626 rc = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Steve French254e55e2006-06-04 05:53:15 +0000628 } else
629 server->capabilities &= ~CAP_EXTENDED_SECURITY;
630
Steve French6344a422006-06-12 04:18:35 +0000631#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000632signing_check:
Steve French6344a422006-06-12 04:18:35 +0000633#endif
Steve French762e5ab2007-06-28 18:41:42 +0000634 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
635 /* MUST_SIGN already includes the MAY_SIGN FLAG
636 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000637 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000638 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000639 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000640 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000641 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000642 rc = -EOPNOTSUPP;
643 }
Steve French50c2f752007-07-13 00:33:32 +0000644 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
647 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000648 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000649 if ((server->secMode &
650 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000651 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000652 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000653 } else
654 server->secMode |= SECMODE_SIGN_REQUIRED;
655 } else {
656 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000657 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000658 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000659 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 }
Steve French50c2f752007-07-13 00:33:32 +0000661
662neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700663 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000664
Joe Perchesb6b38f72010-04-21 03:50:45 +0000665 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 return rc;
667}
668
669int
670CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
671{
672 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Joe Perchesb6b38f72010-04-21 03:50:45 +0000675 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500676
677 /* BB: do we need to check this? These should never be NULL. */
678 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
679 return -EIO;
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500682 * No need to return error on this operation if tid invalidated and
683 * closed on server already e.g. due to tcp session crashing. Also,
684 * the tcon is no longer on the list, so no need to take lock before
685 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 */
Steve French268875b2009-06-25 00:29:21 +0000687 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000688 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
Steve French50c2f752007-07-13 00:33:32 +0000690 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700691 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500692 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return rc;
Steve French133672e2007-11-13 22:41:37 +0000694
695 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000697 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
Steve French50c2f752007-07-13 00:33:32 +0000699 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500700 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 if (rc == -EAGAIN)
702 rc = 0;
703
704 return rc;
705}
706
Jeff Layton766fdbb2011-01-11 07:24:21 -0500707/*
708 * This is a no-op for now. We're not really interested in the reply, but
709 * rather in the fact that the server sent one and that server->lstrp
710 * gets updated.
711 *
712 * FIXME: maybe we should consider checking that the reply matches request?
713 */
714static void
715cifs_echo_callback(struct mid_q_entry *mid)
716{
717 struct TCP_Server_Info *server = mid->callback_data;
718
719 DeleteMidQEntry(mid);
720 atomic_dec(&server->inFlight);
721 wake_up(&server->request_q);
722}
723
724int
725CIFSSMBEcho(struct TCP_Server_Info *server)
726{
727 ECHO_REQ *smb;
728 int rc = 0;
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400729 struct kvec iov;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500730
731 cFYI(1, "In echo request");
732
733 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
734 if (rc)
735 return rc;
736
737 /* set up echo request */
Steve French5443d132011-03-13 05:08:25 +0000738 smb->hdr.Tid = 0xffff;
Jeff Layton99d86c8f2011-01-20 21:19:25 -0500739 smb->hdr.WordCount = 1;
740 put_unaligned_le16(1, &smb->EchoCount);
Jeff Layton820a8032011-05-04 08:05:26 -0400741 put_bcc(1, &smb->hdr);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500742 smb->Data[0] = 'a';
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000743 inc_rfc1001_len(smb, 3);
Jeff Laytonfcc31cb2011-05-19 16:22:53 -0400744 iov.iov_base = smb;
745 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
Jeff Layton766fdbb2011-01-11 07:24:21 -0500746
Jeff Layton59ffd842011-05-19 16:22:55 -0400747 rc = cifs_call_async(server, &iov, 1, cifs_echo_callback, server, true);
Jeff Layton766fdbb2011-01-11 07:24:21 -0500748 if (rc)
749 cFYI(1, "Echo request failed: %d", rc);
750
751 cifs_small_buf_release(smb);
752
753 return rc;
754}
755
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756int
757CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
758{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 LOGOFF_ANDX_REQ *pSMB;
760 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Joe Perchesb6b38f72010-04-21 03:50:45 +0000762 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500763
764 /*
765 * BB: do we need to check validity of ses and server? They should
766 * always be valid since we have an active reference. If not, that
767 * should probably be a BUG()
768 */
769 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return -EIO;
771
Steve Frenchd7b619c2010-02-25 05:36:46 +0000772 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000773 if (ses->need_reconnect)
774 goto session_already_dead; /* no need to send SMBlogoff if uid
775 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
777 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000778 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 return rc;
780 }
781
Steve French3b795212008-11-13 19:45:32 +0000782 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700783
Steve French3b795212008-11-13 19:45:32 +0000784 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
786 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 pSMB->hdr.Uid = ses->Suid;
789
790 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000791 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000792session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000793 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000796 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 error */
798 if (rc == -EAGAIN)
799 rc = 0;
800 return rc;
801}
802
803int
Steve French2d785a52007-07-15 01:48:57 +0000804CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
805 __u16 type, const struct nls_table *nls_codepage, int remap)
806{
807 TRANSACTION2_SPI_REQ *pSMB = NULL;
808 TRANSACTION2_SPI_RSP *pSMBr = NULL;
809 struct unlink_psx_rq *pRqD;
810 int name_len;
811 int rc = 0;
812 int bytes_returned = 0;
813 __u16 params, param_offset, offset, byte_count;
814
Joe Perchesb6b38f72010-04-21 03:50:45 +0000815 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000816PsxDelete:
817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
818 (void **) &pSMBr);
819 if (rc)
820 return rc;
821
822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
823 name_len =
824 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
825 PATH_MAX, nls_codepage, remap);
826 name_len++; /* trailing null */
827 name_len *= 2;
828 } else { /* BB add path length overrun check */
829 name_len = strnlen(fileName, PATH_MAX);
830 name_len++; /* trailing null */
831 strncpy(pSMB->FileName, fileName, name_len);
832 }
833
834 params = 6 + name_len;
835 pSMB->MaxParameterCount = cpu_to_le16(2);
836 pSMB->MaxDataCount = 0; /* BB double check this with jra */
837 pSMB->MaxSetupCount = 0;
838 pSMB->Reserved = 0;
839 pSMB->Flags = 0;
840 pSMB->Timeout = 0;
841 pSMB->Reserved2 = 0;
842 param_offset = offsetof(struct smb_com_transaction2_spi_req,
843 InformationLevel) - 4;
844 offset = param_offset + params;
845
846 /* Setup pointer to Request Data (inode type) */
847 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
848 pRqD->type = cpu_to_le16(type);
849 pSMB->ParameterOffset = cpu_to_le16(param_offset);
850 pSMB->DataOffset = cpu_to_le16(offset);
851 pSMB->SetupCount = 1;
852 pSMB->Reserved3 = 0;
853 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
854 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
855
856 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
857 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
858 pSMB->ParameterCount = cpu_to_le16(params);
859 pSMB->TotalParameterCount = pSMB->ParameterCount;
860 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
861 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000862 inc_rfc1001_len(pSMB, byte_count);
Steve French2d785a52007-07-15 01:48:57 +0000863 pSMB->ByteCount = cpu_to_le16(byte_count);
864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000866 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000867 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000868 cifs_buf_release(pSMB);
869
870 cifs_stats_inc(&tcon->num_deletes);
871
872 if (rc == -EAGAIN)
873 goto PsxDelete;
874
875 return rc;
876}
877
878int
Steve French737b7582005-04-28 22:41:06 -0700879CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
880 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881{
882 DELETE_FILE_REQ *pSMB = NULL;
883 DELETE_FILE_RSP *pSMBr = NULL;
884 int rc = 0;
885 int bytes_returned;
886 int name_len;
887
888DelFileRetry:
889 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
890 (void **) &pSMBr);
891 if (rc)
892 return rc;
893
894 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
895 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000896 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700897 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 name_len++; /* trailing null */
899 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700900 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 name_len = strnlen(fileName, PATH_MAX);
902 name_len++; /* trailing null */
903 strncpy(pSMB->fileName, fileName, name_len);
904 }
905 pSMB->SearchAttributes =
906 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
907 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000908 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 pSMB->ByteCount = cpu_to_le16(name_len + 1);
910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700912 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000913 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000914 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 cifs_buf_release(pSMB);
917 if (rc == -EAGAIN)
918 goto DelFileRetry;
919
920 return rc;
921}
922
923int
Steve French50c2f752007-07-13 00:33:32 +0000924CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
927 DELETE_DIRECTORY_REQ *pSMB = NULL;
928 DELETE_DIRECTORY_RSP *pSMBr = NULL;
929 int rc = 0;
930 int bytes_returned;
931 int name_len;
932
Joe Perchesb6b38f72010-04-21 03:50:45 +0000933 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934RmDirRetry:
935 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
936 (void **) &pSMBr);
937 if (rc)
938 return rc;
939
940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700941 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
942 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 name_len++; /* trailing null */
944 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700945 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 name_len = strnlen(dirName, PATH_MAX);
947 name_len++; /* trailing null */
948 strncpy(pSMB->DirName, dirName, name_len);
949 }
950
951 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000952 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 pSMB->ByteCount = cpu_to_le16(name_len + 1);
954 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
955 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700956 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000957 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000958 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
960 cifs_buf_release(pSMB);
961 if (rc == -EAGAIN)
962 goto RmDirRetry;
963 return rc;
964}
965
966int
967CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700968 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 int rc = 0;
971 CREATE_DIRECTORY_REQ *pSMB = NULL;
972 CREATE_DIRECTORY_RSP *pSMBr = NULL;
973 int bytes_returned;
974 int name_len;
975
Joe Perchesb6b38f72010-04-21 03:50:45 +0000976 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977MkDirRetry:
978 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
979 (void **) &pSMBr);
980 if (rc)
981 return rc;
982
983 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000984 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700985 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 name_len++; /* trailing null */
987 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700988 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 name_len = strnlen(name, PATH_MAX);
990 name_len++; /* trailing null */
991 strncpy(pSMB->DirName, name, name_len);
992 }
993
994 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +0000995 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 pSMB->ByteCount = cpu_to_le16(name_len + 1);
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700999 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +00001000 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001001 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07001002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 cifs_buf_release(pSMB);
1004 if (rc == -EAGAIN)
1005 goto MkDirRetry;
1006 return rc;
1007}
1008
Steve French2dd29d32007-04-23 22:07:35 +00001009int
1010CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +00001011 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001012 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001013 const struct nls_table *nls_codepage, int remap)
1014{
1015 TRANSACTION2_SPI_REQ *pSMB = NULL;
1016 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1017 int name_len;
1018 int rc = 0;
1019 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001020 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +00001021 OPEN_PSX_REQ *pdata;
1022 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +00001023
Joe Perchesb6b38f72010-04-21 03:50:45 +00001024 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +00001025PsxCreat:
1026 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1027 (void **) &pSMBr);
1028 if (rc)
1029 return rc;
1030
1031 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1032 name_len =
1033 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1034 PATH_MAX, nls_codepage, remap);
1035 name_len++; /* trailing null */
1036 name_len *= 2;
1037 } else { /* BB improve the check for buffer overruns BB */
1038 name_len = strnlen(name, PATH_MAX);
1039 name_len++; /* trailing null */
1040 strncpy(pSMB->FileName, name, name_len);
1041 }
1042
1043 params = 6 + name_len;
1044 count = sizeof(OPEN_PSX_REQ);
1045 pSMB->MaxParameterCount = cpu_to_le16(2);
1046 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1047 pSMB->MaxSetupCount = 0;
1048 pSMB->Reserved = 0;
1049 pSMB->Flags = 0;
1050 pSMB->Timeout = 0;
1051 pSMB->Reserved2 = 0;
1052 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001053 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001054 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001055 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001056 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001057 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001058 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001059 pdata->OpenFlags = cpu_to_le32(*pOplock);
1060 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1061 pSMB->DataOffset = cpu_to_le16(offset);
1062 pSMB->SetupCount = 1;
1063 pSMB->Reserved3 = 0;
1064 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1065 byte_count = 3 /* pad */ + params + count;
1066
1067 pSMB->DataCount = cpu_to_le16(count);
1068 pSMB->ParameterCount = cpu_to_le16(params);
1069 pSMB->TotalDataCount = pSMB->DataCount;
1070 pSMB->TotalParameterCount = pSMB->ParameterCount;
1071 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1072 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001073 inc_rfc1001_len(pSMB, byte_count);
Steve French2dd29d32007-04-23 22:07:35 +00001074 pSMB->ByteCount = cpu_to_le16(byte_count);
1075 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1076 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1077 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001078 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001079 goto psx_create_err;
1080 }
1081
Joe Perchesb6b38f72010-04-21 03:50:45 +00001082 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001083 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1084
Jeff Layton820a8032011-05-04 08:05:26 -04001085 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
Steve French2dd29d32007-04-23 22:07:35 +00001086 rc = -EIO; /* bad smb */
1087 goto psx_create_err;
1088 }
1089
1090 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001091 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001092 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001093
Steve French2dd29d32007-04-23 22:07:35 +00001094 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001095 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001096 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1097 /* Let caller know file was created so we can set the mode. */
1098 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001099 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001100 *pOplock |= CIFS_CREATE_ACTION;
1101 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001102 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1103 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001104 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001105 } else {
Jeff Layton820a8032011-05-04 08:05:26 -04001106 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001107 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001108 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001109 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001110 goto psx_create_err;
1111 }
Steve French50c2f752007-07-13 00:33:32 +00001112 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001114 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001115 }
Steve French2dd29d32007-04-23 22:07:35 +00001116
1117psx_create_err:
1118 cifs_buf_release(pSMB);
1119
Steve French65bc98b2009-07-10 15:27:25 +00001120 if (posix_flags & SMB_O_DIRECTORY)
1121 cifs_stats_inc(&tcon->num_posixmkdirs);
1122 else
1123 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001124
1125 if (rc == -EAGAIN)
1126 goto PsxCreat;
1127
Steve French50c2f752007-07-13 00:33:32 +00001128 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001129}
1130
Steve Frencha9d02ad2005-08-24 23:06:05 -07001131static __u16 convert_disposition(int disposition)
1132{
1133 __u16 ofun = 0;
1134
1135 switch (disposition) {
1136 case FILE_SUPERSEDE:
1137 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1138 break;
1139 case FILE_OPEN:
1140 ofun = SMBOPEN_OAPPEND;
1141 break;
1142 case FILE_CREATE:
1143 ofun = SMBOPEN_OCREATE;
1144 break;
1145 case FILE_OPEN_IF:
1146 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1147 break;
1148 case FILE_OVERWRITE:
1149 ofun = SMBOPEN_OTRUNC;
1150 break;
1151 case FILE_OVERWRITE_IF:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1153 break;
1154 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001155 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156 ofun = SMBOPEN_OAPPEND; /* regular open */
1157 }
1158 return ofun;
1159}
1160
Jeff Layton35fc37d2008-05-14 10:22:03 -07001161static int
1162access_flags_to_smbopen_mode(const int access_flags)
1163{
1164 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1165
1166 if (masked_flags == GENERIC_READ)
1167 return SMBOPEN_READ;
1168 else if (masked_flags == GENERIC_WRITE)
1169 return SMBOPEN_WRITE;
1170
1171 /* just go for read/write */
1172 return SMBOPEN_READWRITE;
1173}
1174
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175int
1176SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1177 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001178 const int access_flags, const int create_options, __u16 *netfid,
1179 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001180 const struct nls_table *nls_codepage, int remap)
1181{
1182 int rc = -EACCES;
1183 OPENX_REQ *pSMB = NULL;
1184 OPENX_RSP *pSMBr = NULL;
1185 int bytes_returned;
1186 int name_len;
1187 __u16 count;
1188
1189OldOpenRetry:
1190 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1191 (void **) &pSMBr);
1192 if (rc)
1193 return rc;
1194
1195 pSMB->AndXCommand = 0xFF; /* none */
1196
1197 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1198 count = 1; /* account for one byte pad to word boundary */
1199 name_len =
1200 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1201 fileName, PATH_MAX, nls_codepage, remap);
1202 name_len++; /* trailing null */
1203 name_len *= 2;
1204 } else { /* BB improve check for buffer overruns BB */
1205 count = 0; /* no pad */
1206 name_len = strnlen(fileName, PATH_MAX);
1207 name_len++; /* trailing null */
1208 strncpy(pSMB->fileName, fileName, name_len);
1209 }
1210 if (*pOplock & REQ_OPLOCK)
1211 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001212 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001213 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001214
Steve Frencha9d02ad2005-08-24 23:06:05 -07001215 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001216 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1221
Steve French790fe572007-07-07 19:25:05 +00001222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001224 else /* BB FIXME BB */
1225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
Jeff Layton67750fb2008-05-09 22:28:02 +00001227 if (create_options & CREATE_OPTION_READONLY)
1228 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229
1230 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001231/* pSMB->CreateOptions = cpu_to_le32(create_options &
1232 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001234
1235 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001236 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001238 inc_rfc1001_len(pSMB, count);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239
1240 pSMB->ByteCount = cpu_to_le16(count);
1241 /* long_op set to 1 to allow for oplock break timeouts */
1242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001243 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001244 cifs_stats_inc(&tcon->num_opens);
1245 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001246 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 } else {
1248 /* BB verify if wct == 15 */
1249
Steve French582d21e2008-05-13 04:54:12 +00001250/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251
1252 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1253 /* Let caller know file was created so we can set the mode. */
1254 /* Do we care about the CreateAction in any other cases? */
1255 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001256/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001257 *pOplock |= CIFS_CREATE_ACTION; */
1258 /* BB FIXME END */
1259
Steve French790fe572007-07-07 19:25:05 +00001260 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001261 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1262 pfile_info->LastAccessTime = 0; /* BB fixme */
1263 pfile_info->LastWriteTime = 0; /* BB fixme */
1264 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001265 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001266 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->AllocationSize =
1269 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1270 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001272 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 }
1274 }
1275
1276 cifs_buf_release(pSMB);
1277 if (rc == -EAGAIN)
1278 goto OldOpenRetry;
1279 return rc;
1280}
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282int
1283CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1284 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001285 const int access_flags, const int create_options, __u16 *netfid,
1286 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001287 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288{
1289 int rc = -EACCES;
1290 OPEN_REQ *pSMB = NULL;
1291 OPEN_RSP *pSMBr = NULL;
1292 int bytes_returned;
1293 int name_len;
1294 __u16 count;
1295
1296openRetry:
1297 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1298 (void **) &pSMBr);
1299 if (rc)
1300 return rc;
1301
1302 pSMB->AndXCommand = 0xFF; /* none */
1303
1304 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1305 count = 1; /* account for one byte pad to word boundary */
1306 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001307 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001308 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 name_len++; /* trailing null */
1310 name_len *= 2;
1311 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001312 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 count = 0; /* no pad */
1314 name_len = strnlen(fileName, PATH_MAX);
1315 name_len++; /* trailing null */
1316 pSMB->NameLength = cpu_to_le16(name_len);
1317 strncpy(pSMB->fileName, fileName, name_len);
1318 }
1319 if (*pOplock & REQ_OPLOCK)
1320 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001321 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1324 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001325 /* set file as system file if special file such
1326 as fifo and server expecting SFU style and
1327 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001328 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001329 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1330 else
1331 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 /* XP does not handle ATTR_POSIX_SEMANTICS */
1334 /* but it helps speed up case sensitive checks for other
1335 servers such as Samba */
1336 if (tcon->ses->capabilities & CAP_UNIX)
1337 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1338
Jeff Layton67750fb2008-05-09 22:28:02 +00001339 if (create_options & CREATE_OPTION_READONLY)
1340 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1343 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001344 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001345 /* BB Expirement with various impersonation levels and verify */
1346 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->SecurityFlags =
1348 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1349
1350 count += name_len;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001351 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352
1353 pSMB->ByteCount = cpu_to_le16(count);
1354 /* long_op set to 1 to allow for oplock break timeouts */
1355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Jeff Layton77499812011-01-11 07:24:23 -05001356 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001357 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001359 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 } else {
Steve French09d1db52005-04-28 22:41:08 -07001361 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1363 /* Let caller know file was created so we can set the mode. */
1364 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001365 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001366 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001367 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001368 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1369 36 /* CreationTime to Attributes */);
1370 /* the file_info buf is endian converted by caller */
1371 pfile_info->AllocationSize = pSMBr->AllocationSize;
1372 pfile_info->EndOfFile = pSMBr->EndOfFile;
1373 pfile_info->NumberOfLinks = cpu_to_le32(1);
1374 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001377
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 cifs_buf_release(pSMB);
1379 if (rc == -EAGAIN)
1380 goto openRetry;
1381 return rc;
1382}
1383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384int
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001385CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
Steve French50c2f752007-07-13 00:33:32 +00001386 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387{
1388 int rc = -EACCES;
1389 READ_REQ *pSMB = NULL;
1390 READ_RSP *pSMBr = NULL;
1391 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001392 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001393 int resp_buf_type = 0;
1394 struct kvec iov[1];
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001395 __u32 pid = io_parms->pid;
1396 __u16 netfid = io_parms->netfid;
1397 __u64 offset = io_parms->offset;
1398 struct cifsTconInfo *tcon = io_parms->tcon;
1399 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400
Joe Perchesb6b38f72010-04-21 03:50:45 +00001401 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001402 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001403 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001404 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001405 wct = 10; /* old style read */
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001406 if ((offset >> 32) > 0) {
Steve French4c3130e2008-12-09 00:28:16 +00001407 /* can not handle this big offset for old */
1408 return -EIO;
1409 }
1410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
1412 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001413 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 if (rc)
1415 return rc;
1416
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001417 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1418 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1419
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 /* tcon and ses pointer are checked in smb_init */
1421 if (tcon->ses->server == NULL)
1422 return -ECONNABORTED;
1423
Steve Frenchec637e32005-12-12 20:53:18 -08001424 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 pSMB->Fid = netfid;
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001426 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001427 if (wct == 12)
Pavel Shilovskyd4ffff12011-05-26 06:02:00 +00001428 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001429
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 pSMB->Remaining = 0;
1431 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1432 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001433 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001434 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1435 else {
1436 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001437 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001438 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001439 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001440 }
Steve Frenchec637e32005-12-12 20:53:18 -08001441
1442 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001443 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001444 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Jeff Layton77499812011-01-11 07:24:23 -05001445 &resp_buf_type, CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001446 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001447 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001449 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 } else {
1451 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1452 data_length = data_length << 16;
1453 data_length += le16_to_cpu(pSMBr->DataLength);
1454 *nbytes = data_length;
1455
1456 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001457 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001459 cFYI(1, "bad length %d for count %d",
1460 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 rc = -EIO;
1462 *nbytes = 0;
1463 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001464 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001465 le16_to_cpu(pSMBr->DataOffset);
1466/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001467 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001468 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001469 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001470 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001471 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Steve French4b8f9302006-02-26 16:41:18 +00001475/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001476 if (*buf) {
1477 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001478 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001479 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001480 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001481 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001482 /* return buffer to caller to free */
1483 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001484 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001485 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001486 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001487 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001488 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001489
1490 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 since file handle passed in no longer valid */
1492 return rc;
1493}
1494
Steve Frenchec637e32005-12-12 20:53:18 -08001495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001497CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1498 unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001499 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500{
1501 int rc = -EACCES;
1502 WRITE_REQ *pSMB = NULL;
1503 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001504 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 __u32 bytes_sent;
1506 __u16 byte_count;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001507 __u32 pid = io_parms->pid;
1508 __u16 netfid = io_parms->netfid;
1509 __u64 offset = io_parms->offset;
1510 struct cifsTconInfo *tcon = io_parms->tcon;
1511 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512
Steve Frencha24e2d72010-04-03 17:20:21 +00001513 *nbytes = 0;
1514
Joe Perchesb6b38f72010-04-21 03:50:45 +00001515 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001516 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001517 return -ECONNABORTED;
1518
Steve French790fe572007-07-07 19:25:05 +00001519 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001520 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001521 else {
Steve French1c955182005-08-30 20:58:07 -07001522 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001523 if ((offset >> 32) > 0) {
1524 /* can not handle big offset for old srv */
1525 return -EIO;
1526 }
1527 }
Steve French1c955182005-08-30 20:58:07 -07001528
1529 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 (void **) &pSMBr);
1531 if (rc)
1532 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001533
1534 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1535 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1536
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 /* tcon and ses pointer are checked in smb_init */
1538 if (tcon->ses->server == NULL)
1539 return -ECONNABORTED;
1540
1541 pSMB->AndXCommand = 0xFF; /* none */
1542 pSMB->Fid = netfid;
1543 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001544 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001545 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 pSMB->Reserved = 0xFFFFFFFF;
1548 pSMB->WriteMode = 0;
1549 pSMB->Remaining = 0;
1550
Steve French50c2f752007-07-13 00:33:32 +00001551 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 can send more if LARGE_WRITE_X capability returned by the server and if
1553 our buffer is big enough or if we convert to iovecs on socket writes
1554 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001555 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1557 } else {
1558 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1559 & ~0xFF;
1560 }
1561
1562 if (bytes_sent > count)
1563 bytes_sent = count;
1564 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001565 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001566 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001567 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001568 else if (ubuf) {
1569 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 cifs_buf_release(pSMB);
1571 return -EFAULT;
1572 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001573 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 /* No buffer */
1575 cifs_buf_release(pSMB);
1576 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001577 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001578 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001579 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001580 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001581 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1584 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001585 inc_rfc1001_len(pSMB, byte_count);
Steve French1c955182005-08-30 20:58:07 -07001586
Steve French790fe572007-07-07 19:25:05 +00001587 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001588 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001589 else { /* old style write has byte count 4 bytes earlier
1590 so 4 bytes pad */
1591 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001592 (struct smb_com_writex_req *)pSMB;
1593 pSMBW->ByteCount = cpu_to_le16(byte_count);
1594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1597 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001598 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001600 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 } else {
1602 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1603 *nbytes = (*nbytes) << 16;
1604 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301605
1606 /*
1607 * Mask off high 16 bits when bytes written as returned by the
1608 * server is greater than bytes requested by the client. Some
1609 * OS/2 servers are known to set incorrect CountHigh values.
1610 */
1611 if (*nbytes > count)
1612 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 }
1614
1615 cifs_buf_release(pSMB);
1616
Steve French50c2f752007-07-13 00:33:32 +00001617 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 since file handle passed in no longer valid */
1619
1620 return rc;
1621}
1622
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001623void
1624cifs_writedata_release(struct kref *refcount)
1625{
1626 struct cifs_writedata *wdata = container_of(refcount,
1627 struct cifs_writedata, refcount);
1628
1629 if (wdata->cfile)
1630 cifsFileInfo_put(wdata->cfile);
1631
1632 kfree(wdata);
1633}
1634
1635/*
1636 * Write failed with a retryable error. Resend the write request. It's also
1637 * possible that the page was redirtied so re-clean the page.
1638 */
1639static void
1640cifs_writev_requeue(struct cifs_writedata *wdata)
1641{
1642 int i, rc;
1643 struct inode *inode = wdata->cfile->dentry->d_inode;
1644
1645 for (i = 0; i < wdata->nr_pages; i++) {
1646 lock_page(wdata->pages[i]);
1647 clear_page_dirty_for_io(wdata->pages[i]);
1648 }
1649
1650 do {
1651 rc = cifs_async_writev(wdata);
1652 } while (rc == -EAGAIN);
1653
1654 for (i = 0; i < wdata->nr_pages; i++) {
1655 if (rc != 0)
1656 SetPageError(wdata->pages[i]);
1657 unlock_page(wdata->pages[i]);
1658 }
1659
1660 mapping_set_error(inode->i_mapping, rc);
1661 kref_put(&wdata->refcount, cifs_writedata_release);
1662}
1663
1664static void
1665cifs_writev_complete(struct work_struct *work)
1666{
1667 struct cifs_writedata *wdata = container_of(work,
1668 struct cifs_writedata, work);
1669 struct inode *inode = wdata->cfile->dentry->d_inode;
1670 int i = 0;
1671
1672 if (wdata->result == 0) {
1673 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
1674 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1675 wdata->bytes);
1676 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1677 return cifs_writev_requeue(wdata);
1678
1679 for (i = 0; i < wdata->nr_pages; i++) {
1680 struct page *page = wdata->pages[i];
1681 if (wdata->result == -EAGAIN)
1682 __set_page_dirty_nobuffers(page);
1683 else if (wdata->result < 0)
1684 SetPageError(page);
1685 end_page_writeback(page);
1686 page_cache_release(page);
1687 }
1688 if (wdata->result != -EAGAIN)
1689 mapping_set_error(inode->i_mapping, wdata->result);
1690 kref_put(&wdata->refcount, cifs_writedata_release);
1691}
1692
1693struct cifs_writedata *
1694cifs_writedata_alloc(unsigned int nr_pages)
1695{
1696 struct cifs_writedata *wdata;
1697
1698 /* this would overflow */
1699 if (nr_pages == 0) {
1700 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1701 return NULL;
1702 }
1703
1704 /* writedata + number of page pointers */
1705 wdata = kzalloc(sizeof(*wdata) +
1706 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1707 if (wdata != NULL) {
1708 INIT_WORK(&wdata->work, cifs_writev_complete);
1709 kref_init(&wdata->refcount);
1710 }
1711 return wdata;
1712}
1713
1714/*
1715 * Check the midState and signature on received buffer (if any), and queue the
1716 * workqueue completion task.
1717 */
1718static void
1719cifs_writev_callback(struct mid_q_entry *mid)
1720{
1721 struct cifs_writedata *wdata = mid->callback_data;
1722 struct cifsTconInfo *tcon = tlink_tcon(wdata->cfile->tlink);
1723 unsigned int written;
1724 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
1725
1726 switch (mid->midState) {
1727 case MID_RESPONSE_RECEIVED:
1728 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
1729 if (wdata->result != 0)
1730 break;
1731
1732 written = le16_to_cpu(smb->CountHigh);
1733 written <<= 16;
1734 written += le16_to_cpu(smb->Count);
1735 /*
1736 * Mask off high 16 bits when bytes written as returned
1737 * by the server is greater than bytes requested by the
1738 * client. OS/2 servers are known to set incorrect
1739 * CountHigh values.
1740 */
1741 if (written > wdata->bytes)
1742 written &= 0xFFFF;
1743
1744 if (written < wdata->bytes)
1745 wdata->result = -ENOSPC;
1746 else
1747 wdata->bytes = written;
1748 break;
1749 case MID_REQUEST_SUBMITTED:
1750 case MID_RETRY_NEEDED:
1751 wdata->result = -EAGAIN;
1752 break;
1753 default:
1754 wdata->result = -EIO;
1755 break;
1756 }
1757
1758 queue_work(system_nrt_wq, &wdata->work);
1759 DeleteMidQEntry(mid);
1760 atomic_dec(&tcon->ses->server->inFlight);
1761 wake_up(&tcon->ses->server->request_q);
1762}
1763
1764/* cifs_async_writev - send an async write, and set up mid to handle result */
1765int
1766cifs_async_writev(struct cifs_writedata *wdata)
1767{
1768 int i, rc = -EACCES;
1769 WRITE_REQ *smb = NULL;
1770 int wct;
1771 struct cifsTconInfo *tcon = tlink_tcon(wdata->cfile->tlink);
1772 struct inode *inode = wdata->cfile->dentry->d_inode;
1773 struct kvec *iov = NULL;
1774
1775 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
1776 wct = 14;
1777 } else {
1778 wct = 12;
1779 if (wdata->offset >> 32 > 0) {
1780 /* can not handle big offset for old srv */
1781 return -EIO;
1782 }
1783 }
1784
1785 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
1786 if (rc)
1787 goto async_writev_out;
1788
1789 /* 1 iov per page + 1 for header */
1790 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
1791 if (iov == NULL) {
1792 rc = -ENOMEM;
1793 goto async_writev_out;
1794 }
1795
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001796 smb->hdr.Pid = cpu_to_le16((__u16)wdata->cfile->pid);
1797 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->cfile->pid >> 16));
1798
Jeff Laytonc28c89f2011-05-19 16:22:56 -04001799 smb->AndXCommand = 0xFF; /* none */
1800 smb->Fid = wdata->cfile->netfid;
1801 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
1802 if (wct == 14)
1803 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
1804 smb->Reserved = 0xFFFFFFFF;
1805 smb->WriteMode = 0;
1806 smb->Remaining = 0;
1807
1808 smb->DataOffset =
1809 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1810
1811 /* 4 for RFC1001 length + 1 for BCC */
1812 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
1813 iov[0].iov_base = smb;
1814
1815 /* marshal up the pages into iov array */
1816 wdata->bytes = 0;
1817 for (i = 0; i < wdata->nr_pages; i++) {
1818 iov[i + 1].iov_len = min(inode->i_size -
1819 page_offset(wdata->pages[i]),
1820 (loff_t)PAGE_CACHE_SIZE);
1821 iov[i + 1].iov_base = kmap(wdata->pages[i]);
1822 wdata->bytes += iov[i + 1].iov_len;
1823 }
1824
1825 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
1826
1827 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
1828 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
1829
1830 if (wct == 14) {
1831 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
1832 put_bcc(wdata->bytes + 1, &smb->hdr);
1833 } else {
1834 /* wct == 12 */
1835 struct smb_com_writex_req *smbw =
1836 (struct smb_com_writex_req *)smb;
1837 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
1838 put_bcc(wdata->bytes + 5, &smbw->hdr);
1839 iov[0].iov_len += 4; /* pad bigger by four bytes */
1840 }
1841
1842 kref_get(&wdata->refcount);
1843 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
1844 cifs_writev_callback, wdata, false);
1845
1846 if (rc == 0)
1847 cifs_stats_inc(&tcon->num_writes);
1848 else
1849 kref_put(&wdata->refcount, cifs_writedata_release);
1850
1851 /* send is done, unmap pages */
1852 for (i = 0; i < wdata->nr_pages; i++)
1853 kunmap(wdata->pages[i]);
1854
1855async_writev_out:
1856 cifs_small_buf_release(smb);
1857 kfree(iov);
1858 return rc;
1859}
1860
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001861int
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001862CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
1863 unsigned int *nbytes, struct kvec *iov, int n_vec,
1864 const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865{
1866 int rc = -EACCES;
1867 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001868 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001869 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001870 int resp_buf_type = 0;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001871 __u32 pid = io_parms->pid;
1872 __u16 netfid = io_parms->netfid;
1873 __u64 offset = io_parms->offset;
1874 struct cifsTconInfo *tcon = io_parms->tcon;
1875 unsigned int count = io_parms->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001877 *nbytes = 0;
1878
Joe Perchesb6b38f72010-04-21 03:50:45 +00001879 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001880
Steve French4c3130e2008-12-09 00:28:16 +00001881 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001882 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001883 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001884 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001885 if ((offset >> 32) > 0) {
1886 /* can not handle big offset for old srv */
1887 return -EIO;
1888 }
1889 }
Steve French8cc64c62005-10-03 13:49:43 -07001890 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (rc)
1892 return rc;
Pavel Shilovskyfa2989f2011-05-26 10:01:59 +04001893
1894 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1895 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1896
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 /* tcon and ses pointer are checked in smb_init */
1898 if (tcon->ses->server == NULL)
1899 return -ECONNABORTED;
1900
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001901 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 pSMB->Fid = netfid;
1903 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001904 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001905 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 pSMB->Reserved = 0xFFFFFFFF;
1907 pSMB->WriteMode = 0;
1908 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001909
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001911 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
Steve French3e844692005-10-03 13:37:24 -07001913 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1914 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001915 /* header + 1 byte pad */
1916 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
Steve French790fe572007-07-07 19:25:05 +00001917 if (wct == 14)
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001918 inc_rfc1001_len(pSMB, count + 1);
Steve French8cc64c62005-10-03 13:49:43 -07001919 else /* wct == 12 */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00001920 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
Steve French790fe572007-07-07 19:25:05 +00001921 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001922 pSMB->ByteCount = cpu_to_le16(count + 1);
1923 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001924 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001925 (struct smb_com_writex_req *)pSMB;
1926 pSMBW->ByteCount = cpu_to_le16(count + 5);
1927 }
Steve French3e844692005-10-03 13:37:24 -07001928 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001929 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001930 iov[0].iov_len = smb_hdr_len + 4;
1931 else /* wct == 12 pad bigger by four bytes */
1932 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001933
Steve French3e844692005-10-03 13:37:24 -07001934
Steve Frenchec637e32005-12-12 20:53:18 -08001935 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001936 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001937 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001939 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001940 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001941 /* presumably this can not happen, but best to be safe */
1942 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001943 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001944 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001945 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1946 *nbytes = (*nbytes) << 16;
1947 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301948
1949 /*
1950 * Mask off high 16 bits when bytes written as returned by the
1951 * server is greater than bytes requested by the client. OS/2
1952 * servers are known to set incorrect CountHigh values.
1953 */
1954 if (*nbytes > count)
1955 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Steve French4b8f9302006-02-26 16:41:18 +00001958/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001959 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001960 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001961 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001962 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963
Steve French50c2f752007-07-13 00:33:32 +00001964 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 since file handle passed in no longer valid */
1966
1967 return rc;
1968}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001969
1970
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971int
1972CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1973 const __u16 smb_file_id, const __u64 len,
1974 const __u64 offset, const __u32 numUnlock,
Pavel Shilovsky12fed002011-01-17 20:15:44 +03001975 const __u32 numLock, const __u8 lockType,
1976 const bool waitFlag, const __u8 oplock_level)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977{
1978 int rc = 0;
1979 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001980/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 int bytes_returned;
1982 int timeout = 0;
1983 __u16 count;
1984
Joe Perchesb6b38f72010-04-21 03:50:45 +00001985 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001986 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 if (rc)
1989 return rc;
1990
Steve French790fe572007-07-07 19:25:05 +00001991 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001992 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001994 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001995 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1997 } else {
1998 pSMB->Timeout = 0;
1999 }
2000
2001 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2002 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2003 pSMB->LockType = lockType;
Pavel Shilovsky12fed002011-01-17 20:15:44 +03002004 pSMB->OplockLevel = oplock_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 pSMB->AndXCommand = 0xFF; /* none */
2006 pSMB->Fid = smb_file_id; /* netfid stays le */
2007
Steve French790fe572007-07-07 19:25:05 +00002008 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
2010 /* BB where to store pid high? */
2011 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2012 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2013 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2014 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2015 count = sizeof(LOCKING_ANDX_RANGE);
2016 } else {
2017 /* oplock break */
2018 count = 0;
2019 }
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002020 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 pSMB->ByteCount = cpu_to_le16(count);
2022
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002023 if (waitFlag) {
2024 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00002025 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00002026 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002027 } else {
Steve French133672e2007-11-13 22:41:37 +00002028 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
2029 timeout);
2030 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002031 }
Steve Frencha4544342005-08-24 13:59:35 -07002032 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002033 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002034 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002035
Steve French50c2f752007-07-13 00:33:32 +00002036 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 since file handle passed in no longer valid */
2038 return rc;
2039}
2040
2041int
Steve French08547b02006-02-28 22:39:25 +00002042CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
2043 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00002044 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00002045 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00002046{
2047 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2048 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00002049 struct cifs_posix_lock *parm_data;
2050 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00002051 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00002052 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00002053 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00002054 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00002055 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00002056
Joe Perchesb6b38f72010-04-21 03:50:45 +00002057 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002058
Steve French790fe572007-07-07 19:25:05 +00002059 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00002060 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002061
Steve French08547b02006-02-28 22:39:25 +00002062 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2063
2064 if (rc)
2065 return rc;
2066
2067 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2068
Steve French50c2f752007-07-13 00:33:32 +00002069 params = 6;
Steve French08547b02006-02-28 22:39:25 +00002070 pSMB->MaxSetupCount = 0;
2071 pSMB->Reserved = 0;
2072 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00002073 pSMB->Reserved2 = 0;
2074 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2075 offset = param_offset + params;
2076
Steve French08547b02006-02-28 22:39:25 +00002077 count = sizeof(struct cifs_posix_lock);
2078 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002079 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00002080 pSMB->SetupCount = 1;
2081 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00002082 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00002083 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2084 else
2085 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2086 byte_count = 3 /* pad */ + params + count;
2087 pSMB->DataCount = cpu_to_le16(count);
2088 pSMB->ParameterCount = cpu_to_le16(params);
2089 pSMB->TotalDataCount = pSMB->DataCount;
2090 pSMB->TotalParameterCount = pSMB->ParameterCount;
2091 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00002092 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00002093 (((char *) &pSMB->hdr.Protocol) + offset);
2094
2095 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00002096 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00002097 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00002098 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00002099 pSMB->Timeout = cpu_to_le32(-1);
2100 } else
2101 pSMB->Timeout = 0;
2102
Steve French08547b02006-02-28 22:39:25 +00002103 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002104 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00002105 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00002106
2107 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00002108 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00002109 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2110 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002111 inc_rfc1001_len(pSMB, byte_count);
Steve French08547b02006-02-28 22:39:25 +00002112 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002113 if (waitFlag) {
2114 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2115 (struct smb_hdr *) pSMBr, &bytes_returned);
2116 } else {
Steve French133672e2007-11-13 22:41:37 +00002117 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002118 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French133672e2007-11-13 22:41:37 +00002119 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2120 &resp_buf_type, timeout);
2121 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2122 not try to free it twice below on exit */
2123 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00002124 }
2125
Steve French08547b02006-02-28 22:39:25 +00002126 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002127 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002128 } else if (get_flag) {
2129 /* lock structure can be returned on get */
2130 __u16 data_offset;
2131 __u16 data_count;
2132 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00002133
Jeff Layton820a8032011-05-04 08:05:26 -04002134 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002135 rc = -EIO; /* bad smb */
2136 goto plk_err_exit;
2137 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002138 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2139 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00002140 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002141 rc = -EIO;
2142 goto plk_err_exit;
2143 }
2144 parm_data = (struct cifs_posix_lock *)
2145 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002146 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002147 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002148 else {
2149 if (parm_data->lock_type ==
2150 __constant_cpu_to_le16(CIFS_RDLCK))
2151 pLockData->fl_type = F_RDLCK;
2152 else if (parm_data->lock_type ==
2153 __constant_cpu_to_le16(CIFS_WRLCK))
2154 pLockData->fl_type = F_WRLCK;
2155
Steve French5443d132011-03-13 05:08:25 +00002156 pLockData->fl_start = le64_to_cpu(parm_data->start);
2157 pLockData->fl_end = pLockData->fl_start +
2158 le64_to_cpu(parm_data->length) - 1;
2159 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04002160 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002161 }
Steve French50c2f752007-07-13 00:33:32 +00002162
Steve Frenchfc94cdb2006-05-30 18:03:32 +00002163plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00002164 if (pSMB)
2165 cifs_small_buf_release(pSMB);
2166
Steve French133672e2007-11-13 22:41:37 +00002167 if (resp_buf_type == CIFS_SMALL_BUFFER)
2168 cifs_small_buf_release(iov[0].iov_base);
2169 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2170 cifs_buf_release(iov[0].iov_base);
2171
Steve French08547b02006-02-28 22:39:25 +00002172 /* Note: On -EAGAIN error only caller can retry on handle based calls
2173 since file handle passed in no longer valid */
2174
2175 return rc;
2176}
2177
2178
2179int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
2181{
2182 int rc = 0;
2183 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002184 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185
2186/* do not retry on dead session on close */
2187 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00002188 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 return 0;
2190 if (rc)
2191 return rc;
2192
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00002194 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00002196 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002197 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002199 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002201 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 }
2203 }
2204
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00002206 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 rc = 0;
2208
2209 return rc;
2210}
2211
2212int
Steve Frenchb298f222009-02-21 21:17:43 +00002213CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
2214{
2215 int rc = 0;
2216 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002217 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00002218
2219 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2220 if (rc)
2221 return rc;
2222
2223 pSMB->FileID = (__u16) smb_file_id;
2224 pSMB->ByteCount = 0;
2225 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
2226 cifs_stats_inc(&tcon->num_flushes);
2227 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002228 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00002229
2230 return rc;
2231}
2232
2233int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
2235 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002236 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237{
2238 int rc = 0;
2239 RENAME_REQ *pSMB = NULL;
2240 RENAME_RSP *pSMBr = NULL;
2241 int bytes_returned;
2242 int name_len, name_len2;
2243 __u16 count;
2244
Joe Perchesb6b38f72010-04-21 03:50:45 +00002245 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246renameRetry:
2247 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2248 (void **) &pSMBr);
2249 if (rc)
2250 return rc;
2251
2252 pSMB->BufferFormat = 0x04;
2253 pSMB->SearchAttributes =
2254 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2255 ATTR_DIRECTORY);
2256
2257 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2258 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002259 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002260 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 name_len++; /* trailing null */
2262 name_len *= 2;
2263 pSMB->OldFileName[name_len] = 0x04; /* pad */
2264 /* protocol requires ASCII signature byte on Unicode string */
2265 pSMB->OldFileName[name_len + 1] = 0x00;
2266 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00002267 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002268 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2270 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002271 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 name_len = strnlen(fromName, PATH_MAX);
2273 name_len++; /* trailing null */
2274 strncpy(pSMB->OldFileName, fromName, name_len);
2275 name_len2 = strnlen(toName, PATH_MAX);
2276 name_len2++; /* trailing null */
2277 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2278 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2279 name_len2++; /* trailing null */
2280 name_len2++; /* signature byte */
2281 }
2282
2283 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002284 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 pSMB->ByteCount = cpu_to_le16(count);
2286
2287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2288 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002289 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002290 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002291 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 cifs_buf_release(pSMB);
2294
2295 if (rc == -EAGAIN)
2296 goto renameRetry;
2297
2298 return rc;
2299}
2300
Steve French50c2f752007-07-13 00:33:32 +00002301int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04002302 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00002303 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304{
2305 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2306 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002307 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 char *data_offset;
2309 char dummy_string[30];
2310 int rc = 0;
2311 int bytes_returned = 0;
2312 int len_of_str;
2313 __u16 params, param_offset, offset, count, byte_count;
2314
Joe Perchesb6b38f72010-04-21 03:50:45 +00002315 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2317 (void **) &pSMBr);
2318 if (rc)
2319 return rc;
2320
2321 params = 6;
2322 pSMB->MaxSetupCount = 0;
2323 pSMB->Reserved = 0;
2324 pSMB->Flags = 0;
2325 pSMB->Timeout = 0;
2326 pSMB->Reserved2 = 0;
2327 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2328 offset = param_offset + params;
2329
2330 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2331 rename_info = (struct set_file_rename *) data_offset;
2332 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00002333 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 pSMB->SetupCount = 1;
2335 pSMB->Reserved3 = 0;
2336 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2337 byte_count = 3 /* pad */ + params;
2338 pSMB->ParameterCount = cpu_to_le16(params);
2339 pSMB->TotalParameterCount = pSMB->ParameterCount;
2340 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2341 pSMB->DataOffset = cpu_to_le16(offset);
2342 /* construct random name ".cifs_tmp<inodenum><mid>" */
2343 rename_info->overwrite = cpu_to_le32(1);
2344 rename_info->root_fid = 0;
2345 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002346 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002347 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2348 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002349 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002351 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002352 target_name, PATH_MAX, nls_codepage,
2353 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 }
2355 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002356 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 byte_count += count;
2358 pSMB->DataCount = cpu_to_le16(count);
2359 pSMB->TotalDataCount = pSMB->DataCount;
2360 pSMB->Fid = netfid;
2361 pSMB->InformationLevel =
2362 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2363 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002364 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 pSMB->ByteCount = cpu_to_le16(byte_count);
2366 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002367 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002368 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002369 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002370 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 cifs_buf_release(pSMB);
2373
2374 /* Note: On -EAGAIN error only caller can retry on handle based calls
2375 since file handle passed in no longer valid */
2376
2377 return rc;
2378}
2379
2380int
Steve French50c2f752007-07-13 00:33:32 +00002381CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2382 const __u16 target_tid, const char *toName, const int flags,
2383 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384{
2385 int rc = 0;
2386 COPY_REQ *pSMB = NULL;
2387 COPY_RSP *pSMBr = NULL;
2388 int bytes_returned;
2389 int name_len, name_len2;
2390 __u16 count;
2391
Joe Perchesb6b38f72010-04-21 03:50:45 +00002392 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393copyRetry:
2394 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2395 (void **) &pSMBr);
2396 if (rc)
2397 return rc;
2398
2399 pSMB->BufferFormat = 0x04;
2400 pSMB->Tid2 = target_tid;
2401
2402 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2403
2404 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002405 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002406 fromName, PATH_MAX, nls_codepage,
2407 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 name_len++; /* trailing null */
2409 name_len *= 2;
2410 pSMB->OldFileName[name_len] = 0x04; /* pad */
2411 /* protocol requires ASCII signature byte on Unicode string */
2412 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002413 name_len2 =
2414 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002415 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2417 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002418 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 name_len = strnlen(fromName, PATH_MAX);
2420 name_len++; /* trailing null */
2421 strncpy(pSMB->OldFileName, fromName, name_len);
2422 name_len2 = strnlen(toName, PATH_MAX);
2423 name_len2++; /* trailing null */
2424 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2425 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2426 name_len2++; /* trailing null */
2427 name_len2++; /* signature byte */
2428 }
2429
2430 count = 1 /* 1st signature byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002431 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 pSMB->ByteCount = cpu_to_le16(count);
2433
2434 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2435 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2436 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002437 cFYI(1, "Send error in copy = %d with %d files copied",
2438 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 }
Steve French0d817bc2008-05-22 02:02:03 +00002440 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441
2442 if (rc == -EAGAIN)
2443 goto copyRetry;
2444
2445 return rc;
2446}
2447
2448int
2449CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2450 const char *fromName, const char *toName,
2451 const struct nls_table *nls_codepage)
2452{
2453 TRANSACTION2_SPI_REQ *pSMB = NULL;
2454 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2455 char *data_offset;
2456 int name_len;
2457 int name_len_target;
2458 int rc = 0;
2459 int bytes_returned = 0;
2460 __u16 params, param_offset, offset, byte_count;
2461
Joe Perchesb6b38f72010-04-21 03:50:45 +00002462 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463createSymLinkRetry:
2464 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2465 (void **) &pSMBr);
2466 if (rc)
2467 return rc;
2468
2469 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2470 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002471 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 /* find define for this maxpathcomponent */
2473 , nls_codepage);
2474 name_len++; /* trailing null */
2475 name_len *= 2;
2476
Steve French50c2f752007-07-13 00:33:32 +00002477 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 name_len = strnlen(fromName, PATH_MAX);
2479 name_len++; /* trailing null */
2480 strncpy(pSMB->FileName, fromName, name_len);
2481 }
2482 params = 6 + name_len;
2483 pSMB->MaxSetupCount = 0;
2484 pSMB->Reserved = 0;
2485 pSMB->Flags = 0;
2486 pSMB->Timeout = 0;
2487 pSMB->Reserved2 = 0;
2488 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002489 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 offset = param_offset + params;
2491
2492 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2493 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2494 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002495 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 /* find define for this maxpathcomponent */
2497 , nls_codepage);
2498 name_len_target++; /* trailing null */
2499 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002500 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501 name_len_target = strnlen(toName, PATH_MAX);
2502 name_len_target++; /* trailing null */
2503 strncpy(data_offset, toName, name_len_target);
2504 }
2505
2506 pSMB->MaxParameterCount = cpu_to_le16(2);
2507 /* BB find exact max on data count below from sess */
2508 pSMB->MaxDataCount = cpu_to_le16(1000);
2509 pSMB->SetupCount = 1;
2510 pSMB->Reserved3 = 0;
2511 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2512 byte_count = 3 /* pad */ + params + name_len_target;
2513 pSMB->DataCount = cpu_to_le16(name_len_target);
2514 pSMB->ParameterCount = cpu_to_le16(params);
2515 pSMB->TotalDataCount = pSMB->DataCount;
2516 pSMB->TotalParameterCount = pSMB->ParameterCount;
2517 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2518 pSMB->DataOffset = cpu_to_le16(offset);
2519 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2520 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002521 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002522 pSMB->ByteCount = cpu_to_le16(byte_count);
2523 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2524 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002525 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002526 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002527 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
Steve French0d817bc2008-05-22 02:02:03 +00002529 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
2531 if (rc == -EAGAIN)
2532 goto createSymLinkRetry;
2533
2534 return rc;
2535}
2536
2537int
2538CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2539 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002540 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541{
2542 TRANSACTION2_SPI_REQ *pSMB = NULL;
2543 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2544 char *data_offset;
2545 int name_len;
2546 int name_len_target;
2547 int rc = 0;
2548 int bytes_returned = 0;
2549 __u16 params, param_offset, offset, byte_count;
2550
Joe Perchesb6b38f72010-04-21 03:50:45 +00002551 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552createHardLinkRetry:
2553 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2554 (void **) &pSMBr);
2555 if (rc)
2556 return rc;
2557
2558 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002559 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002560 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 name_len++; /* trailing null */
2562 name_len *= 2;
2563
Steve French50c2f752007-07-13 00:33:32 +00002564 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 name_len = strnlen(toName, PATH_MAX);
2566 name_len++; /* trailing null */
2567 strncpy(pSMB->FileName, toName, name_len);
2568 }
2569 params = 6 + name_len;
2570 pSMB->MaxSetupCount = 0;
2571 pSMB->Reserved = 0;
2572 pSMB->Flags = 0;
2573 pSMB->Timeout = 0;
2574 pSMB->Reserved2 = 0;
2575 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002576 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 offset = param_offset + params;
2578
2579 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2580 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2581 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002582 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002583 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 name_len_target++; /* trailing null */
2585 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002586 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 name_len_target = strnlen(fromName, PATH_MAX);
2588 name_len_target++; /* trailing null */
2589 strncpy(data_offset, fromName, name_len_target);
2590 }
2591
2592 pSMB->MaxParameterCount = cpu_to_le16(2);
2593 /* BB find exact max on data count below from sess*/
2594 pSMB->MaxDataCount = cpu_to_le16(1000);
2595 pSMB->SetupCount = 1;
2596 pSMB->Reserved3 = 0;
2597 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2598 byte_count = 3 /* pad */ + params + name_len_target;
2599 pSMB->ParameterCount = cpu_to_le16(params);
2600 pSMB->TotalParameterCount = pSMB->ParameterCount;
2601 pSMB->DataCount = cpu_to_le16(name_len_target);
2602 pSMB->TotalDataCount = pSMB->DataCount;
2603 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2604 pSMB->DataOffset = cpu_to_le16(offset);
2605 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2606 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002607 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 pSMB->ByteCount = cpu_to_le16(byte_count);
2609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2610 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002611 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002612 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002613 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 cifs_buf_release(pSMB);
2616 if (rc == -EAGAIN)
2617 goto createHardLinkRetry;
2618
2619 return rc;
2620}
2621
2622int
2623CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2624 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002625 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626{
2627 int rc = 0;
2628 NT_RENAME_REQ *pSMB = NULL;
2629 RENAME_RSP *pSMBr = NULL;
2630 int bytes_returned;
2631 int name_len, name_len2;
2632 __u16 count;
2633
Joe Perchesb6b38f72010-04-21 03:50:45 +00002634 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635winCreateHardLinkRetry:
2636
2637 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2638 (void **) &pSMBr);
2639 if (rc)
2640 return rc;
2641
2642 pSMB->SearchAttributes =
2643 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2644 ATTR_DIRECTORY);
2645 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2646 pSMB->ClusterCount = 0;
2647
2648 pSMB->BufferFormat = 0x04;
2649
2650 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2651 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002652 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002653 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 name_len++; /* trailing null */
2655 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002656
2657 /* protocol specifies ASCII buffer format (0x04) for unicode */
2658 pSMB->OldFileName[name_len] = 0x04;
2659 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002661 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002662 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2664 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002665 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 name_len = strnlen(fromName, PATH_MAX);
2667 name_len++; /* trailing null */
2668 strncpy(pSMB->OldFileName, fromName, name_len);
2669 name_len2 = strnlen(toName, PATH_MAX);
2670 name_len2++; /* trailing null */
2671 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2672 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2673 name_len2++; /* trailing null */
2674 name_len2++; /* signature byte */
2675 }
2676
2677 count = 1 /* string type byte */ + name_len + name_len2;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002678 inc_rfc1001_len(pSMB, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 pSMB->ByteCount = cpu_to_le16(count);
2680
2681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002683 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002684 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002685 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002686
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 cifs_buf_release(pSMB);
2688 if (rc == -EAGAIN)
2689 goto winCreateHardLinkRetry;
2690
2691 return rc;
2692}
2693
2694int
2695CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002696 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 const struct nls_table *nls_codepage)
2698{
2699/* SMB_QUERY_FILE_UNIX_LINK */
2700 TRANSACTION2_QPI_REQ *pSMB = NULL;
2701 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2702 int rc = 0;
2703 int bytes_returned;
2704 int name_len;
2705 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002706 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Joe Perchesb6b38f72010-04-21 03:50:45 +00002708 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709
2710querySymLinkRetry:
2711 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2712 (void **) &pSMBr);
2713 if (rc)
2714 return rc;
2715
2716 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2717 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002718 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2719 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 name_len++; /* trailing null */
2721 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002722 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 name_len = strnlen(searchName, PATH_MAX);
2724 name_len++; /* trailing null */
2725 strncpy(pSMB->FileName, searchName, name_len);
2726 }
2727
2728 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2729 pSMB->TotalDataCount = 0;
2730 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002731 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 pSMB->MaxSetupCount = 0;
2733 pSMB->Reserved = 0;
2734 pSMB->Flags = 0;
2735 pSMB->Timeout = 0;
2736 pSMB->Reserved2 = 0;
2737 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002738 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 pSMB->DataCount = 0;
2740 pSMB->DataOffset = 0;
2741 pSMB->SetupCount = 1;
2742 pSMB->Reserved3 = 0;
2743 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2744 byte_count = params + 1 /* pad */ ;
2745 pSMB->TotalParameterCount = cpu_to_le16(params);
2746 pSMB->ParameterCount = pSMB->TotalParameterCount;
2747 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2748 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00002749 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 pSMB->ByteCount = cpu_to_le16(byte_count);
2751
2752 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2753 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2754 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002755 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 } else {
2757 /* decode response */
2758
2759 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04002761 if (rc || get_bcc(&pSMBr->hdr) < 2)
Jeff Layton460b9692009-04-30 07:17:56 -04002762 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002764 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002765 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766
Jeff Layton460b9692009-04-30 07:17:56 -04002767 data_start = ((char *) &pSMBr->hdr.Protocol) +
2768 le16_to_cpu(pSMBr->t2.DataOffset);
2769
Steve French0e0d2cf2009-05-01 05:27:32 +00002770 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2771 is_unicode = true;
2772 else
2773 is_unicode = false;
2774
Steve French737b7582005-04-28 22:41:06 -07002775 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002776 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002777 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002778 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002779 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 }
2781 }
2782 cifs_buf_release(pSMB);
2783 if (rc == -EAGAIN)
2784 goto querySymLinkRetry;
2785 return rc;
2786}
2787
Steve Frenchc52a9552011-02-24 06:16:22 +00002788#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
2789/*
2790 * Recent Windows versions now create symlinks more frequently
2791 * and they use the "reparse point" mechanism below. We can of course
2792 * do symlinks nicely to Samba and other servers which support the
2793 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
2794 * "MF" symlinks optionally, but for recent Windows we really need to
2795 * reenable the code below and fix the cifs_symlink callers to handle this.
2796 * In the interim this code has been moved to its own config option so
2797 * it is not compiled in by default until callers fixed up and more tested.
2798 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799int
2800CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2801 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002802 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 const struct nls_table *nls_codepage)
2804{
2805 int rc = 0;
2806 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002807 struct smb_com_transaction_ioctl_req *pSMB;
2808 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809
Joe Perchesb6b38f72010-04-21 03:50:45 +00002810 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2812 (void **) &pSMBr);
2813 if (rc)
2814 return rc;
2815
2816 pSMB->TotalParameterCount = 0 ;
2817 pSMB->TotalDataCount = 0;
2818 pSMB->MaxParameterCount = cpu_to_le32(2);
2819 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002820 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2821 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 pSMB->MaxSetupCount = 4;
2823 pSMB->Reserved = 0;
2824 pSMB->ParameterOffset = 0;
2825 pSMB->DataCount = 0;
2826 pSMB->DataOffset = 0;
2827 pSMB->SetupCount = 4;
2828 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2829 pSMB->ParameterCount = pSMB->TotalParameterCount;
2830 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2831 pSMB->IsFsctl = 1; /* FSCTL */
2832 pSMB->IsRootFlag = 0;
2833 pSMB->Fid = fid; /* file handle always le */
2834 pSMB->ByteCount = 0;
2835
2836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2838 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002839 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 } else { /* decode response */
2841 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2842 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Jeff Layton820a8032011-05-04 08:05:26 -04002843 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
2844 /* BB also check enough total bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002846 goto qreparse_out;
2847 }
2848 if (data_count && (data_count < 2048)) {
2849 char *end_of_smb = 2 /* sizeof byte count */ +
Jeff Layton820a8032011-05-04 08:05:26 -04002850 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
Steve Frenchafe48c32009-05-02 05:25:46 +00002852 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002853 (struct reparse_data *)
2854 ((char *)&pSMBr->hdr.Protocol
2855 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002856 if ((char *)reparse_buf >= end_of_smb) {
2857 rc = -EIO;
2858 goto qreparse_out;
2859 }
2860 if ((reparse_buf->LinkNamesBuf +
2861 reparse_buf->TargetNameOffset +
2862 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002863 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002864 rc = -EIO;
2865 goto qreparse_out;
2866 }
Steve French50c2f752007-07-13 00:33:32 +00002867
Steve Frenchafe48c32009-05-02 05:25:46 +00002868 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2869 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002870 (reparse_buf->LinkNamesBuf +
2871 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002872 buflen,
2873 reparse_buf->TargetNameLen,
2874 nls_codepage, 0);
2875 } else { /* ASCII names */
2876 strncpy(symlinkinfo,
2877 reparse_buf->LinkNamesBuf +
2878 reparse_buf->TargetNameOffset,
2879 min_t(const int, buflen,
2880 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002882 } else {
2883 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002884 cFYI(1, "Invalid return data count on "
2885 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002887 symlinkinfo[buflen] = 0; /* just in case so the caller
2888 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002889 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 }
Steve French989c7e52009-05-02 05:32:20 +00002891
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002893 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894
2895 /* Note: On -EAGAIN error only caller can retry on handle based calls
2896 since file handle passed in no longer valid */
2897
2898 return rc;
2899}
Steve Frenchc52a9552011-02-24 06:16:22 +00002900#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
2902#ifdef CONFIG_CIFS_POSIX
2903
2904/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002905static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2906 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907{
2908 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002909 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2910 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2911 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002912 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913
2914 return;
2915}
2916
2917/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002918static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2919 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920{
2921 int size = 0;
2922 int i;
2923 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002924 struct cifs_posix_ace *pACE;
2925 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2926 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
2928 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2929 return -EOPNOTSUPP;
2930
Steve French790fe572007-07-07 19:25:05 +00002931 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 count = le16_to_cpu(cifs_acl->access_entry_count);
2933 pACE = &cifs_acl->ace_array[0];
2934 size = sizeof(struct cifs_posix_acl);
2935 size += sizeof(struct cifs_posix_ace) * count;
2936 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002937 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002938 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2939 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 return -EINVAL;
2941 }
Steve French790fe572007-07-07 19:25:05 +00002942 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 count = le16_to_cpu(cifs_acl->access_entry_count);
2944 size = sizeof(struct cifs_posix_acl);
2945 size += sizeof(struct cifs_posix_ace) * count;
2946/* skip past access ACEs to get to default ACEs */
2947 pACE = &cifs_acl->ace_array[count];
2948 count = le16_to_cpu(cifs_acl->default_entry_count);
2949 size += sizeof(struct cifs_posix_ace) * count;
2950 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002951 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 return -EINVAL;
2953 } else {
2954 /* illegal type */
2955 return -EINVAL;
2956 }
2957
2958 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002959 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002960 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002961 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 return -ERANGE;
2963 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002964 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002965 for (i = 0; i < count ; i++) {
2966 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2967 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 }
2969 }
2970 return size;
2971}
2972
Steve French50c2f752007-07-13 00:33:32 +00002973static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2974 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975{
2976 __u16 rc = 0; /* 0 = ACL converted ok */
2977
Steve Frenchff7feac2005-11-15 16:45:16 -08002978 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2979 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002981 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 /* Probably no need to le convert -1 on any arch but can not hurt */
2983 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002984 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002985 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002986 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 return rc;
2988}
2989
2990/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002991static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2992 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993{
2994 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002995 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2996 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 int count;
2998 int i;
2999
Steve French790fe572007-07-07 19:25:05 +00003000 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 return 0;
3002
3003 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00003004 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00003005 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00003006 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00003007 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003008 cFYI(1, "unknown POSIX ACL version %d",
3009 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 return 0;
3011 }
3012 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00003013 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08003014 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00003015 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08003016 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003018 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019 return 0;
3020 }
Steve French50c2f752007-07-13 00:33:32 +00003021 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3023 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00003024 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 /* ACE not converted */
3026 break;
3027 }
3028 }
Steve French790fe572007-07-07 19:25:05 +00003029 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3031 rc += sizeof(struct cifs_posix_acl);
3032 /* BB add check to make sure ACL does not overflow SMB */
3033 }
3034 return rc;
3035}
3036
3037int
3038CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003039 const unsigned char *searchName,
3040 char *acl_inf, const int buflen, const int acl_type,
3041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042{
3043/* SMB_QUERY_POSIX_ACL */
3044 TRANSACTION2_QPI_REQ *pSMB = NULL;
3045 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3046 int rc = 0;
3047 int bytes_returned;
3048 int name_len;
3049 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00003050
Joe Perchesb6b38f72010-04-21 03:50:45 +00003051 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052
3053queryAclRetry:
3054 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3055 (void **) &pSMBr);
3056 if (rc)
3057 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003058
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3060 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003061 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003062 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 name_len++; /* trailing null */
3064 name_len *= 2;
3065 pSMB->FileName[name_len] = 0;
3066 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00003067 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 name_len = strnlen(searchName, PATH_MAX);
3069 name_len++; /* trailing null */
3070 strncpy(pSMB->FileName, searchName, name_len);
3071 }
3072
3073 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3074 pSMB->TotalDataCount = 0;
3075 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00003076 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 pSMB->MaxDataCount = cpu_to_le16(4000);
3078 pSMB->MaxSetupCount = 0;
3079 pSMB->Reserved = 0;
3080 pSMB->Flags = 0;
3081 pSMB->Timeout = 0;
3082 pSMB->Reserved2 = 0;
3083 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003084 offsetof(struct smb_com_transaction2_qpi_req,
3085 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 pSMB->DataCount = 0;
3087 pSMB->DataOffset = 0;
3088 pSMB->SetupCount = 1;
3089 pSMB->Reserved3 = 0;
3090 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3091 byte_count = params + 1 /* pad */ ;
3092 pSMB->TotalParameterCount = cpu_to_le16(params);
3093 pSMB->ParameterCount = pSMB->TotalParameterCount;
3094 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3095 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003096 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 pSMB->ByteCount = cpu_to_le16(byte_count);
3098
3099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003101 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003103 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 } else {
3105 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00003106
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003109 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 rc = -EIO; /* bad smb */
3111 else {
3112 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3113 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3114 rc = cifs_copy_posix_acl(acl_inf,
3115 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00003116 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 }
3118 }
3119 cifs_buf_release(pSMB);
3120 if (rc == -EAGAIN)
3121 goto queryAclRetry;
3122 return rc;
3123}
3124
3125int
3126CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003127 const unsigned char *fileName,
3128 const char *local_acl, const int buflen,
3129 const int acl_type,
3130 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131{
3132 struct smb_com_transaction2_spi_req *pSMB = NULL;
3133 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3134 char *parm_data;
3135 int name_len;
3136 int rc = 0;
3137 int bytes_returned = 0;
3138 __u16 params, byte_count, data_count, param_offset, offset;
3139
Joe Perchesb6b38f72010-04-21 03:50:45 +00003140 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141setAclRetry:
3142 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003143 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 if (rc)
3145 return rc;
3146 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3147 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003148 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003149 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 name_len++; /* trailing null */
3151 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003152 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 name_len = strnlen(fileName, PATH_MAX);
3154 name_len++; /* trailing null */
3155 strncpy(pSMB->FileName, fileName, name_len);
3156 }
3157 params = 6 + name_len;
3158 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003159 /* BB find max SMB size from sess */
3160 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 pSMB->MaxSetupCount = 0;
3162 pSMB->Reserved = 0;
3163 pSMB->Flags = 0;
3164 pSMB->Timeout = 0;
3165 pSMB->Reserved2 = 0;
3166 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00003167 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 offset = param_offset + params;
3169 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3170 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3171
3172 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00003173 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174
Steve French790fe572007-07-07 19:25:05 +00003175 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 rc = -EOPNOTSUPP;
3177 goto setACLerrorExit;
3178 }
3179 pSMB->DataOffset = cpu_to_le16(offset);
3180 pSMB->SetupCount = 1;
3181 pSMB->Reserved3 = 0;
3182 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3183 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3184 byte_count = 3 /* pad */ + params + data_count;
3185 pSMB->DataCount = cpu_to_le16(data_count);
3186 pSMB->TotalDataCount = pSMB->DataCount;
3187 pSMB->ParameterCount = cpu_to_le16(params);
3188 pSMB->TotalParameterCount = pSMB->ParameterCount;
3189 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003190 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 pSMB->ByteCount = cpu_to_le16(byte_count);
3192 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003193 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003194 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003195 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003196
3197setACLerrorExit:
3198 cifs_buf_release(pSMB);
3199 if (rc == -EAGAIN)
3200 goto setAclRetry;
3201 return rc;
3202}
3203
Steve Frenchf654bac2005-04-28 22:41:04 -07003204/* BB fix tabs in this function FIXME BB */
3205int
3206CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00003207 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07003208{
Steve French50c2f752007-07-13 00:33:32 +00003209 int rc = 0;
3210 struct smb_t2_qfi_req *pSMB = NULL;
3211 struct smb_t2_qfi_rsp *pSMBr = NULL;
3212 int bytes_returned;
3213 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07003214
Joe Perchesb6b38f72010-04-21 03:50:45 +00003215 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003216 if (tcon == NULL)
3217 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07003218
3219GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003220 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3221 (void **) &pSMBr);
3222 if (rc)
3223 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003224
Steve Frenchad7a2922008-02-07 23:25:02 +00003225 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00003226 pSMB->t2.TotalDataCount = 0;
3227 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3228 /* BB find exact max data count below from sess structure BB */
3229 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3230 pSMB->t2.MaxSetupCount = 0;
3231 pSMB->t2.Reserved = 0;
3232 pSMB->t2.Flags = 0;
3233 pSMB->t2.Timeout = 0;
3234 pSMB->t2.Reserved2 = 0;
3235 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3236 Fid) - 4);
3237 pSMB->t2.DataCount = 0;
3238 pSMB->t2.DataOffset = 0;
3239 pSMB->t2.SetupCount = 1;
3240 pSMB->t2.Reserved3 = 0;
3241 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3242 byte_count = params + 1 /* pad */ ;
3243 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3244 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3245 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3246 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003247 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003248 inc_rfc1001_len(pSMB, byte_count);
Steve French790fe572007-07-07 19:25:05 +00003249 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003250
Steve French790fe572007-07-07 19:25:05 +00003251 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3252 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3253 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003254 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003255 } else {
3256 /* decode response */
3257 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003258 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04003259 if (rc || get_bcc(&pSMBr->hdr) < 2)
Steve French790fe572007-07-07 19:25:05 +00003260 /* If rc should we check for EOPNOSUPP and
3261 disable the srvino flag? or in caller? */
3262 rc = -EIO; /* bad smb */
3263 else {
3264 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3265 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3266 struct file_chattr_info *pfinfo;
3267 /* BB Do we need a cast or hash here ? */
3268 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003269 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003270 rc = -EIO;
3271 goto GetExtAttrOut;
3272 }
3273 pfinfo = (struct file_chattr_info *)
3274 (data_offset + (char *) &pSMBr->hdr.Protocol);
3275 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003276 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003277 }
3278 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003279GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003280 cifs_buf_release(pSMB);
3281 if (rc == -EAGAIN)
3282 goto GetExtAttrRetry;
3283 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003284}
3285
Steve Frenchf654bac2005-04-28 22:41:04 -07003286#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287
Jeff Layton79df1ba2010-12-06 12:52:08 -05003288#ifdef CONFIG_CIFS_ACL
3289/*
3290 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3291 * all NT TRANSACTS that we init here have total parm and data under about 400
3292 * bytes (to fit in small cifs buffer size), which is the case so far, it
3293 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3294 * returned setup area) and MaxParameterCount (returned parms size) must be set
3295 * by caller
3296 */
3297static int
3298smb_init_nttransact(const __u16 sub_command, const int setup_count,
3299 const int parm_len, struct cifsTconInfo *tcon,
3300 void **ret_buf)
3301{
3302 int rc;
3303 __u32 temp_offset;
3304 struct smb_com_ntransact_req *pSMB;
3305
3306 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3307 (void **)&pSMB);
3308 if (rc)
3309 return rc;
3310 *ret_buf = (void *)pSMB;
3311 pSMB->Reserved = 0;
3312 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3313 pSMB->TotalDataCount = 0;
3314 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
3315 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3316 pSMB->ParameterCount = pSMB->TotalParameterCount;
3317 pSMB->DataCount = pSMB->TotalDataCount;
3318 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3319 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3320 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3321 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3322 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3323 pSMB->SubCommand = cpu_to_le16(sub_command);
3324 return 0;
3325}
3326
3327static int
3328validate_ntransact(char *buf, char **ppparm, char **ppdata,
3329 __u32 *pparmlen, __u32 *pdatalen)
3330{
3331 char *end_of_smb;
3332 __u32 data_count, data_offset, parm_count, parm_offset;
3333 struct smb_com_ntransact_rsp *pSMBr;
Jeff Layton820a8032011-05-04 08:05:26 -04003334 u16 bcc;
Jeff Layton79df1ba2010-12-06 12:52:08 -05003335
3336 *pdatalen = 0;
3337 *pparmlen = 0;
3338
3339 if (buf == NULL)
3340 return -EINVAL;
3341
3342 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3343
Jeff Layton820a8032011-05-04 08:05:26 -04003344 bcc = get_bcc(&pSMBr->hdr);
3345 end_of_smb = 2 /* sizeof byte count */ + bcc +
Jeff Layton79df1ba2010-12-06 12:52:08 -05003346 (char *)&pSMBr->ByteCount;
3347
3348 data_offset = le32_to_cpu(pSMBr->DataOffset);
3349 data_count = le32_to_cpu(pSMBr->DataCount);
3350 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3351 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3352
3353 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3354 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3355
3356 /* should we also check that parm and data areas do not overlap? */
3357 if (*ppparm > end_of_smb) {
3358 cFYI(1, "parms start after end of smb");
3359 return -EINVAL;
3360 } else if (parm_count + *ppparm > end_of_smb) {
3361 cFYI(1, "parm end after end of smb");
3362 return -EINVAL;
3363 } else if (*ppdata > end_of_smb) {
3364 cFYI(1, "data starts after end of smb");
3365 return -EINVAL;
3366 } else if (data_count + *ppdata > end_of_smb) {
3367 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3368 *ppdata, data_count, (data_count + *ppdata),
3369 end_of_smb, pSMBr);
3370 return -EINVAL;
Jeff Layton820a8032011-05-04 08:05:26 -04003371 } else if (parm_count + data_count > bcc) {
Jeff Layton79df1ba2010-12-06 12:52:08 -05003372 cFYI(1, "parm count and data count larger than SMB");
3373 return -EINVAL;
3374 }
3375 *pdatalen = data_count;
3376 *pparmlen = parm_count;
3377 return 0;
3378}
3379
Steve French0a4b92c2006-01-12 15:44:21 -08003380/* Get Security Descriptor (by handle) from remote server for a file or dir */
3381int
3382CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003383 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003384{
3385 int rc = 0;
3386 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003387 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003388 struct kvec iov[1];
3389
Joe Perchesb6b38f72010-04-21 03:50:45 +00003390 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003391
Steve French630f3f0c2007-10-25 21:17:17 +00003392 *pbuflen = 0;
3393 *acl_inf = NULL;
3394
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003395 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003396 8 /* parm len */, tcon, (void **) &pSMB);
3397 if (rc)
3398 return rc;
3399
3400 pSMB->MaxParameterCount = cpu_to_le32(4);
3401 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3402 pSMB->MaxSetupCount = 0;
3403 pSMB->Fid = fid; /* file handle always le */
3404 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3405 CIFS_ACL_DACL);
3406 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003407 inc_rfc1001_len(pSMB, 11);
Steve French0a4b92c2006-01-12 15:44:21 -08003408 iov[0].iov_base = (char *)pSMB;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003409 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
Steve French0a4b92c2006-01-12 15:44:21 -08003410
Steve Frencha761ac52007-10-18 21:45:27 +00003411 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Jeff Layton77499812011-01-11 07:24:23 -05003412 0);
Steve French0a4b92c2006-01-12 15:44:21 -08003413 cifs_stats_inc(&tcon->num_acl_get);
3414 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003415 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003416 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003417 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003418 __u32 parm_len;
3419 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003420 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003421 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003422
3423/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003424 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003425 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003426 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003427 goto qsec_out;
3428 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3429
Joe Perchesb6b38f72010-04-21 03:50:45 +00003430 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003431
3432 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3433 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003434 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003435 goto qsec_out;
3436 }
3437
3438/* BB check that data area is minimum length and as big as acl_len */
3439
Steve Frenchaf6f4612007-10-16 18:40:37 +00003440 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003441 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003442 cERROR(1, "acl length %d does not match %d",
3443 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003444 if (*pbuflen > acl_len)
3445 *pbuflen = acl_len;
3446 }
Steve French0a4b92c2006-01-12 15:44:21 -08003447
Steve French630f3f0c2007-10-25 21:17:17 +00003448 /* check if buffer is big enough for the acl
3449 header followed by the smallest SID */
3450 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3451 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003452 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003453 rc = -EINVAL;
3454 *pbuflen = 0;
3455 } else {
3456 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3457 if (*acl_inf == NULL) {
3458 *pbuflen = 0;
3459 rc = -ENOMEM;
3460 }
3461 memcpy(*acl_inf, pdata, *pbuflen);
3462 }
Steve French0a4b92c2006-01-12 15:44:21 -08003463 }
3464qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003465 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003466 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003467 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003468 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003469/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003470 return rc;
3471}
Steve French97837582007-12-31 07:47:21 +00003472
3473int
3474CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3475 struct cifs_ntsd *pntsd, __u32 acllen)
3476{
3477 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3478 int rc = 0;
3479 int bytes_returned = 0;
3480 SET_SEC_DESC_REQ *pSMB = NULL;
3481 NTRANSACT_RSP *pSMBr = NULL;
3482
3483setCifsAclRetry:
3484 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3485 (void **) &pSMBr);
3486 if (rc)
3487 return (rc);
3488
3489 pSMB->MaxSetupCount = 0;
3490 pSMB->Reserved = 0;
3491
3492 param_count = 8;
3493 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3494 data_count = acllen;
3495 data_offset = param_offset + param_count;
3496 byte_count = 3 /* pad */ + param_count;
3497
3498 pSMB->DataCount = cpu_to_le32(data_count);
3499 pSMB->TotalDataCount = pSMB->DataCount;
3500 pSMB->MaxParameterCount = cpu_to_le32(4);
3501 pSMB->MaxDataCount = cpu_to_le32(16384);
3502 pSMB->ParameterCount = cpu_to_le32(param_count);
3503 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3504 pSMB->TotalParameterCount = pSMB->ParameterCount;
3505 pSMB->DataOffset = cpu_to_le32(data_offset);
3506 pSMB->SetupCount = 0;
3507 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3508 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3509
3510 pSMB->Fid = fid; /* file handle always le */
3511 pSMB->Reserved2 = 0;
3512 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3513
3514 if (pntsd && acllen) {
3515 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3516 (char *) pntsd,
3517 acllen);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003518 inc_rfc1001_len(pSMB, byte_count + data_count);
Steve French97837582007-12-31 07:47:21 +00003519 } else
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003520 inc_rfc1001_len(pSMB, byte_count);
Steve French97837582007-12-31 07:47:21 +00003521
3522 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3523 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3524
Joe Perchesb6b38f72010-04-21 03:50:45 +00003525 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003526 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003527 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003528 cifs_buf_release(pSMB);
3529
3530 if (rc == -EAGAIN)
3531 goto setCifsAclRetry;
3532
3533 return (rc);
3534}
3535
Jeff Layton79df1ba2010-12-06 12:52:08 -05003536#endif /* CONFIG_CIFS_ACL */
Steve French0a4b92c2006-01-12 15:44:21 -08003537
Steve French6b8edfe2005-08-23 20:26:03 -07003538/* Legacy Query Path Information call for lookup to old servers such
3539 as Win9x/WinME */
3540int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003541 const unsigned char *searchName,
3542 FILE_ALL_INFO *pFinfo,
3543 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003544{
Steve Frenchad7a2922008-02-07 23:25:02 +00003545 QUERY_INFORMATION_REQ *pSMB;
3546 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003547 int rc = 0;
3548 int bytes_returned;
3549 int name_len;
3550
Joe Perchesb6b38f72010-04-21 03:50:45 +00003551 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003552QInfRetry:
3553 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003554 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003555 if (rc)
3556 return rc;
3557
3558 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3559 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003560 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3561 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003562 name_len++; /* trailing null */
3563 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003564 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003565 name_len = strnlen(searchName, PATH_MAX);
3566 name_len++; /* trailing null */
3567 strncpy(pSMB->FileName, searchName, name_len);
3568 }
3569 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003570 name_len++; /* account for buffer type byte */
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003571 inc_rfc1001_len(pSMB, (__u16)name_len);
Steve French6b8edfe2005-08-23 20:26:03 -07003572 pSMB->ByteCount = cpu_to_le16(name_len);
3573
3574 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003575 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003576 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003577 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003578 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003579 struct timespec ts;
3580 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003581
3582 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003583 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003584 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003585 ts.tv_nsec = 0;
3586 ts.tv_sec = time;
3587 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003588 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003589 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3590 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003591 pFinfo->AllocationSize =
3592 cpu_to_le64(le32_to_cpu(pSMBr->size));
3593 pFinfo->EndOfFile = pFinfo->AllocationSize;
3594 pFinfo->Attributes =
3595 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003596 } else
3597 rc = -EIO; /* bad buffer passed in */
3598
3599 cifs_buf_release(pSMB);
3600
3601 if (rc == -EAGAIN)
3602 goto QInfRetry;
3603
3604 return rc;
3605}
3606
Jeff Laytonbcd53572010-02-12 07:44:16 -05003607int
3608CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3609 u16 netfid, FILE_ALL_INFO *pFindData)
3610{
3611 struct smb_t2_qfi_req *pSMB = NULL;
3612 struct smb_t2_qfi_rsp *pSMBr = NULL;
3613 int rc = 0;
3614 int bytes_returned;
3615 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003616
Jeff Laytonbcd53572010-02-12 07:44:16 -05003617QFileInfoRetry:
3618 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3619 (void **) &pSMBr);
3620 if (rc)
3621 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003622
Jeff Laytonbcd53572010-02-12 07:44:16 -05003623 params = 2 /* level */ + 2 /* fid */;
3624 pSMB->t2.TotalDataCount = 0;
3625 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3626 /* BB find exact max data count below from sess structure BB */
3627 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3628 pSMB->t2.MaxSetupCount = 0;
3629 pSMB->t2.Reserved = 0;
3630 pSMB->t2.Flags = 0;
3631 pSMB->t2.Timeout = 0;
3632 pSMB->t2.Reserved2 = 0;
3633 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3634 Fid) - 4);
3635 pSMB->t2.DataCount = 0;
3636 pSMB->t2.DataOffset = 0;
3637 pSMB->t2.SetupCount = 1;
3638 pSMB->t2.Reserved3 = 0;
3639 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3640 byte_count = params + 1 /* pad */ ;
3641 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3642 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3643 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3644 pSMB->Pad = 0;
3645 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003646 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003647
3648 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3649 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3650 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003651 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003652 } else { /* decode response */
3653 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3654
3655 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3656 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003657 else if (get_bcc(&pSMBr->hdr) < 40)
Jeff Laytonbcd53572010-02-12 07:44:16 -05003658 rc = -EIO; /* bad smb */
3659 else if (pFindData) {
3660 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3661 memcpy((char *) pFindData,
3662 (char *) &pSMBr->hdr.Protocol +
3663 data_offset, sizeof(FILE_ALL_INFO));
3664 } else
3665 rc = -ENOMEM;
3666 }
3667 cifs_buf_release(pSMB);
3668 if (rc == -EAGAIN)
3669 goto QFileInfoRetry;
3670
3671 return rc;
3672}
Steve French6b8edfe2005-08-23 20:26:03 -07003673
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674int
3675CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3676 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003677 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003678 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003679 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680{
3681/* level 263 SMB_QUERY_FILE_ALL_INFO */
3682 TRANSACTION2_QPI_REQ *pSMB = NULL;
3683 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3684 int rc = 0;
3685 int bytes_returned;
3686 int name_len;
3687 __u16 params, byte_count;
3688
Joe Perchesb6b38f72010-04-21 03:50:45 +00003689/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690QPathInfoRetry:
3691 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3692 (void **) &pSMBr);
3693 if (rc)
3694 return rc;
3695
3696 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3697 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003698 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003699 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 name_len++; /* trailing null */
3701 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003702 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703 name_len = strnlen(searchName, PATH_MAX);
3704 name_len++; /* trailing null */
3705 strncpy(pSMB->FileName, searchName, name_len);
3706 }
3707
Steve French50c2f752007-07-13 00:33:32 +00003708 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 pSMB->TotalDataCount = 0;
3710 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003711 /* BB find exact max SMB PDU from sess structure BB */
3712 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 pSMB->MaxSetupCount = 0;
3714 pSMB->Reserved = 0;
3715 pSMB->Flags = 0;
3716 pSMB->Timeout = 0;
3717 pSMB->Reserved2 = 0;
3718 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003719 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003720 pSMB->DataCount = 0;
3721 pSMB->DataOffset = 0;
3722 pSMB->SetupCount = 1;
3723 pSMB->Reserved3 = 0;
3724 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3725 byte_count = params + 1 /* pad */ ;
3726 pSMB->TotalParameterCount = cpu_to_le16(params);
3727 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003728 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003729 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3730 else
3731 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003733 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 pSMB->ByteCount = cpu_to_le16(byte_count);
3735
3736 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3737 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3738 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003739 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 } else { /* decode response */
3741 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3742
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003743 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3744 rc = -EIO;
Jeff Layton820a8032011-05-04 08:05:26 -04003745 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 rc = -EIO; /* bad smb */
Jeff Layton820a8032011-05-04 08:05:26 -04003747 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
Steve French50c2f752007-07-13 00:33:32 +00003748 rc = -EIO; /* 24 or 26 expected but we do not read
3749 last field */
3750 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003751 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003753
3754 /* On legacy responses we do not read the last field,
3755 EAsize, fortunately since it varies by subdialect and
3756 also note it differs on Set vs. Get, ie two bytes or 4
3757 bytes depending but we don't care here */
3758 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003759 size = sizeof(FILE_INFO_STANDARD);
3760 else
3761 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 memcpy((char *) pFindData,
3763 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003764 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003765 } else
3766 rc = -ENOMEM;
3767 }
3768 cifs_buf_release(pSMB);
3769 if (rc == -EAGAIN)
3770 goto QPathInfoRetry;
3771
3772 return rc;
3773}
3774
3775int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003776CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3777 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3778{
3779 struct smb_t2_qfi_req *pSMB = NULL;
3780 struct smb_t2_qfi_rsp *pSMBr = NULL;
3781 int rc = 0;
3782 int bytes_returned;
3783 __u16 params, byte_count;
3784
3785UnixQFileInfoRetry:
3786 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3787 (void **) &pSMBr);
3788 if (rc)
3789 return rc;
3790
3791 params = 2 /* level */ + 2 /* fid */;
3792 pSMB->t2.TotalDataCount = 0;
3793 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3794 /* BB find exact max data count below from sess structure BB */
3795 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3796 pSMB->t2.MaxSetupCount = 0;
3797 pSMB->t2.Reserved = 0;
3798 pSMB->t2.Flags = 0;
3799 pSMB->t2.Timeout = 0;
3800 pSMB->t2.Reserved2 = 0;
3801 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3802 Fid) - 4);
3803 pSMB->t2.DataCount = 0;
3804 pSMB->t2.DataOffset = 0;
3805 pSMB->t2.SetupCount = 1;
3806 pSMB->t2.Reserved3 = 0;
3807 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3808 byte_count = params + 1 /* pad */ ;
3809 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3810 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3811 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3812 pSMB->Pad = 0;
3813 pSMB->Fid = netfid;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003814 inc_rfc1001_len(pSMB, byte_count);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003815
3816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3818 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003819 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003820 } else { /* decode response */
3821 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3822
Jeff Layton820a8032011-05-04 08:05:26 -04003823 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003824 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003825 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003826 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003827 rc = -EIO; /* bad smb */
3828 } else {
3829 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3830 memcpy((char *) pFindData,
3831 (char *) &pSMBr->hdr.Protocol +
3832 data_offset,
3833 sizeof(FILE_UNIX_BASIC_INFO));
3834 }
3835 }
3836
3837 cifs_buf_release(pSMB);
3838 if (rc == -EAGAIN)
3839 goto UnixQFileInfoRetry;
3840
3841 return rc;
3842}
3843
3844int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3846 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003847 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003848 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849{
3850/* SMB_QUERY_FILE_UNIX_BASIC */
3851 TRANSACTION2_QPI_REQ *pSMB = NULL;
3852 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3853 int rc = 0;
3854 int bytes_returned = 0;
3855 int name_len;
3856 __u16 params, byte_count;
3857
Joe Perchesb6b38f72010-04-21 03:50:45 +00003858 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859UnixQPathInfoRetry:
3860 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3861 (void **) &pSMBr);
3862 if (rc)
3863 return rc;
3864
3865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3866 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003867 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003868 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 name_len++; /* trailing null */
3870 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003871 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 name_len = strnlen(searchName, PATH_MAX);
3873 name_len++; /* trailing null */
3874 strncpy(pSMB->FileName, searchName, name_len);
3875 }
3876
Steve French50c2f752007-07-13 00:33:32 +00003877 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 pSMB->TotalDataCount = 0;
3879 pSMB->MaxParameterCount = cpu_to_le16(2);
3880 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003881 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 pSMB->MaxSetupCount = 0;
3883 pSMB->Reserved = 0;
3884 pSMB->Flags = 0;
3885 pSMB->Timeout = 0;
3886 pSMB->Reserved2 = 0;
3887 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003888 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889 pSMB->DataCount = 0;
3890 pSMB->DataOffset = 0;
3891 pSMB->SetupCount = 1;
3892 pSMB->Reserved3 = 0;
3893 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3894 byte_count = params + 1 /* pad */ ;
3895 pSMB->TotalParameterCount = cpu_to_le16(params);
3896 pSMB->ParameterCount = pSMB->TotalParameterCount;
3897 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3898 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00003899 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 pSMB->ByteCount = cpu_to_le16(byte_count);
3901
3902 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3903 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3904 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003905 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 } else { /* decode response */
3907 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3908
Jeff Layton820a8032011-05-04 08:05:26 -04003909 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003910 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003911 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003912 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 rc = -EIO; /* bad smb */
3914 } else {
3915 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3916 memcpy((char *) pFindData,
3917 (char *) &pSMBr->hdr.Protocol +
3918 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003919 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 }
3921 }
3922 cifs_buf_release(pSMB);
3923 if (rc == -EAGAIN)
3924 goto UnixQPathInfoRetry;
3925
3926 return rc;
3927}
3928
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929/* xid, tcon, searchName and codepage are input parms, rest are returned */
3930int
3931CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003932 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003934 __u16 *pnetfid,
3935 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936{
3937/* level 257 SMB_ */
3938 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3939 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003940 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 int rc = 0;
3942 int bytes_returned = 0;
3943 int name_len;
3944 __u16 params, byte_count;
3945
Joe Perchesb6b38f72010-04-21 03:50:45 +00003946 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003947
3948findFirstRetry:
3949 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3950 (void **) &pSMBr);
3951 if (rc)
3952 return rc;
3953
3954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3955 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003956 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003957 PATH_MAX, nls_codepage, remap);
3958 /* We can not add the asterik earlier in case
3959 it got remapped to 0xF03A as if it were part of the
3960 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003962 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003963 pSMB->FileName[name_len+1] = 0;
3964 pSMB->FileName[name_len+2] = '*';
3965 pSMB->FileName[name_len+3] = 0;
3966 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3968 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003969 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 } else { /* BB add check for overrun of SMB buf BB */
3971 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003973 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 free buffer exit; BB */
3975 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003976 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003977 pSMB->FileName[name_len+1] = '*';
3978 pSMB->FileName[name_len+2] = 0;
3979 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 }
3981
3982 params = 12 + name_len /* includes null */ ;
3983 pSMB->TotalDataCount = 0; /* no EAs */
3984 pSMB->MaxParameterCount = cpu_to_le16(10);
3985 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3986 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3987 pSMB->MaxSetupCount = 0;
3988 pSMB->Reserved = 0;
3989 pSMB->Flags = 0;
3990 pSMB->Timeout = 0;
3991 pSMB->Reserved2 = 0;
3992 byte_count = params + 1 /* pad */ ;
3993 pSMB->TotalParameterCount = cpu_to_le16(params);
3994 pSMB->ParameterCount = pSMB->TotalParameterCount;
3995 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003996 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3997 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 pSMB->DataCount = 0;
3999 pSMB->DataOffset = 0;
4000 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4001 pSMB->Reserved3 = 0;
4002 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4003 pSMB->SearchAttributes =
4004 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4005 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00004006 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
4007 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 CIFS_SEARCH_RETURN_RESUME);
4009 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4010
4011 /* BB what should we set StorageType to? Does it matter? BB */
4012 pSMB->SearchStorageType = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004013 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 pSMB->ByteCount = cpu_to_le16(byte_count);
4015
4016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004018 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019
Steve French88274812006-03-09 22:21:45 +00004020 if (rc) {/* BB add logic to retry regular search if Unix search
4021 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00004023 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07004024
Steve French88274812006-03-09 22:21:45 +00004025 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026
4027 /* BB eventually could optimize out free and realloc of buf */
4028 /* for this case */
4029 if (rc == -EAGAIN)
4030 goto findFirstRetry;
4031 } else { /* decode response */
4032 /* BB remember to free buffer if error BB */
4033 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00004034 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004035 unsigned int lnoff;
4036
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004038 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 else
Steve French4b18f2a2008-04-29 00:06:05 +00004040 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
4042 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004043 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00004044 psrch_inf->srch_entries_start =
4045 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4048 le16_to_cpu(pSMBr->t2.ParameterOffset));
4049
Steve French790fe572007-07-07 19:25:05 +00004050 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004051 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 else
Steve French4b18f2a2008-04-29 00:06:05 +00004053 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
Steve French50c2f752007-07-13 00:33:32 +00004055 psrch_inf->entries_in_buffer =
4056 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00004057 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004059 lnoff = le16_to_cpu(parms->LastNameOffset);
4060 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4061 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004062 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004063 psrch_inf->last_entry = NULL;
4064 return rc;
4065 }
4066
Steve French0752f152008-10-07 20:03:33 +00004067 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00004068 lnoff;
4069
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070 *pnetfid = parms->SearchHandle;
4071 } else {
4072 cifs_buf_release(pSMB);
4073 }
4074 }
4075
4076 return rc;
4077}
4078
4079int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004080 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081{
4082 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4083 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00004084 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 char *response_data;
4086 int rc = 0;
4087 int bytes_returned, name_len;
4088 __u16 params, byte_count;
4089
Joe Perchesb6b38f72010-04-21 03:50:45 +00004090 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
Steve French4b18f2a2008-04-29 00:06:05 +00004092 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 return -ENOENT;
4094
4095 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4096 (void **) &pSMBr);
4097 if (rc)
4098 return rc;
4099
Steve French50c2f752007-07-13 00:33:32 +00004100 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 byte_count = 0;
4102 pSMB->TotalDataCount = 0; /* no EAs */
4103 pSMB->MaxParameterCount = cpu_to_le16(8);
4104 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00004105 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
4106 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 pSMB->MaxSetupCount = 0;
4108 pSMB->Reserved = 0;
4109 pSMB->Flags = 0;
4110 pSMB->Timeout = 0;
4111 pSMB->Reserved2 = 0;
4112 pSMB->ParameterOffset = cpu_to_le16(
4113 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4114 pSMB->DataCount = 0;
4115 pSMB->DataOffset = 0;
4116 pSMB->SetupCount = 1;
4117 pSMB->Reserved3 = 0;
4118 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4119 pSMB->SearchHandle = searchHandle; /* always kept as le */
4120 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00004121 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4123 pSMB->ResumeKey = psrch_inf->resume_key;
4124 pSMB->SearchFlags =
4125 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
4126
4127 name_len = psrch_inf->resume_name_len;
4128 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00004129 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4131 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07004132 /* 14 byte parm len above enough for 2 byte null terminator */
4133 pSMB->ResumeFileName[name_len] = 0;
4134 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135 } else {
4136 rc = -EINVAL;
4137 goto FNext2_err_exit;
4138 }
4139 byte_count = params + 1 /* pad */ ;
4140 pSMB->TotalParameterCount = cpu_to_le16(params);
4141 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004142 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004144
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4146 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07004147 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148 if (rc) {
4149 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00004150 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07004151 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00004152 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00004154 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004155 } else { /* decode response */
4156 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00004157
Steve French790fe572007-07-07 19:25:05 +00004158 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00004159 unsigned int lnoff;
4160
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 /* BB fixme add lock for file (srch_info) struct here */
4162 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00004163 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 else
Steve French4b18f2a2008-04-29 00:06:05 +00004165 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 response_data = (char *) &pSMBr->hdr.Protocol +
4167 le16_to_cpu(pSMBr->t2.ParameterOffset);
4168 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4169 response_data = (char *)&pSMBr->hdr.Protocol +
4170 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00004171 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00004172 cifs_small_buf_release(
4173 psrch_inf->ntwrk_buf_start);
4174 else
4175 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 psrch_inf->srch_entries_start = response_data;
4177 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00004178 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00004179 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00004180 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 else
Steve French4b18f2a2008-04-29 00:06:05 +00004182 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00004183 psrch_inf->entries_in_buffer =
4184 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 psrch_inf->index_of_last_entry +=
4186 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00004187 lnoff = le16_to_cpu(parms->LastNameOffset);
4188 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
4189 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004190 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00004191 psrch_inf->last_entry = NULL;
4192 return rc;
4193 } else
4194 psrch_inf->last_entry =
4195 psrch_inf->srch_entries_start + lnoff;
4196
Joe Perchesb6b38f72010-04-21 03:50:45 +00004197/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4198 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199
4200 /* BB fixme add unlock here */
4201 }
4202
4203 }
4204
4205 /* BB On error, should we leave previous search buf (and count and
4206 last entry fields) intact or free the previous one? */
4207
4208 /* Note: On -EAGAIN error only caller can retry on handle based calls
4209 since file handle passed in no longer valid */
4210FNext2_err_exit:
4211 if (rc != 0)
4212 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 return rc;
4214}
4215
4216int
Steve French50c2f752007-07-13 00:33:32 +00004217CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
4218 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219{
4220 int rc = 0;
4221 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
Joe Perchesb6b38f72010-04-21 03:50:45 +00004223 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4225
4226 /* no sense returning error if session restarted
4227 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00004228 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 return 0;
4230 if (rc)
4231 return rc;
4232
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 pSMB->FileID = searchHandle;
4234 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00004235 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004236 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004237 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00004238
Steve Frencha4544342005-08-24 13:59:35 -07004239 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
4241 /* Since session is dead, search handle closed on server already */
4242 if (rc == -EAGAIN)
4243 rc = 0;
4244
4245 return rc;
4246}
4247
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248int
4249CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004250 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00004251 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00004252 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253{
4254 int rc = 0;
4255 TRANSACTION2_QPI_REQ *pSMB = NULL;
4256 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4257 int name_len, bytes_returned;
4258 __u16 params, byte_count;
4259
Joe Perchesb6b38f72010-04-21 03:50:45 +00004260 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00004261 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00004262 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263
4264GetInodeNumberRetry:
4265 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00004266 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 if (rc)
4268 return rc;
4269
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4271 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004272 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00004273 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274 name_len++; /* trailing null */
4275 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004276 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 name_len = strnlen(searchName, PATH_MAX);
4278 name_len++; /* trailing null */
4279 strncpy(pSMB->FileName, searchName, name_len);
4280 }
4281
4282 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4283 pSMB->TotalDataCount = 0;
4284 pSMB->MaxParameterCount = cpu_to_le16(2);
4285 /* BB find exact max data count below from sess structure BB */
4286 pSMB->MaxDataCount = cpu_to_le16(4000);
4287 pSMB->MaxSetupCount = 0;
4288 pSMB->Reserved = 0;
4289 pSMB->Flags = 0;
4290 pSMB->Timeout = 0;
4291 pSMB->Reserved2 = 0;
4292 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004293 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 pSMB->DataCount = 0;
4295 pSMB->DataOffset = 0;
4296 pSMB->SetupCount = 1;
4297 pSMB->Reserved3 = 0;
4298 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4299 byte_count = params + 1 /* pad */ ;
4300 pSMB->TotalParameterCount = cpu_to_le16(params);
4301 pSMB->ParameterCount = pSMB->TotalParameterCount;
4302 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4303 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004304 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 pSMB->ByteCount = cpu_to_le16(byte_count);
4306
4307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4309 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004310 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 } else {
4312 /* decode response */
4313 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 /* BB also check enough total bytes returned */
Jeff Layton820a8032011-05-04 08:05:26 -04004315 if (rc || get_bcc(&pSMBr->hdr) < 2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 /* If rc should we check for EOPNOSUPP and
4317 disable the srvino flag? or in caller? */
4318 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00004319 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4321 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00004322 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00004324 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004325 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 rc = -EIO;
4327 goto GetInodeNumOut;
4328 }
4329 pfinfo = (struct file_internal_info *)
4330 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00004331 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 }
4333 }
4334GetInodeNumOut:
4335 cifs_buf_release(pSMB);
4336 if (rc == -EAGAIN)
4337 goto GetInodeNumberRetry;
4338 return rc;
4339}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Igor Mammedovfec45852008-05-16 13:06:30 +04004341/* parses DFS refferal V3 structure
4342 * caller is responsible for freeing target_nodes
4343 * returns:
4344 * on success - 0
4345 * on failure - errno
4346 */
4347static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004348parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004349 unsigned int *num_of_nodes,
4350 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004351 const struct nls_table *nls_codepage, int remap,
4352 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004353{
4354 int i, rc = 0;
4355 char *data_end;
4356 bool is_unicode;
4357 struct dfs_referral_level_3 *ref;
4358
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004359 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4360 is_unicode = true;
4361 else
4362 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004363 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4364
4365 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004366 cERROR(1, "num_referrals: must be at least > 0,"
4367 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004368 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004369 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004370 }
4371
4372 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004373 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004374 cERROR(1, "Referrals of V%d version are not supported,"
4375 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004376 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004377 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004378 }
4379
4380 /* get the upper boundary of the resp buffer */
4381 data_end = (char *)(&(pSMBr->PathConsumed)) +
4382 le16_to_cpu(pSMBr->t2.DataCount);
4383
Steve Frenchf19159d2010-04-21 04:12:10 +00004384 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004385 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004386 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004387
4388 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4389 *num_of_nodes, GFP_KERNEL);
4390 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004391 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004392 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004393 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004394 }
4395
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004396 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004397 for (i = 0; i < *num_of_nodes; i++) {
4398 char *temp;
4399 int max_len;
4400 struct dfs_info3_param *node = (*target_nodes)+i;
4401
Steve French0e0d2cf2009-05-01 05:27:32 +00004402 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004403 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004404 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4405 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004406 if (tmp == NULL) {
4407 rc = -ENOMEM;
4408 goto parse_DFS_referrals_exit;
4409 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004410 cifsConvertToUCS((__le16 *) tmp, searchName,
4411 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004412 node->path_consumed = cifs_ucs2_bytes(tmp,
4413 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004414 nls_codepage);
4415 kfree(tmp);
4416 } else
4417 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4418
Igor Mammedovfec45852008-05-16 13:06:30 +04004419 node->server_type = le16_to_cpu(ref->ServerType);
4420 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4421
4422 /* copy DfsPath */
4423 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4424 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004425 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4426 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004427 if (!node->path_name) {
4428 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004429 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004430 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004431
4432 /* copy link target UNC */
4433 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4434 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004435 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4436 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004437 if (!node->node_name)
4438 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004439 }
4440
Steve Frencha1fe78f2008-05-16 18:48:38 +00004441parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004442 if (rc) {
4443 free_dfs_info_array(*target_nodes, *num_of_nodes);
4444 *target_nodes = NULL;
4445 *num_of_nodes = 0;
4446 }
4447 return rc;
4448}
4449
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450int
4451CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4452 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004453 struct dfs_info3_param **target_nodes,
4454 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004455 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456{
4457/* TRANS2_GET_DFS_REFERRAL */
4458 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4459 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 int rc = 0;
4461 int bytes_returned;
4462 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004464 *num_of_nodes = 0;
4465 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466
Joe Perchesb6b38f72010-04-21 03:50:45 +00004467 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 if (ses == NULL)
4469 return -ENODEV;
4470getDFSRetry:
4471 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4472 (void **) &pSMBr);
4473 if (rc)
4474 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004475
4476 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004477 but should never be null here anyway */
4478 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 pSMB->hdr.Tid = ses->ipc_tid;
4480 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004481 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004483 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485
4486 if (ses->capabilities & CAP_UNICODE) {
4487 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4488 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004489 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004490 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 name_len++; /* trailing null */
4492 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004493 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 name_len = strnlen(searchName, PATH_MAX);
4495 name_len++; /* trailing null */
4496 strncpy(pSMB->RequestFileName, searchName, name_len);
4497 }
4498
Steve French790fe572007-07-07 19:25:05 +00004499 if (ses->server) {
4500 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004501 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4502 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4503 }
4504
Steve French50c2f752007-07-13 00:33:32 +00004505 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004506
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 params = 2 /* level */ + name_len /*includes null */ ;
4508 pSMB->TotalDataCount = 0;
4509 pSMB->DataCount = 0;
4510 pSMB->DataOffset = 0;
4511 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004512 /* BB find exact max SMB PDU from sess structure BB */
4513 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 pSMB->MaxSetupCount = 0;
4515 pSMB->Reserved = 0;
4516 pSMB->Flags = 0;
4517 pSMB->Timeout = 0;
4518 pSMB->Reserved2 = 0;
4519 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004520 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004521 pSMB->SetupCount = 1;
4522 pSMB->Reserved3 = 0;
4523 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4524 byte_count = params + 3 /* pad */ ;
4525 pSMB->ParameterCount = cpu_to_le16(params);
4526 pSMB->TotalParameterCount = pSMB->ParameterCount;
4527 pSMB->MaxReferralLevel = cpu_to_le16(3);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004528 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 pSMB->ByteCount = cpu_to_le16(byte_count);
4530
4531 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4532 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4533 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004534 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004535 goto GetDFSRefExit;
4536 }
4537 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004539 /* BB Also check if enough total bytes returned? */
Jeff Layton820a8032011-05-04 08:05:26 -04004540 if (rc || get_bcc(&pSMBr->hdr) < 17) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004541 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004542 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004544
Joe Perchesb6b38f72010-04-21 03:50:45 +00004545 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004546 get_bcc(&pSMBr->hdr),
Joe Perchesb6b38f72010-04-21 03:50:45 +00004547 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004548
4549 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004550 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004551 target_nodes, nls_codepage, remap,
4552 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004553
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004555 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
4557 if (rc == -EAGAIN)
4558 goto getDFSRetry;
4559
4560 return rc;
4561}
4562
Steve French20962432005-09-21 22:05:57 -07004563/* Query File System Info such as free space to old servers such as Win 9x */
4564int
4565SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4566{
4567/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4568 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4569 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4570 FILE_SYSTEM_ALLOC_INFO *response_data;
4571 int rc = 0;
4572 int bytes_returned = 0;
4573 __u16 params, byte_count;
4574
Joe Perchesb6b38f72010-04-21 03:50:45 +00004575 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004576oldQFSInfoRetry:
4577 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4578 (void **) &pSMBr);
4579 if (rc)
4580 return rc;
Steve French20962432005-09-21 22:05:57 -07004581
4582 params = 2; /* level */
4583 pSMB->TotalDataCount = 0;
4584 pSMB->MaxParameterCount = cpu_to_le16(2);
4585 pSMB->MaxDataCount = cpu_to_le16(1000);
4586 pSMB->MaxSetupCount = 0;
4587 pSMB->Reserved = 0;
4588 pSMB->Flags = 0;
4589 pSMB->Timeout = 0;
4590 pSMB->Reserved2 = 0;
4591 byte_count = params + 1 /* pad */ ;
4592 pSMB->TotalParameterCount = cpu_to_le16(params);
4593 pSMB->ParameterCount = pSMB->TotalParameterCount;
4594 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4595 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4596 pSMB->DataCount = 0;
4597 pSMB->DataOffset = 0;
4598 pSMB->SetupCount = 1;
4599 pSMB->Reserved3 = 0;
4600 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4601 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004602 inc_rfc1001_len(pSMB, byte_count);
Steve French20962432005-09-21 22:05:57 -07004603 pSMB->ByteCount = cpu_to_le16(byte_count);
4604
4605 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4606 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4607 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004608 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004609 } else { /* decode response */
4610 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4611
Jeff Layton820a8032011-05-04 08:05:26 -04004612 if (rc || get_bcc(&pSMBr->hdr) < 18)
Steve French20962432005-09-21 22:05:57 -07004613 rc = -EIO; /* bad smb */
4614 else {
4615 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004616 cFYI(1, "qfsinf resp BCC: %d Offset %d",
Jeff Layton820a8032011-05-04 08:05:26 -04004617 get_bcc(&pSMBr->hdr), data_offset);
Steve French20962432005-09-21 22:05:57 -07004618
Steve French50c2f752007-07-13 00:33:32 +00004619 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004620 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4621 FSData->f_bsize =
4622 le16_to_cpu(response_data->BytesPerSector) *
4623 le32_to_cpu(response_data->
4624 SectorsPerAllocationUnit);
4625 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004626 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004627 FSData->f_bfree = FSData->f_bavail =
4628 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004629 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4630 (unsigned long long)FSData->f_blocks,
4631 (unsigned long long)FSData->f_bfree,
4632 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004633 }
4634 }
4635 cifs_buf_release(pSMB);
4636
4637 if (rc == -EAGAIN)
4638 goto oldQFSInfoRetry;
4639
4640 return rc;
4641}
4642
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643int
Steve French737b7582005-04-28 22:41:06 -07004644CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645{
4646/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4647 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4648 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4649 FILE_SYSTEM_INFO *response_data;
4650 int rc = 0;
4651 int bytes_returned = 0;
4652 __u16 params, byte_count;
4653
Joe Perchesb6b38f72010-04-21 03:50:45 +00004654 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655QFSInfoRetry:
4656 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4657 (void **) &pSMBr);
4658 if (rc)
4659 return rc;
4660
4661 params = 2; /* level */
4662 pSMB->TotalDataCount = 0;
4663 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004664 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 pSMB->MaxSetupCount = 0;
4666 pSMB->Reserved = 0;
4667 pSMB->Flags = 0;
4668 pSMB->Timeout = 0;
4669 pSMB->Reserved2 = 0;
4670 byte_count = params + 1 /* pad */ ;
4671 pSMB->TotalParameterCount = cpu_to_le16(params);
4672 pSMB->ParameterCount = pSMB->TotalParameterCount;
4673 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004674 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 pSMB->DataCount = 0;
4676 pSMB->DataOffset = 0;
4677 pSMB->SetupCount = 1;
4678 pSMB->Reserved3 = 0;
4679 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4680 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004681 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682 pSMB->ByteCount = cpu_to_le16(byte_count);
4683
4684 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4685 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4686 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004687 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004689 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690
Jeff Layton820a8032011-05-04 08:05:26 -04004691 if (rc || get_bcc(&pSMBr->hdr) < 24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 rc = -EIO; /* bad smb */
4693 else {
4694 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695
4696 response_data =
4697 (FILE_SYSTEM_INFO
4698 *) (((char *) &pSMBr->hdr.Protocol) +
4699 data_offset);
4700 FSData->f_bsize =
4701 le32_to_cpu(response_data->BytesPerSector) *
4702 le32_to_cpu(response_data->
4703 SectorsPerAllocationUnit);
4704 FSData->f_blocks =
4705 le64_to_cpu(response_data->TotalAllocationUnits);
4706 FSData->f_bfree = FSData->f_bavail =
4707 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004708 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4709 (unsigned long long)FSData->f_blocks,
4710 (unsigned long long)FSData->f_bfree,
4711 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 }
4713 }
4714 cifs_buf_release(pSMB);
4715
4716 if (rc == -EAGAIN)
4717 goto QFSInfoRetry;
4718
4719 return rc;
4720}
4721
4722int
Steve French737b7582005-04-28 22:41:06 -07004723CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724{
4725/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4726 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4727 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4728 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4729 int rc = 0;
4730 int bytes_returned = 0;
4731 __u16 params, byte_count;
4732
Joe Perchesb6b38f72010-04-21 03:50:45 +00004733 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734QFSAttributeRetry:
4735 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4736 (void **) &pSMBr);
4737 if (rc)
4738 return rc;
4739
4740 params = 2; /* level */
4741 pSMB->TotalDataCount = 0;
4742 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004743 /* BB find exact max SMB PDU from sess structure BB */
4744 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 pSMB->MaxSetupCount = 0;
4746 pSMB->Reserved = 0;
4747 pSMB->Flags = 0;
4748 pSMB->Timeout = 0;
4749 pSMB->Reserved2 = 0;
4750 byte_count = params + 1 /* pad */ ;
4751 pSMB->TotalParameterCount = cpu_to_le16(params);
4752 pSMB->ParameterCount = pSMB->TotalParameterCount;
4753 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004754 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 pSMB->DataCount = 0;
4756 pSMB->DataOffset = 0;
4757 pSMB->SetupCount = 1;
4758 pSMB->Reserved3 = 0;
4759 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4760 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004761 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 pSMB->ByteCount = cpu_to_le16(byte_count);
4763
4764 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4765 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4766 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004767 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 } else { /* decode response */
4769 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4770
Jeff Layton820a8032011-05-04 08:05:26 -04004771 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Steve French50c2f752007-07-13 00:33:32 +00004772 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 rc = -EIO; /* bad smb */
4774 } else {
4775 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4776 response_data =
4777 (FILE_SYSTEM_ATTRIBUTE_INFO
4778 *) (((char *) &pSMBr->hdr.Protocol) +
4779 data_offset);
4780 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004781 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 }
4783 }
4784 cifs_buf_release(pSMB);
4785
4786 if (rc == -EAGAIN)
4787 goto QFSAttributeRetry;
4788
4789 return rc;
4790}
4791
4792int
Steve French737b7582005-04-28 22:41:06 -07004793CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794{
4795/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4796 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4797 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4798 FILE_SYSTEM_DEVICE_INFO *response_data;
4799 int rc = 0;
4800 int bytes_returned = 0;
4801 __u16 params, byte_count;
4802
Joe Perchesb6b38f72010-04-21 03:50:45 +00004803 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804QFSDeviceRetry:
4805 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4806 (void **) &pSMBr);
4807 if (rc)
4808 return rc;
4809
4810 params = 2; /* level */
4811 pSMB->TotalDataCount = 0;
4812 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004813 /* BB find exact max SMB PDU from sess structure BB */
4814 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815 pSMB->MaxSetupCount = 0;
4816 pSMB->Reserved = 0;
4817 pSMB->Flags = 0;
4818 pSMB->Timeout = 0;
4819 pSMB->Reserved2 = 0;
4820 byte_count = params + 1 /* pad */ ;
4821 pSMB->TotalParameterCount = cpu_to_le16(params);
4822 pSMB->ParameterCount = pSMB->TotalParameterCount;
4823 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004824 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825
4826 pSMB->DataCount = 0;
4827 pSMB->DataOffset = 0;
4828 pSMB->SetupCount = 1;
4829 pSMB->Reserved3 = 0;
4830 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4831 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004832 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 pSMB->ByteCount = cpu_to_le16(byte_count);
4834
4835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4837 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004838 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 } else { /* decode response */
4840 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4841
Jeff Layton820a8032011-05-04 08:05:26 -04004842 if (rc || get_bcc(&pSMBr->hdr) <
4843 sizeof(FILE_SYSTEM_DEVICE_INFO))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004844 rc = -EIO; /* bad smb */
4845 else {
4846 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4847 response_data =
Steve French737b7582005-04-28 22:41:06 -07004848 (FILE_SYSTEM_DEVICE_INFO *)
4849 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 data_offset);
4851 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004852 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853 }
4854 }
4855 cifs_buf_release(pSMB);
4856
4857 if (rc == -EAGAIN)
4858 goto QFSDeviceRetry;
4859
4860 return rc;
4861}
4862
4863int
Steve French737b7582005-04-28 22:41:06 -07004864CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865{
4866/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4867 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4868 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4869 FILE_SYSTEM_UNIX_INFO *response_data;
4870 int rc = 0;
4871 int bytes_returned = 0;
4872 __u16 params, byte_count;
4873
Joe Perchesb6b38f72010-04-21 03:50:45 +00004874 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004875QFSUnixRetry:
Jeff Laytonf5695992010-09-29 15:27:08 -04004876 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4877 (void **) &pSMB, (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 if (rc)
4879 return rc;
4880
4881 params = 2; /* level */
4882 pSMB->TotalDataCount = 0;
4883 pSMB->DataCount = 0;
4884 pSMB->DataOffset = 0;
4885 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004886 /* BB find exact max SMB PDU from sess structure BB */
4887 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 pSMB->MaxSetupCount = 0;
4889 pSMB->Reserved = 0;
4890 pSMB->Flags = 0;
4891 pSMB->Timeout = 0;
4892 pSMB->Reserved2 = 0;
4893 byte_count = params + 1 /* pad */ ;
4894 pSMB->ParameterCount = cpu_to_le16(params);
4895 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004896 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4897 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004898 pSMB->SetupCount = 1;
4899 pSMB->Reserved3 = 0;
4900 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4901 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004902 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 pSMB->ByteCount = cpu_to_le16(byte_count);
4904
4905 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4906 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4907 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004908 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 } else { /* decode response */
4910 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4911
Jeff Layton820a8032011-05-04 08:05:26 -04004912 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 rc = -EIO; /* bad smb */
4914 } else {
4915 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4916 response_data =
4917 (FILE_SYSTEM_UNIX_INFO
4918 *) (((char *) &pSMBr->hdr.Protocol) +
4919 data_offset);
4920 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004921 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 }
4923 }
4924 cifs_buf_release(pSMB);
4925
4926 if (rc == -EAGAIN)
4927 goto QFSUnixRetry;
4928
4929
4930 return rc;
4931}
4932
Jeremy Allisonac670552005-06-22 17:26:35 -07004933int
Steve French45abc6e2005-06-23 13:42:03 -05004934CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004935{
4936/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4937 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4938 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4939 int rc = 0;
4940 int bytes_returned = 0;
4941 __u16 params, param_offset, offset, byte_count;
4942
Joe Perchesb6b38f72010-04-21 03:50:45 +00004943 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004944SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004945 /* BB switch to small buf init to save memory */
Jeff Laytonf5695992010-09-29 15:27:08 -04004946 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
4947 (void **) &pSMB, (void **) &pSMBr);
Jeremy Allisonac670552005-06-22 17:26:35 -07004948 if (rc)
4949 return rc;
4950
4951 params = 4; /* 2 bytes zero followed by info level. */
4952 pSMB->MaxSetupCount = 0;
4953 pSMB->Reserved = 0;
4954 pSMB->Flags = 0;
4955 pSMB->Timeout = 0;
4956 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004957 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4958 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004959 offset = param_offset + params;
4960
4961 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004962 /* BB find exact max SMB PDU from sess structure BB */
4963 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004964 pSMB->SetupCount = 1;
4965 pSMB->Reserved3 = 0;
4966 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4967 byte_count = 1 /* pad */ + params + 12;
4968
4969 pSMB->DataCount = cpu_to_le16(12);
4970 pSMB->ParameterCount = cpu_to_le16(params);
4971 pSMB->TotalDataCount = pSMB->DataCount;
4972 pSMB->TotalParameterCount = pSMB->ParameterCount;
4973 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4974 pSMB->DataOffset = cpu_to_le16(offset);
4975
4976 /* Params. */
4977 pSMB->FileNum = 0;
4978 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4979
4980 /* Data. */
4981 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4982 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4983 pSMB->ClientUnixCap = cpu_to_le64(cap);
4984
Steve Frenchbe8e3b02011-04-29 05:40:20 +00004985 inc_rfc1001_len(pSMB, byte_count);
Jeremy Allisonac670552005-06-22 17:26:35 -07004986 pSMB->ByteCount = cpu_to_le16(byte_count);
4987
4988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4990 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004991 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004992 } else { /* decode response */
4993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004994 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004995 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004996 }
4997 cifs_buf_release(pSMB);
4998
4999 if (rc == -EAGAIN)
5000 goto SETFSUnixRetry;
5001
5002 return rc;
5003}
5004
5005
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006
5007int
5008CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07005009 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005010{
5011/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5012 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5013 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5014 FILE_SYSTEM_POSIX_INFO *response_data;
5015 int rc = 0;
5016 int bytes_returned = 0;
5017 __u16 params, byte_count;
5018
Joe Perchesb6b38f72010-04-21 03:50:45 +00005019 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020QFSPosixRetry:
5021 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5022 (void **) &pSMBr);
5023 if (rc)
5024 return rc;
5025
5026 params = 2; /* level */
5027 pSMB->TotalDataCount = 0;
5028 pSMB->DataCount = 0;
5029 pSMB->DataOffset = 0;
5030 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005031 /* BB find exact max SMB PDU from sess structure BB */
5032 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 pSMB->MaxSetupCount = 0;
5034 pSMB->Reserved = 0;
5035 pSMB->Flags = 0;
5036 pSMB->Timeout = 0;
5037 pSMB->Reserved2 = 0;
5038 byte_count = params + 1 /* pad */ ;
5039 pSMB->ParameterCount = cpu_to_le16(params);
5040 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00005041 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5042 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005043 pSMB->SetupCount = 1;
5044 pSMB->Reserved3 = 0;
5045 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5046 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005047 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 pSMB->ByteCount = cpu_to_le16(byte_count);
5049
5050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5052 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005053 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 } else { /* decode response */
5055 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5056
Jeff Layton820a8032011-05-04 08:05:26 -04005057 if (rc || get_bcc(&pSMBr->hdr) < 13) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 rc = -EIO; /* bad smb */
5059 } else {
5060 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5061 response_data =
5062 (FILE_SYSTEM_POSIX_INFO
5063 *) (((char *) &pSMBr->hdr.Protocol) +
5064 data_offset);
5065 FSData->f_bsize =
5066 le32_to_cpu(response_data->BlockSize);
5067 FSData->f_blocks =
5068 le64_to_cpu(response_data->TotalBlocks);
5069 FSData->f_bfree =
5070 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00005071 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 FSData->f_bavail = FSData->f_bfree;
5073 } else {
5074 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00005075 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005076 }
Steve French790fe572007-07-07 19:25:05 +00005077 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00005079 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00005080 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00005082 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083 }
5084 }
5085 cifs_buf_release(pSMB);
5086
5087 if (rc == -EAGAIN)
5088 goto QFSPosixRetry;
5089
5090 return rc;
5091}
5092
5093
Steve French50c2f752007-07-13 00:33:32 +00005094/* We can not use write of zero bytes trick to
5095 set file size due to need for large file support. Also note that
5096 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 routine which is only needed to work around a sharing violation bug
5098 in Samba which this routine can run into */
5099
5100int
5101CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00005102 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07005103 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104{
5105 struct smb_com_transaction2_spi_req *pSMB = NULL;
5106 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5107 struct file_end_of_file_info *parm_data;
5108 int name_len;
5109 int rc = 0;
5110 int bytes_returned = 0;
5111 __u16 params, byte_count, data_count, param_offset, offset;
5112
Joe Perchesb6b38f72010-04-21 03:50:45 +00005113 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114SetEOFRetry:
5115 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5116 (void **) &pSMBr);
5117 if (rc)
5118 return rc;
5119
5120 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5121 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005122 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005123 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 name_len++; /* trailing null */
5125 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005126 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 name_len = strnlen(fileName, PATH_MAX);
5128 name_len++; /* trailing null */
5129 strncpy(pSMB->FileName, fileName, name_len);
5130 }
5131 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005132 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07005134 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 pSMB->MaxSetupCount = 0;
5136 pSMB->Reserved = 0;
5137 pSMB->Flags = 0;
5138 pSMB->Timeout = 0;
5139 pSMB->Reserved2 = 0;
5140 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005141 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005142 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00005143 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00005144 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5145 pSMB->InformationLevel =
5146 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5147 else
5148 pSMB->InformationLevel =
5149 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5150 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5152 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005153 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 else
5155 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005156 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157 }
5158
5159 parm_data =
5160 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5161 offset);
5162 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5163 pSMB->DataOffset = cpu_to_le16(offset);
5164 pSMB->SetupCount = 1;
5165 pSMB->Reserved3 = 0;
5166 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5167 byte_count = 3 /* pad */ + params + data_count;
5168 pSMB->DataCount = cpu_to_le16(data_count);
5169 pSMB->TotalDataCount = pSMB->DataCount;
5170 pSMB->ParameterCount = cpu_to_le16(params);
5171 pSMB->TotalParameterCount = pSMB->ParameterCount;
5172 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005173 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005174 parm_data->FileSize = cpu_to_le64(size);
5175 pSMB->ByteCount = cpu_to_le16(byte_count);
5176 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5177 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005178 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005179 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005180
5181 cifs_buf_release(pSMB);
5182
5183 if (rc == -EAGAIN)
5184 goto SetEOFRetry;
5185
5186 return rc;
5187}
5188
5189int
Steve French50c2f752007-07-13 00:33:32 +00005190CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00005191 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192{
5193 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 struct file_end_of_file_info *parm_data;
5195 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 __u16 params, param_offset, offset, byte_count, count;
5197
Joe Perchesb6b38f72010-04-21 03:50:45 +00005198 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5199 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07005200 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5201
Linus Torvalds1da177e2005-04-16 15:20:36 -07005202 if (rc)
5203 return rc;
5204
5205 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5206 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005207
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 params = 6;
5209 pSMB->MaxSetupCount = 0;
5210 pSMB->Reserved = 0;
5211 pSMB->Flags = 0;
5212 pSMB->Timeout = 0;
5213 pSMB->Reserved2 = 0;
5214 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5215 offset = param_offset + params;
5216
Linus Torvalds1da177e2005-04-16 15:20:36 -07005217 count = sizeof(struct file_end_of_file_info);
5218 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005219 /* BB find exact max SMB PDU from sess structure BB */
5220 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 pSMB->SetupCount = 1;
5222 pSMB->Reserved3 = 0;
5223 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5224 byte_count = 3 /* pad */ + params + count;
5225 pSMB->DataCount = cpu_to_le16(count);
5226 pSMB->ParameterCount = cpu_to_le16(params);
5227 pSMB->TotalDataCount = pSMB->DataCount;
5228 pSMB->TotalParameterCount = pSMB->ParameterCount;
5229 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5230 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00005231 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5232 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005233 pSMB->DataOffset = cpu_to_le16(offset);
5234 parm_data->FileSize = cpu_to_le64(size);
5235 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00005236 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5238 pSMB->InformationLevel =
5239 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5240 else
5241 pSMB->InformationLevel =
5242 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00005243 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5245 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005246 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 else
5248 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00005249 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250 }
5251 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005252 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00005254 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005256 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 }
5258
Steve French50c2f752007-07-13 00:33:32 +00005259 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260 since file handle passed in no longer valid */
5261
5262 return rc;
5263}
5264
Steve French50c2f752007-07-13 00:33:32 +00005265/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07005266 an open handle, rather than by pathname - this is awkward due to
5267 potential access conflicts on the open, but it is unavoidable for these
5268 old servers since the only other choice is to go from 100 nanosecond DCE
5269 time and resort to the original setpathinfo level which takes the ancient
5270 DOS time format with 2 second granularity */
5271int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005272CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5273 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005274{
5275 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005276 char *data_offset;
5277 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005278 __u16 params, param_offset, offset, byte_count, count;
5279
Joe Perchesb6b38f72010-04-21 03:50:45 +00005280 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07005281 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5282
Linus Torvalds1da177e2005-04-16 15:20:36 -07005283 if (rc)
5284 return rc;
5285
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04005286 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5287 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00005288
Linus Torvalds1da177e2005-04-16 15:20:36 -07005289 params = 6;
5290 pSMB->MaxSetupCount = 0;
5291 pSMB->Reserved = 0;
5292 pSMB->Flags = 0;
5293 pSMB->Timeout = 0;
5294 pSMB->Reserved2 = 0;
5295 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5296 offset = param_offset + params;
5297
Steve French50c2f752007-07-13 00:33:32 +00005298 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299
Steve French26f57362007-08-30 22:09:15 +00005300 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005302 /* BB find max SMB PDU from sess */
5303 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005304 pSMB->SetupCount = 1;
5305 pSMB->Reserved3 = 0;
5306 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5307 byte_count = 3 /* pad */ + params + count;
5308 pSMB->DataCount = cpu_to_le16(count);
5309 pSMB->ParameterCount = cpu_to_le16(params);
5310 pSMB->TotalDataCount = pSMB->DataCount;
5311 pSMB->TotalParameterCount = pSMB->ParameterCount;
5312 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5313 pSMB->DataOffset = cpu_to_le16(offset);
5314 pSMB->Fid = fid;
5315 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5316 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5317 else
5318 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5319 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005320 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005322 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00005323 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005324 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005325 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326
Steve French50c2f752007-07-13 00:33:32 +00005327 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07005328 since file handle passed in no longer valid */
5329
5330 return rc;
5331}
5332
Jeff Layton6d22f092008-09-23 11:48:35 -04005333int
5334CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
5335 bool delete_file, __u16 fid, __u32 pid_of_opener)
5336{
5337 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5338 char *data_offset;
5339 int rc = 0;
5340 __u16 params, param_offset, offset, byte_count, count;
5341
Joe Perchesb6b38f72010-04-21 03:50:45 +00005342 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005343 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5344
5345 if (rc)
5346 return rc;
5347
5348 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5349 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5350
5351 params = 6;
5352 pSMB->MaxSetupCount = 0;
5353 pSMB->Reserved = 0;
5354 pSMB->Flags = 0;
5355 pSMB->Timeout = 0;
5356 pSMB->Reserved2 = 0;
5357 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5358 offset = param_offset + params;
5359
5360 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5361
5362 count = 1;
5363 pSMB->MaxParameterCount = cpu_to_le16(2);
5364 /* BB find max SMB PDU from sess */
5365 pSMB->MaxDataCount = cpu_to_le16(1000);
5366 pSMB->SetupCount = 1;
5367 pSMB->Reserved3 = 0;
5368 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5369 byte_count = 3 /* pad */ + params + count;
5370 pSMB->DataCount = cpu_to_le16(count);
5371 pSMB->ParameterCount = cpu_to_le16(params);
5372 pSMB->TotalDataCount = pSMB->DataCount;
5373 pSMB->TotalParameterCount = pSMB->ParameterCount;
5374 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5375 pSMB->DataOffset = cpu_to_le16(offset);
5376 pSMB->Fid = fid;
5377 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5378 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005379 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton6d22f092008-09-23 11:48:35 -04005380 pSMB->ByteCount = cpu_to_le16(byte_count);
5381 *data_offset = delete_file ? 1 : 0;
5382 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5383 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005384 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005385
5386 return rc;
5387}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388
5389int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005390CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5391 const char *fileName, const FILE_BASIC_INFO *data,
5392 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393{
5394 TRANSACTION2_SPI_REQ *pSMB = NULL;
5395 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5396 int name_len;
5397 int rc = 0;
5398 int bytes_returned = 0;
5399 char *data_offset;
5400 __u16 params, param_offset, offset, byte_count, count;
5401
Joe Perchesb6b38f72010-04-21 03:50:45 +00005402 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403
5404SetTimesRetry:
5405 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5406 (void **) &pSMBr);
5407 if (rc)
5408 return rc;
5409
5410 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5411 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005412 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005413 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 name_len++; /* trailing null */
5415 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005416 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 name_len = strnlen(fileName, PATH_MAX);
5418 name_len++; /* trailing null */
5419 strncpy(pSMB->FileName, fileName, name_len);
5420 }
5421
5422 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005423 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005425 /* BB find max SMB PDU from sess structure BB */
5426 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 pSMB->MaxSetupCount = 0;
5428 pSMB->Reserved = 0;
5429 pSMB->Flags = 0;
5430 pSMB->Timeout = 0;
5431 pSMB->Reserved2 = 0;
5432 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005433 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 offset = param_offset + params;
5435 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5436 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5437 pSMB->DataOffset = cpu_to_le16(offset);
5438 pSMB->SetupCount = 1;
5439 pSMB->Reserved3 = 0;
5440 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5441 byte_count = 3 /* pad */ + params + count;
5442
5443 pSMB->DataCount = cpu_to_le16(count);
5444 pSMB->ParameterCount = cpu_to_le16(params);
5445 pSMB->TotalDataCount = pSMB->DataCount;
5446 pSMB->TotalParameterCount = pSMB->ParameterCount;
5447 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5448 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5449 else
5450 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5451 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005452 inc_rfc1001_len(pSMB, byte_count);
Steve French26f57362007-08-30 22:09:15 +00005453 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005454 pSMB->ByteCount = cpu_to_le16(byte_count);
5455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005457 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005458 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
5460 cifs_buf_release(pSMB);
5461
5462 if (rc == -EAGAIN)
5463 goto SetTimesRetry;
5464
5465 return rc;
5466}
5467
5468/* Can not be used to set time stamps yet (due to old DOS time format) */
5469/* Can be used to set attributes */
5470#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5471 handling it anyway and NT4 was what we thought it would be needed for
5472 Do not delete it until we prove whether needed for Win9x though */
5473int
5474CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5475 __u16 dos_attrs, const struct nls_table *nls_codepage)
5476{
5477 SETATTR_REQ *pSMB = NULL;
5478 SETATTR_RSP *pSMBr = NULL;
5479 int rc = 0;
5480 int bytes_returned;
5481 int name_len;
5482
Joe Perchesb6b38f72010-04-21 03:50:45 +00005483 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484
5485SetAttrLgcyRetry:
5486 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5487 (void **) &pSMBr);
5488 if (rc)
5489 return rc;
5490
5491 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5492 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005493 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494 PATH_MAX, nls_codepage);
5495 name_len++; /* trailing null */
5496 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005497 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 name_len = strnlen(fileName, PATH_MAX);
5499 name_len++; /* trailing null */
5500 strncpy(pSMB->fileName, fileName, name_len);
5501 }
5502 pSMB->attr = cpu_to_le16(dos_attrs);
5503 pSMB->BufferFormat = 0x04;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005504 inc_rfc1001_len(pSMB, name_len + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5506 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5507 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005508 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005509 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510
5511 cifs_buf_release(pSMB);
5512
5513 if (rc == -EAGAIN)
5514 goto SetAttrLgcyRetry;
5515
5516 return rc;
5517}
5518#endif /* temporarily unneeded SetAttr legacy function */
5519
Jeff Layton654cf142009-07-09 20:02:49 -04005520static void
5521cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5522 const struct cifs_unix_set_info_args *args)
5523{
5524 u64 mode = args->mode;
5525
5526 /*
5527 * Samba server ignores set of file size to zero due to bugs in some
5528 * older clients, but we should be precise - we use SetFileSize to
5529 * set file size and do not want to truncate file size to zero
Lucas De Marchi25985ed2011-03-30 22:57:33 -03005530 * accidentally as happened on one Samba server beta by putting
Jeff Layton654cf142009-07-09 20:02:49 -04005531 * zero instead of -1 here
5532 */
5533 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5534 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5535 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5536 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5537 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5538 data_offset->Uid = cpu_to_le64(args->uid);
5539 data_offset->Gid = cpu_to_le64(args->gid);
5540 /* better to leave device as zero when it is */
5541 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5542 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5543 data_offset->Permissions = cpu_to_le64(mode);
5544
5545 if (S_ISREG(mode))
5546 data_offset->Type = cpu_to_le32(UNIX_FILE);
5547 else if (S_ISDIR(mode))
5548 data_offset->Type = cpu_to_le32(UNIX_DIR);
5549 else if (S_ISLNK(mode))
5550 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5551 else if (S_ISCHR(mode))
5552 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5553 else if (S_ISBLK(mode))
5554 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5555 else if (S_ISFIFO(mode))
5556 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5557 else if (S_ISSOCK(mode))
5558 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5559}
5560
Linus Torvalds1da177e2005-04-16 15:20:36 -07005561int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005562CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5563 const struct cifs_unix_set_info_args *args,
5564 u16 fid, u32 pid_of_opener)
5565{
5566 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5567 FILE_UNIX_BASIC_INFO *data_offset;
5568 int rc = 0;
5569 u16 params, param_offset, offset, byte_count, count;
5570
Joe Perchesb6b38f72010-04-21 03:50:45 +00005571 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005572 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5573
5574 if (rc)
5575 return rc;
5576
5577 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5578 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5579
5580 params = 6;
5581 pSMB->MaxSetupCount = 0;
5582 pSMB->Reserved = 0;
5583 pSMB->Flags = 0;
5584 pSMB->Timeout = 0;
5585 pSMB->Reserved2 = 0;
5586 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5587 offset = param_offset + params;
5588
5589 data_offset = (FILE_UNIX_BASIC_INFO *)
5590 ((char *)(&pSMB->hdr.Protocol) + offset);
5591 count = sizeof(FILE_UNIX_BASIC_INFO);
5592
5593 pSMB->MaxParameterCount = cpu_to_le16(2);
5594 /* BB find max SMB PDU from sess */
5595 pSMB->MaxDataCount = cpu_to_le16(1000);
5596 pSMB->SetupCount = 1;
5597 pSMB->Reserved3 = 0;
5598 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5599 byte_count = 3 /* pad */ + params + count;
5600 pSMB->DataCount = cpu_to_le16(count);
5601 pSMB->ParameterCount = cpu_to_le16(params);
5602 pSMB->TotalDataCount = pSMB->DataCount;
5603 pSMB->TotalParameterCount = pSMB->ParameterCount;
5604 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5605 pSMB->DataOffset = cpu_to_le16(offset);
5606 pSMB->Fid = fid;
5607 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5608 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005609 inc_rfc1001_len(pSMB, byte_count);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005610 pSMB->ByteCount = cpu_to_le16(byte_count);
5611
5612 cifs_fill_unix_set_info(data_offset, args);
5613
5614 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5615 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005616 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005617
5618 /* Note: On -EAGAIN error only caller can retry on handle based calls
5619 since file handle passed in no longer valid */
5620
5621 return rc;
5622}
5623
5624int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005625CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5626 const struct cifs_unix_set_info_args *args,
5627 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005628{
5629 TRANSACTION2_SPI_REQ *pSMB = NULL;
5630 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5631 int name_len;
5632 int rc = 0;
5633 int bytes_returned = 0;
5634 FILE_UNIX_BASIC_INFO *data_offset;
5635 __u16 params, param_offset, offset, count, byte_count;
5636
Joe Perchesb6b38f72010-04-21 03:50:45 +00005637 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005638setPermsRetry:
5639 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5640 (void **) &pSMBr);
5641 if (rc)
5642 return rc;
5643
5644 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5645 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005646 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005647 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005648 name_len++; /* trailing null */
5649 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005650 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005651 name_len = strnlen(fileName, PATH_MAX);
5652 name_len++; /* trailing null */
5653 strncpy(pSMB->FileName, fileName, name_len);
5654 }
5655
5656 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005657 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005658 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005659 /* BB find max SMB PDU from sess structure BB */
5660 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 pSMB->MaxSetupCount = 0;
5662 pSMB->Reserved = 0;
5663 pSMB->Flags = 0;
5664 pSMB->Timeout = 0;
5665 pSMB->Reserved2 = 0;
5666 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005667 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668 offset = param_offset + params;
5669 data_offset =
5670 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5671 offset);
5672 memset(data_offset, 0, count);
5673 pSMB->DataOffset = cpu_to_le16(offset);
5674 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5675 pSMB->SetupCount = 1;
5676 pSMB->Reserved3 = 0;
5677 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5678 byte_count = 3 /* pad */ + params + count;
5679 pSMB->ParameterCount = cpu_to_le16(params);
5680 pSMB->DataCount = cpu_to_le16(count);
5681 pSMB->TotalParameterCount = pSMB->ParameterCount;
5682 pSMB->TotalDataCount = pSMB->DataCount;
5683 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5684 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005685 inc_rfc1001_len(pSMB, byte_count);
Steve French50c2f752007-07-13 00:33:32 +00005686
Jeff Layton654cf142009-07-09 20:02:49 -04005687 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005688
5689 pSMB->ByteCount = cpu_to_le16(byte_count);
5690 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5691 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005692 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005693 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694
Steve French0d817bc2008-05-22 02:02:03 +00005695 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005696 if (rc == -EAGAIN)
5697 goto setPermsRetry;
5698 return rc;
5699}
5700
Linus Torvalds1da177e2005-04-16 15:20:36 -07005701#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005702/*
5703 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5704 * function used by listxattr and getxattr type calls. When ea_name is set,
5705 * it looks for that attribute name and stuffs that value into the EAData
5706 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5707 * buffer. In both cases, the return value is either the length of the
5708 * resulting data or a negative error code. If EAData is a NULL pointer then
5709 * the data isn't copied to it, but the length is returned.
5710 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005711ssize_t
5712CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005713 const unsigned char *searchName, const unsigned char *ea_name,
5714 char *EAData, size_t buf_size,
5715 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005716{
5717 /* BB assumes one setup word */
5718 TRANSACTION2_QPI_REQ *pSMB = NULL;
5719 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5720 int rc = 0;
5721 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005722 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005723 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005724 struct fea *temp_fea;
5725 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005726 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005727 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005728
Joe Perchesb6b38f72010-04-21 03:50:45 +00005729 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005730QAllEAsRetry:
5731 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5732 (void **) &pSMBr);
5733 if (rc)
5734 return rc;
5735
5736 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005737 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005738 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005739 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005740 list_len++; /* trailing null */
5741 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005742 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005743 list_len = strnlen(searchName, PATH_MAX);
5744 list_len++; /* trailing null */
5745 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005746 }
5747
Jeff Layton6e462b92010-02-10 16:18:26 -05005748 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005749 pSMB->TotalDataCount = 0;
5750 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005751 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005752 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005753 pSMB->MaxSetupCount = 0;
5754 pSMB->Reserved = 0;
5755 pSMB->Flags = 0;
5756 pSMB->Timeout = 0;
5757 pSMB->Reserved2 = 0;
5758 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005759 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005760 pSMB->DataCount = 0;
5761 pSMB->DataOffset = 0;
5762 pSMB->SetupCount = 1;
5763 pSMB->Reserved3 = 0;
5764 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5765 byte_count = params + 1 /* pad */ ;
5766 pSMB->TotalParameterCount = cpu_to_le16(params);
5767 pSMB->ParameterCount = pSMB->TotalParameterCount;
5768 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5769 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005770 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005771 pSMB->ByteCount = cpu_to_le16(byte_count);
5772
5773 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5774 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5775 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005776 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005777 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005779
5780
5781 /* BB also check enough total bytes returned */
5782 /* BB we need to improve the validity checking
5783 of these trans2 responses */
5784
5785 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Jeff Layton820a8032011-05-04 08:05:26 -04005786 if (rc || get_bcc(&pSMBr->hdr) < 4) {
Jeff Laytonf0d38682010-02-10 16:18:26 -05005787 rc = -EIO; /* bad smb */
5788 goto QAllEAsOut;
5789 }
5790
5791 /* check that length of list is not more than bcc */
5792 /* check that each entry does not go beyond length
5793 of list */
5794 /* check that each element of each entry does not
5795 go beyond end of list */
5796 /* validate_trans2_offsets() */
5797 /* BB check if start of smb + data_offset > &bcc+ bcc */
5798
5799 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5800 ea_response_data = (struct fealist *)
5801 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5802
Jeff Layton6e462b92010-02-10 16:18:26 -05005803 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005804 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005805 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005806 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005807 goto QAllEAsOut;
5808 }
5809
Jeff Layton0cd126b2010-02-10 16:18:26 -05005810 /* make sure list_len doesn't go past end of SMB */
Jeff Layton690c5222011-01-20 13:36:51 -05005811 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
Jeff Layton0cd126b2010-02-10 16:18:26 -05005812 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005813 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005814 rc = -EIO;
5815 goto QAllEAsOut;
5816 }
5817
Jeff Laytonf0d38682010-02-10 16:18:26 -05005818 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005819 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005820 temp_fea = ea_response_data->list;
5821 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005822 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005823 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005824 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005825
Jeff Layton6e462b92010-02-10 16:18:26 -05005826 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005827 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005828 /* make sure we can read name_len and value_len */
5829 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005830 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005831 rc = -EIO;
5832 goto QAllEAsOut;
5833 }
5834
5835 name_len = temp_fea->name_len;
5836 value_len = le16_to_cpu(temp_fea->value_len);
5837 list_len -= name_len + 1 + value_len;
5838 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005839 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005840 rc = -EIO;
5841 goto QAllEAsOut;
5842 }
5843
Jeff Layton31c05192010-02-10 16:18:26 -05005844 if (ea_name) {
5845 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5846 temp_ptr += name_len + 1;
5847 rc = value_len;
5848 if (buf_size == 0)
5849 goto QAllEAsOut;
5850 if ((size_t)value_len > buf_size) {
5851 rc = -ERANGE;
5852 goto QAllEAsOut;
5853 }
5854 memcpy(EAData, temp_ptr, value_len);
5855 goto QAllEAsOut;
5856 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005857 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005858 /* account for prefix user. and trailing null */
5859 rc += (5 + 1 + name_len);
5860 if (rc < (int) buf_size) {
5861 memcpy(EAData, "user.", 5);
5862 EAData += 5;
5863 memcpy(EAData, temp_ptr, name_len);
5864 EAData += name_len;
5865 /* null terminate name */
5866 *EAData = 0;
5867 ++EAData;
5868 } else if (buf_size == 0) {
5869 /* skip copy - calc size only */
5870 } else {
5871 /* stop before overrun buffer */
5872 rc = -ERANGE;
5873 break;
5874 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005875 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005876 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005877 temp_fea = (struct fea *)temp_ptr;
5878 }
5879
Jeff Layton31c05192010-02-10 16:18:26 -05005880 /* didn't find the named attribute */
5881 if (ea_name)
5882 rc = -ENODATA;
5883
Jeff Laytonf0d38682010-02-10 16:18:26 -05005884QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005885 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005886 if (rc == -EAGAIN)
5887 goto QAllEAsRetry;
5888
5889 return (ssize_t)rc;
5890}
5891
Linus Torvalds1da177e2005-04-16 15:20:36 -07005892int
5893CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005894 const char *ea_name, const void *ea_value,
5895 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5896 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897{
5898 struct smb_com_transaction2_spi_req *pSMB = NULL;
5899 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5900 struct fealist *parm_data;
5901 int name_len;
5902 int rc = 0;
5903 int bytes_returned = 0;
5904 __u16 params, param_offset, byte_count, offset, count;
5905
Joe Perchesb6b38f72010-04-21 03:50:45 +00005906 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005907SetEARetry:
5908 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5909 (void **) &pSMBr);
5910 if (rc)
5911 return rc;
5912
5913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5914 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005915 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005916 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005917 name_len++; /* trailing null */
5918 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005919 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005920 name_len = strnlen(fileName, PATH_MAX);
5921 name_len++; /* trailing null */
5922 strncpy(pSMB->FileName, fileName, name_len);
5923 }
5924
5925 params = 6 + name_len;
5926
5927 /* done calculating parms using name_len of file name,
5928 now use name_len to calculate length of ea name
5929 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005930 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005931 name_len = 0;
5932 else
Steve French50c2f752007-07-13 00:33:32 +00005933 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005934
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005935 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005936 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005937 /* BB find max SMB PDU from sess */
5938 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005939 pSMB->MaxSetupCount = 0;
5940 pSMB->Reserved = 0;
5941 pSMB->Flags = 0;
5942 pSMB->Timeout = 0;
5943 pSMB->Reserved2 = 0;
5944 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005945 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005946 offset = param_offset + params;
5947 pSMB->InformationLevel =
5948 cpu_to_le16(SMB_SET_FILE_EA);
5949
5950 parm_data =
5951 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5952 offset);
5953 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5954 pSMB->DataOffset = cpu_to_le16(offset);
5955 pSMB->SetupCount = 1;
5956 pSMB->Reserved3 = 0;
5957 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5958 byte_count = 3 /* pad */ + params + count;
5959 pSMB->DataCount = cpu_to_le16(count);
5960 parm_data->list_len = cpu_to_le32(count);
5961 parm_data->list[0].EA_flags = 0;
5962 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005963 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005964 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005965 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005966 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005967 parm_data->list[0].name[name_len] = 0;
5968 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5969 /* caller ensures that ea_value_len is less than 64K but
5970 we need to ensure that it fits within the smb */
5971
Steve French50c2f752007-07-13 00:33:32 +00005972 /*BB add length check to see if it would fit in
5973 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005974 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5975 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005976 memcpy(parm_data->list[0].name+name_len+1,
5977 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005978
5979 pSMB->TotalDataCount = pSMB->DataCount;
5980 pSMB->ParameterCount = cpu_to_le16(params);
5981 pSMB->TotalParameterCount = pSMB->ParameterCount;
5982 pSMB->Reserved4 = 0;
Steve Frenchbe8e3b02011-04-29 05:40:20 +00005983 inc_rfc1001_len(pSMB, byte_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005984 pSMB->ByteCount = cpu_to_le16(byte_count);
5985 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5986 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005987 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005988 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005989
5990 cifs_buf_release(pSMB);
5991
5992 if (rc == -EAGAIN)
5993 goto SetEARetry;
5994
5995 return rc;
5996}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005997#endif
Steve French0eff0e22011-02-24 05:39:23 +00005998
5999#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6000/*
6001 * Years ago the kernel added a "dnotify" function for Samba server,
6002 * to allow network clients (such as Windows) to display updated
6003 * lists of files in directory listings automatically when
6004 * files are added by one user when another user has the
6005 * same directory open on their desktop. The Linux cifs kernel
6006 * client hooked into the kernel side of this interface for
6007 * the same reason, but ironically when the VFS moved from
6008 * "dnotify" to "inotify" it became harder to plug in Linux
6009 * network file system clients (the most obvious use case
6010 * for notify interfaces is when multiple users can update
6011 * the contents of the same directory - exactly what network
6012 * file systems can do) although the server (Samba) could
6013 * still use it. For the short term we leave the worker
6014 * function ifdeffed out (below) until inotify is fixed
6015 * in the VFS to make it easier to plug in network file
6016 * system clients. If inotify turns out to be permanently
6017 * incompatible for network fs clients, we could instead simply
6018 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6019 */
6020int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
6021 const int notify_subdirs, const __u16 netfid,
6022 __u32 filter, struct file *pfile, int multishot,
6023 const struct nls_table *nls_codepage)
6024{
6025 int rc = 0;
6026 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6027 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6028 struct dir_notify_req *dnotify_req;
6029 int bytes_returned;
6030
6031 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6032 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6033 (void **) &pSMBr);
6034 if (rc)
6035 return rc;
6036
6037 pSMB->TotalParameterCount = 0 ;
6038 pSMB->TotalDataCount = 0;
6039 pSMB->MaxParameterCount = cpu_to_le32(2);
6040 /* BB find exact data count max from sess structure BB */
6041 pSMB->MaxDataCount = 0; /* same in little endian or be */
6042/* BB VERIFY verify which is correct for above BB */
6043 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
6044 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
6045
6046 pSMB->MaxSetupCount = 4;
6047 pSMB->Reserved = 0;
6048 pSMB->ParameterOffset = 0;
6049 pSMB->DataCount = 0;
6050 pSMB->DataOffset = 0;
6051 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6052 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6053 pSMB->ParameterCount = pSMB->TotalParameterCount;
6054 if (notify_subdirs)
6055 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6056 pSMB->Reserved2 = 0;
6057 pSMB->CompletionFilter = cpu_to_le32(filter);
6058 pSMB->Fid = netfid; /* file handle always le */
6059 pSMB->ByteCount = 0;
6060
6061 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6062 (struct smb_hdr *)pSMBr, &bytes_returned,
6063 CIFS_ASYNC_OP);
6064 if (rc) {
6065 cFYI(1, "Error in Notify = %d", rc);
6066 } else {
6067 /* Add file to outstanding requests */
6068 /* BB change to kmem cache alloc */
6069 dnotify_req = kmalloc(
6070 sizeof(struct dir_notify_req),
6071 GFP_KERNEL);
6072 if (dnotify_req) {
6073 dnotify_req->Pid = pSMB->hdr.Pid;
6074 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6075 dnotify_req->Mid = pSMB->hdr.Mid;
6076 dnotify_req->Tid = pSMB->hdr.Tid;
6077 dnotify_req->Uid = pSMB->hdr.Uid;
6078 dnotify_req->netfid = netfid;
6079 dnotify_req->pfile = pfile;
6080 dnotify_req->filter = filter;
6081 dnotify_req->multishot = multishot;
6082 spin_lock(&GlobalMid_Lock);
6083 list_add_tail(&dnotify_req->lhead,
6084 &GlobalDnotifyReqList);
6085 spin_unlock(&GlobalMid_Lock);
6086 } else
6087 rc = -ENOMEM;
6088 }
6089 cifs_buf_release(pSMB);
6090 return rc;
6091}
6092#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */