blob: 1372253a0606f6a2b82e79ccfa30b574a7eba6b8 [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>
35#include <asm/uaccess.h>
36#include "cifspdu.h"
37#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000038#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "cifsproto.h"
40#include "cifs_unicode.h"
41#include "cifs_debug.h"
42
43#ifdef CONFIG_CIFS_POSIX
44static struct {
45 int index;
46 char *name;
47} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000048#ifdef CONFIG_CIFS_WEAK_PW_HASH
49 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000050 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000051#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000052 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000053 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 {BAD_PROT, "\2"}
55};
56#else
57static struct {
58 int index;
59 char *name;
60} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000061#ifdef CONFIG_CIFS_WEAK_PW_HASH
62 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000063 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000064#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000065 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 {BAD_PROT, "\2"}
67};
68#endif
69
Steve French39798772006-05-31 22:40:51 +000070/* define the number of elements in the cifs dialect array */
71#ifdef CONFIG_CIFS_POSIX
72#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000073#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000074#else
75#define CIFS_NUM_PROT 2
76#endif /* CIFS_WEAK_PW_HASH */
77#else /* not posix */
78#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000079#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000080#else
81#define CIFS_NUM_PROT 1
82#endif /* CONFIG_CIFS_WEAK_PW_HASH */
83#endif /* CIFS_POSIX */
84
Linus Torvalds1da177e2005-04-16 15:20:36 -070085/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000097 open_file->invalidHandle = true;
Jeff Layton3bc303c2009-09-21 06:47:50 -040098 open_file->oplock_break_cancelled = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
Jeff Layton9162ab22009-09-03 12:07:17 -0400105/* reconnect the socket, tcon, and smb session if needed */
106static int
107cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
108{
109 int rc = 0;
110 struct cifsSesInfo *ses;
111 struct TCP_Server_Info *server;
112 struct nls_table *nls_codepage;
113
114 /*
115 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
116 * tcp and smb session status done differently for those three - in the
117 * calling routine
118 */
119 if (!tcon)
120 return 0;
121
122 ses = tcon->ses;
123 server = ses->server;
124
125 /*
126 * only tree disconnect, open, and write, (and ulogoff which does not
127 * have tcon) are allowed as we start force umount
128 */
129 if (tcon->tidStatus == CifsExiting) {
130 if (smb_command != SMB_COM_WRITE_ANDX &&
131 smb_command != SMB_COM_OPEN_ANDX &&
132 smb_command != SMB_COM_TREE_DISCONNECT) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000133 cFYI(1, "can not send cmd %d while umounting",
134 smb_command);
Jeff Layton9162ab22009-09-03 12:07:17 -0400135 return -ENODEV;
136 }
137 }
138
139 if (ses->status == CifsExiting)
140 return -EIO;
141
142 /*
143 * Give demultiplex thread up to 10 seconds to reconnect, should be
144 * greater than cifs socket timeout which is 7 seconds
145 */
146 while (server->tcpStatus == CifsNeedReconnect) {
147 wait_event_interruptible_timeout(server->response_q,
148 (server->tcpStatus == CifsGood), 10 * HZ);
149
150 /* is TCP session is reestablished now ?*/
151 if (server->tcpStatus != CifsNeedReconnect)
152 break;
153
154 /*
155 * on "soft" mounts we wait once. Hard mounts keep
156 * retrying until process is killed or server comes
157 * back on-line
158 */
159 if (!tcon->retry || ses->status == CifsExiting) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000160 cFYI(1, "gave up waiting on reconnect in smb_init");
Jeff Layton9162ab22009-09-03 12:07:17 -0400161 return -EHOSTDOWN;
162 }
163 }
164
165 if (!ses->need_reconnect && !tcon->need_reconnect)
166 return 0;
167
168 nls_codepage = load_nls_default();
169
170 /*
171 * need to prevent multiple threads trying to simultaneously
172 * reconnect the same SMB session
173 */
Steve Frenchd7b619c2010-02-25 05:36:46 +0000174 mutex_lock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400175 if (ses->need_reconnect)
176 rc = cifs_setup_session(0, ses, nls_codepage);
177
178 /* do we need to reconnect tcon? */
179 if (rc || !tcon->need_reconnect) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000180 mutex_unlock(&ses->session_mutex);
Jeff Layton9162ab22009-09-03 12:07:17 -0400181 goto out;
182 }
183
184 mark_open_files_invalid(tcon);
185 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
Steve Frenchd7b619c2010-02-25 05:36:46 +0000186 mutex_unlock(&ses->session_mutex);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000187 cFYI(1, "reconnect tcon rc = %d", rc);
Jeff Layton9162ab22009-09-03 12:07:17 -0400188
189 if (rc)
190 goto out;
191
192 /*
193 * FIXME: check if wsize needs updated due to negotiated smb buffer
194 * size shrinking
195 */
196 atomic_inc(&tconInfoReconnectCount);
197
198 /* tell server Unix caps we support */
199 if (ses->capabilities & CAP_UNIX)
200 reset_cifs_unix_caps(0, tcon, NULL, NULL);
201
202 /*
203 * Removed call to reopen open files here. It is safer (and faster) to
204 * reopen files one at a time as needed in read and write.
205 *
206 * FIXME: what about file locks? don't we need to reclaim them ASAP?
207 */
208
209out:
210 /*
211 * Check if handle based operation so we know whether we can continue
212 * or not without returning to caller to reset file handle
213 */
214 switch (smb_command) {
215 case SMB_COM_READ_ANDX:
216 case SMB_COM_WRITE_ANDX:
217 case SMB_COM_CLOSE:
218 case SMB_COM_FIND_CLOSE2:
219 case SMB_COM_LOCKING_ANDX:
220 rc = -EAGAIN;
221 }
222
223 unload_nls(nls_codepage);
224 return rc;
225}
226
Steve Frenchad7a2922008-02-07 23:25:02 +0000227/* Allocate and return pointer to an SMB request buffer, and set basic
228 SMB information in the SMB header. If the return code is zero, this
229 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230static int
231small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000232 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
234 int rc = 0;
235
Jeff Layton9162ab22009-09-03 12:07:17 -0400236 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000237 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 return rc;
239
240 *request_buf = cifs_small_buf_get();
241 if (*request_buf == NULL) {
242 /* BB should we add a retry in here if not a writepage? */
243 return -ENOMEM;
244 }
245
Steve French63135e02007-07-17 17:34:02 +0000246 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000247 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Steve French790fe572007-07-07 19:25:05 +0000249 if (tcon != NULL)
250 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000253}
254
Steve French12b3b8f2006-02-09 21:12:47 +0000255int
Steve French50c2f752007-07-13 00:33:32 +0000256small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000257 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000258{
259 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000260 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000261
Steve French5815449d2006-02-14 01:36:20 +0000262 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000263 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000264 return rc;
265
Steve French04fdabe2006-02-10 05:52:50 +0000266 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000267 buffer->Mid = GetNextMid(ses->server);
268 if (ses->capabilities & CAP_UNICODE)
269 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000270 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000271 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
272
273 /* uid, tid can stay at zero as set in header assemble */
274
Steve French50c2f752007-07-13 00:33:32 +0000275 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000276 this function is used after 1st of session setup requests */
277
278 return rc;
279}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281/* If the return code is zero, this function must fill in request_buf pointer */
282static int
283smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
284 void **request_buf /* returned */ ,
285 void **response_buf /* returned */ )
286{
287 int rc = 0;
288
Jeff Layton9162ab22009-09-03 12:07:17 -0400289 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000290 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 return rc;
292
293 *request_buf = cifs_buf_get();
294 if (*request_buf == NULL) {
295 /* BB should we add a retry in here if not a writepage? */
296 return -ENOMEM;
297 }
298 /* Although the original thought was we needed the response buf for */
299 /* potential retries of smb operations it turns out we can determine */
300 /* from the mid flags when the request buffer can be resent without */
301 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000302 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000303 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000306 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Steve French790fe572007-07-07 19:25:05 +0000308 if (tcon != NULL)
309 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 return rc;
312}
313
Steve French50c2f752007-07-13 00:33:32 +0000314static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 int rc = -EINVAL;
317 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000318 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 /* check for plausible wct, bcc and t2 data and parm sizes */
321 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000322 if (pSMB->hdr.WordCount >= 10) {
323 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
325 /* check that bcc is at least as big as parms + data */
326 /* check that bcc is less than negotiated smb buffer */
327 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000328 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000329 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000330 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000332 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700333 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000335 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000336 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
338 return 0;
339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 }
341 }
342 }
Steve French50c2f752007-07-13 00:33:32 +0000343 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 sizeof(struct smb_t2_rsp) + 16);
345 return rc;
346}
347int
348CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
349{
350 NEGOTIATE_REQ *pSMB;
351 NEGOTIATE_RSP *pSMBr;
352 int rc = 0;
353 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000354 int i;
Steve French50c2f752007-07-13 00:33:32 +0000355 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000357 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358
Steve French790fe572007-07-07 19:25:05 +0000359 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 server = ses->server;
361 else {
362 rc = -EIO;
363 return rc;
364 }
365 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
366 (void **) &pSMB, (void **) &pSMBr);
367 if (rc)
368 return rc;
Steve French750d1152006-06-27 06:28:30 +0000369
370 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000371 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000372 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000373 else /* if override flags set only sign/seal OR them with global auth */
Jeff Layton04912d62010-04-24 07:57:45 -0400374 secFlags = global_secflags | ses->overrideSecFlg;
Steve French750d1152006-06-27 06:28:30 +0000375
Joe Perchesb6b38f72010-04-21 03:50:45 +0000376 cFYI(1, "secFlags 0x%x", secFlags);
Steve Frenchf40c5622006-06-28 00:13:38 +0000377
Steve French1982c342005-08-17 12:38:22 -0700378 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000379 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000380
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000381 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000382 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000383 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000384 cFYI(1, "Kerberos only mechanism, enable extended security");
Steve Frencha0136892007-10-04 20:05:09 +0000385 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
386 }
Steve Frenchac683922009-05-06 04:16:04 +0000387#ifdef CONFIG_CIFS_EXPERIMENTAL
388 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
389 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
390 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000391 cFYI(1, "NTLMSSP only mechanism, enable extended security");
Steve Frenchac683922009-05-06 04:16:04 +0000392 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
393 }
394#endif
Steve French50c2f752007-07-13 00:33:32 +0000395
Steve French39798772006-05-31 22:40:51 +0000396 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000397 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000398 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
399 count += strlen(protocols[i].name) + 1;
400 /* null at end of source and target buffers anyway */
401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 pSMB->hdr.smb_buf_length += count;
403 pSMB->ByteCount = cpu_to_le16(count);
404
405 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
406 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000407 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000408 goto neg_err_exit;
409
Jeff Layton9bf67e52010-04-24 07:57:46 -0400410 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
411 cFYI(1, "Dialect: %d", server->dialect);
Steve French254e55e2006-06-04 05:53:15 +0000412 /* Check wct = 1 error case */
Jeff Layton9bf67e52010-04-24 07:57:46 -0400413 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000414 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000415 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000416 could not negotiate a common dialect */
417 rc = -EOPNOTSUPP;
418 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000419#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000420 } else if ((pSMBr->hdr.WordCount == 13)
Jeff Layton9bf67e52010-04-24 07:57:46 -0400421 && ((server->dialect == LANMAN_PROT)
422 || (server->dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000423 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000424 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000425
Steve French790fe572007-07-07 19:25:05 +0000426 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000427 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000428 server->secType = LANMAN;
429 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000430 cERROR(1, "mount failed weak security disabled"
431 " in /proc/fs/cifs/SecurityFlags");
Steve French39798772006-05-31 22:40:51 +0000432 rc = -EOPNOTSUPP;
433 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000434 }
Steve French254e55e2006-06-04 05:53:15 +0000435 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
436 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
437 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000438 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000439 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000440 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
441 /* even though we do not use raw we might as well set this
442 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000443 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000444 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000445 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
446 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000447 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000448 server->capabilities = CAP_MPX_MODE;
449 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000450 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000451 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000452 /* OS/2 often does not set timezone therefore
453 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000454 * Could deviate slightly from the right zone.
455 * Smallest defined timezone difference is 15 minutes
456 * (i.e. Nepal). Rounding up/down is done to match
457 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000458 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000459 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000460 struct timespec ts, utc;
461 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400462 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
463 rsp->SrvTime.Time, 0);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000464 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
Steve French50c2f752007-07-13 00:33:32 +0000465 (int)ts.tv_sec, (int)utc.tv_sec,
Joe Perchesb6b38f72010-04-21 03:50:45 +0000466 (int)(utc.tv_sec - ts.tv_sec));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000467 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000468 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000469 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000470 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000471 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000472 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000473 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000474 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000475 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000476 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000477 server->timeAdj = (int)tmp;
478 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000479 }
Joe Perchesb6b38f72010-04-21 03:50:45 +0000480 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
Steve French25ee4a92006-09-30 00:54:23 +0000481
Steve French39798772006-05-31 22:40:51 +0000482
Steve French254e55e2006-06-04 05:53:15 +0000483 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000484 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000485
Steve French50c2f752007-07-13 00:33:32 +0000486 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000487 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000488 memcpy(server->cryptKey, rsp->EncryptionKey,
489 CIFS_CRYPTO_KEY_SIZE);
490 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
491 rc = -EIO; /* need cryptkey unless plain text */
492 goto neg_err_exit;
493 }
Steve French39798772006-05-31 22:40:51 +0000494
Steve Frenchf19159d2010-04-21 04:12:10 +0000495 cFYI(1, "LANMAN negotiated");
Steve French254e55e2006-06-04 05:53:15 +0000496 /* we will not end up setting signing flags - as no signing
497 was in LANMAN and server did not return the flags on */
498 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000499#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000500 } else if (pSMBr->hdr.WordCount == 13) {
Steve Frenchf19159d2010-04-21 04:12:10 +0000501 cERROR(1, "mount failed, cifs module not built "
502 "with CIFS_WEAK_PW_HASH support");
Dan Carpenter8212cf72010-03-15 11:22:26 +0300503 rc = -EOPNOTSUPP;
Steve French7c7b25b2006-06-01 19:20:10 +0000504#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000505 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000506 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000507 /* unknown wct */
508 rc = -EOPNOTSUPP;
509 goto neg_err_exit;
510 }
511 /* else wct == 17 NTLM */
512 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000513 if ((server->secMode & SECMODE_USER) == 0)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000514 cFYI(1, "share mode security");
Steve French39798772006-05-31 22:40:51 +0000515
Steve French790fe572007-07-07 19:25:05 +0000516 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000517#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000518 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000519#endif /* CIFS_WEAK_PW_HASH */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000520 cERROR(1, "Server requests plain text password"
521 " but client support disabled");
Steve French9312f672006-06-04 22:21:07 +0000522
Steve French790fe572007-07-07 19:25:05 +0000523 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000524 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000525 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000526 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000527 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000528 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000529 else if (secFlags & CIFSSEC_MAY_KRB5)
530 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000531 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000532 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000533 else if (secFlags & CIFSSEC_MAY_LANMAN)
534 server->secType = LANMAN;
535/* #ifdef CONFIG_CIFS_EXPERIMENTAL
536 else if (secFlags & CIFSSEC_MAY_PLNTXT)
537 server->secType = ??
538#endif */
539 else {
540 rc = -EOPNOTSUPP;
Joe Perchesb6b38f72010-04-21 03:50:45 +0000541 cERROR(1, "Invalid security type");
Steve Frencha0136892007-10-04 20:05:09 +0000542 goto neg_err_exit;
543 }
544 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000545
Steve French254e55e2006-06-04 05:53:15 +0000546 /* one byte, so no need to convert this or EncryptionKeyLen from
547 little endian */
548 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
549 /* probably no need to store and check maxvcs */
550 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000552 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Joe Perchesb6b38f72010-04-21 03:50:45 +0000553 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
Steve French254e55e2006-06-04 05:53:15 +0000554 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
555 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000556 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
557 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000558 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
559 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
560 CIFS_CRYPTO_KEY_SIZE);
561 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
562 && (pSMBr->EncryptionKeyLength == 0)) {
563 /* decode security blob */
564 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
565 rc = -EIO; /* no crypt key only if plain text pwd */
566 goto neg_err_exit;
567 }
568
569 /* BB might be helpful to save off the domain of server here */
570
Steve French50c2f752007-07-13 00:33:32 +0000571 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000572 (server->capabilities & CAP_EXTENDED_SECURITY)) {
573 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000574 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000576 goto neg_err_exit;
577 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500578 read_lock(&cifs_tcp_ses_lock);
579 if (server->srv_count > 1) {
580 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000581 if (memcmp(server->server_GUID,
582 pSMBr->u.extended_response.
583 GUID, 16) != 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000584 cFYI(1, "server UID changed");
Steve French254e55e2006-06-04 05:53:15 +0000585 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000586 pSMBr->u.extended_response.GUID,
587 16);
588 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500589 } else {
590 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000591 memcpy(server->server_GUID,
592 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500593 }
Jeff Laytone187e442007-10-16 17:10:44 +0000594
595 if (count == 16) {
596 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000597 } else {
598 rc = decode_negTokenInit(pSMBr->u.extended_response.
599 SecurityBlob,
600 count - 16,
601 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000602 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000603 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000604 else
Steve French254e55e2006-06-04 05:53:15 +0000605 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 }
Steve French254e55e2006-06-04 05:53:15 +0000607 } else
608 server->capabilities &= ~CAP_EXTENDED_SECURITY;
609
Steve French6344a422006-06-12 04:18:35 +0000610#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000611signing_check:
Steve French6344a422006-06-12 04:18:35 +0000612#endif
Steve French762e5ab2007-06-28 18:41:42 +0000613 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
614 /* MUST_SIGN already includes the MAY_SIGN FLAG
615 so if this is zero it means that signing is disabled */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000616 cFYI(1, "Signing disabled");
Steve Frenchabb63d62007-10-18 02:58:40 +0000617 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000618 cERROR(1, "Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000619 "packet signing to be enabled in "
Joe Perchesb6b38f72010-04-21 03:50:45 +0000620 "/proc/fs/cifs/SecurityFlags.");
Steve Frenchabb63d62007-10-18 02:58:40 +0000621 rc = -EOPNOTSUPP;
622 }
Steve French50c2f752007-07-13 00:33:32 +0000623 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000624 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000625 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
626 /* signing required */
Joe Perchesb6b38f72010-04-21 03:50:45 +0000627 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
Steve French762e5ab2007-06-28 18:41:42 +0000628 if ((server->secMode &
629 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +0000630 cERROR(1, "signing required but server lacks support");
Jeff38c10a12007-07-06 21:10:07 +0000631 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000632 } else
633 server->secMode |= SECMODE_SIGN_REQUIRED;
634 } else {
635 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000636 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000637 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000638 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 }
Steve French50c2f752007-07-13 00:33:32 +0000640
641neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700642 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000643
Joe Perchesb6b38f72010-04-21 03:50:45 +0000644 cFYI(1, "negprot rc %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return rc;
646}
647
648int
649CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
650{
651 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
Joe Perchesb6b38f72010-04-21 03:50:45 +0000654 cFYI(1, "In tree disconnect");
Jeff Laytonf1987b42008-11-15 11:12:47 -0500655
656 /* BB: do we need to check this? These should never be NULL. */
657 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
658 return -EIO;
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500661 * No need to return error on this operation if tid invalidated and
662 * closed on server already e.g. due to tcp session crashing. Also,
663 * the tcon is no longer on the list, so no need to take lock before
664 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 */
Steve French268875b2009-06-25 00:29:21 +0000666 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000667 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Steve French50c2f752007-07-13 00:33:32 +0000669 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700670 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500671 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 return rc;
Steve French133672e2007-11-13 22:41:37 +0000673
674 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000676 cFYI(1, "Tree disconnect failed %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Steve French50c2f752007-07-13 00:33:32 +0000678 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500679 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if (rc == -EAGAIN)
681 rc = 0;
682
683 return rc;
684}
685
686int
687CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
688{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 LOGOFF_ANDX_REQ *pSMB;
690 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
Joe Perchesb6b38f72010-04-21 03:50:45 +0000692 cFYI(1, "In SMBLogoff for session disconnect");
Jeff Layton14fbf502008-11-14 13:53:46 -0500693
694 /*
695 * BB: do we need to check validity of ses and server? They should
696 * always be valid since we have an active reference. If not, that
697 * should probably be a BUG()
698 */
699 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return -EIO;
701
Steve Frenchd7b619c2010-02-25 05:36:46 +0000702 mutex_lock(&ses->session_mutex);
Steve French3b795212008-11-13 19:45:32 +0000703 if (ses->need_reconnect)
704 goto session_already_dead; /* no need to send SMBlogoff if uid
705 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
707 if (rc) {
Steve Frenchd7b619c2010-02-25 05:36:46 +0000708 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 return rc;
710 }
711
Steve French3b795212008-11-13 19:45:32 +0000712 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700713
Steve French3b795212008-11-13 19:45:32 +0000714 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
716 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
718 pSMB->hdr.Uid = ses->Suid;
719
720 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000721 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000722session_already_dead:
Steve Frenchd7b619c2010-02-25 05:36:46 +0000723 mutex_unlock(&ses->session_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000726 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 error */
728 if (rc == -EAGAIN)
729 rc = 0;
730 return rc;
731}
732
733int
Steve French2d785a52007-07-15 01:48:57 +0000734CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
735 __u16 type, const struct nls_table *nls_codepage, int remap)
736{
737 TRANSACTION2_SPI_REQ *pSMB = NULL;
738 TRANSACTION2_SPI_RSP *pSMBr = NULL;
739 struct unlink_psx_rq *pRqD;
740 int name_len;
741 int rc = 0;
742 int bytes_returned = 0;
743 __u16 params, param_offset, offset, byte_count;
744
Joe Perchesb6b38f72010-04-21 03:50:45 +0000745 cFYI(1, "In POSIX delete");
Steve French2d785a52007-07-15 01:48:57 +0000746PsxDelete:
747 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
748 (void **) &pSMBr);
749 if (rc)
750 return rc;
751
752 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
753 name_len =
754 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
755 PATH_MAX, nls_codepage, remap);
756 name_len++; /* trailing null */
757 name_len *= 2;
758 } else { /* BB add path length overrun check */
759 name_len = strnlen(fileName, PATH_MAX);
760 name_len++; /* trailing null */
761 strncpy(pSMB->FileName, fileName, name_len);
762 }
763
764 params = 6 + name_len;
765 pSMB->MaxParameterCount = cpu_to_le16(2);
766 pSMB->MaxDataCount = 0; /* BB double check this with jra */
767 pSMB->MaxSetupCount = 0;
768 pSMB->Reserved = 0;
769 pSMB->Flags = 0;
770 pSMB->Timeout = 0;
771 pSMB->Reserved2 = 0;
772 param_offset = offsetof(struct smb_com_transaction2_spi_req,
773 InformationLevel) - 4;
774 offset = param_offset + params;
775
776 /* Setup pointer to Request Data (inode type) */
777 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
778 pRqD->type = cpu_to_le16(type);
779 pSMB->ParameterOffset = cpu_to_le16(param_offset);
780 pSMB->DataOffset = cpu_to_le16(offset);
781 pSMB->SetupCount = 1;
782 pSMB->Reserved3 = 0;
783 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
784 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
785
786 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
787 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
788 pSMB->ParameterCount = cpu_to_le16(params);
789 pSMB->TotalParameterCount = pSMB->ParameterCount;
790 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
791 pSMB->Reserved4 = 0;
792 pSMB->hdr.smb_buf_length += byte_count;
793 pSMB->ByteCount = cpu_to_le16(byte_count);
794 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
795 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000796 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000797 cFYI(1, "Posix delete returned %d", rc);
Steve French2d785a52007-07-15 01:48:57 +0000798 cifs_buf_release(pSMB);
799
800 cifs_stats_inc(&tcon->num_deletes);
801
802 if (rc == -EAGAIN)
803 goto PsxDelete;
804
805 return rc;
806}
807
808int
Steve French737b7582005-04-28 22:41:06 -0700809CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
810 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
812 DELETE_FILE_REQ *pSMB = NULL;
813 DELETE_FILE_RSP *pSMBr = NULL;
814 int rc = 0;
815 int bytes_returned;
816 int name_len;
817
818DelFileRetry:
819 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
820 (void **) &pSMBr);
821 if (rc)
822 return rc;
823
824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
825 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000826 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700827 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 name_len++; /* trailing null */
829 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700830 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 name_len = strnlen(fileName, PATH_MAX);
832 name_len++; /* trailing null */
833 strncpy(pSMB->fileName, fileName, name_len);
834 }
835 pSMB->SearchAttributes =
836 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
837 pSMB->BufferFormat = 0x04;
838 pSMB->hdr.smb_buf_length += name_len + 1;
839 pSMB->ByteCount = cpu_to_le16(name_len + 1);
840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700842 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000843 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000844 cFYI(1, "Error in RMFile = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 cifs_buf_release(pSMB);
847 if (rc == -EAGAIN)
848 goto DelFileRetry;
849
850 return rc;
851}
852
853int
Steve French50c2f752007-07-13 00:33:32 +0000854CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700855 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856{
857 DELETE_DIRECTORY_REQ *pSMB = NULL;
858 DELETE_DIRECTORY_RSP *pSMBr = NULL;
859 int rc = 0;
860 int bytes_returned;
861 int name_len;
862
Joe Perchesb6b38f72010-04-21 03:50:45 +0000863 cFYI(1, "In CIFSSMBRmDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864RmDirRetry:
865 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
866 (void **) &pSMBr);
867 if (rc)
868 return rc;
869
870 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700871 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
872 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 name_len++; /* trailing null */
874 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700875 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 name_len = strnlen(dirName, PATH_MAX);
877 name_len++; /* trailing null */
878 strncpy(pSMB->DirName, dirName, name_len);
879 }
880
881 pSMB->BufferFormat = 0x04;
882 pSMB->hdr.smb_buf_length += name_len + 1;
883 pSMB->ByteCount = cpu_to_le16(name_len + 1);
884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700886 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000887 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000888 cFYI(1, "Error in RMDir = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
890 cifs_buf_release(pSMB);
891 if (rc == -EAGAIN)
892 goto RmDirRetry;
893 return rc;
894}
895
896int
897CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700898 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 int rc = 0;
901 CREATE_DIRECTORY_REQ *pSMB = NULL;
902 CREATE_DIRECTORY_RSP *pSMBr = NULL;
903 int bytes_returned;
904 int name_len;
905
Joe Perchesb6b38f72010-04-21 03:50:45 +0000906 cFYI(1, "In CIFSSMBMkDir");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907MkDirRetry:
908 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
909 (void **) &pSMBr);
910 if (rc)
911 return rc;
912
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000914 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700915 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 name_len++; /* trailing null */
917 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700918 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 name_len = strnlen(name, PATH_MAX);
920 name_len++; /* trailing null */
921 strncpy(pSMB->DirName, name, name_len);
922 }
923
924 pSMB->BufferFormat = 0x04;
925 pSMB->hdr.smb_buf_length += name_len + 1;
926 pSMB->ByteCount = cpu_to_le16(name_len + 1);
927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700929 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000930 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +0000931 cFYI(1, "Error in Mkdir = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -0700932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 cifs_buf_release(pSMB);
934 if (rc == -EAGAIN)
935 goto MkDirRetry;
936 return rc;
937}
938
Steve French2dd29d32007-04-23 22:07:35 +0000939int
940CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000941 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000942 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000943 const struct nls_table *nls_codepage, int remap)
944{
945 TRANSACTION2_SPI_REQ *pSMB = NULL;
946 TRANSACTION2_SPI_RSP *pSMBr = NULL;
947 int name_len;
948 int rc = 0;
949 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +0000950 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +0000951 OPEN_PSX_REQ *pdata;
952 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +0000953
Joe Perchesb6b38f72010-04-21 03:50:45 +0000954 cFYI(1, "In POSIX Create");
Steve French2dd29d32007-04-23 22:07:35 +0000955PsxCreat:
956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
957 (void **) &pSMBr);
958 if (rc)
959 return rc;
960
961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
962 name_len =
963 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
964 PATH_MAX, nls_codepage, remap);
965 name_len++; /* trailing null */
966 name_len *= 2;
967 } else { /* BB improve the check for buffer overruns BB */
968 name_len = strnlen(name, PATH_MAX);
969 name_len++; /* trailing null */
970 strncpy(pSMB->FileName, name, name_len);
971 }
972
973 params = 6 + name_len;
974 count = sizeof(OPEN_PSX_REQ);
975 pSMB->MaxParameterCount = cpu_to_le16(2);
976 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
977 pSMB->MaxSetupCount = 0;
978 pSMB->Reserved = 0;
979 pSMB->Flags = 0;
980 pSMB->Timeout = 0;
981 pSMB->Reserved2 = 0;
982 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000983 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000984 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +0000985 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000986 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +0000987 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000988 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000989 pdata->OpenFlags = cpu_to_le32(*pOplock);
990 pSMB->ParameterOffset = cpu_to_le16(param_offset);
991 pSMB->DataOffset = cpu_to_le16(offset);
992 pSMB->SetupCount = 1;
993 pSMB->Reserved3 = 0;
994 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
995 byte_count = 3 /* pad */ + params + count;
996
997 pSMB->DataCount = cpu_to_le16(count);
998 pSMB->ParameterCount = cpu_to_le16(params);
999 pSMB->TotalDataCount = pSMB->DataCount;
1000 pSMB->TotalParameterCount = pSMB->ParameterCount;
1001 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1002 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001003 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001004 pSMB->ByteCount = cpu_to_le16(byte_count);
1005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1007 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001008 cFYI(1, "Posix create returned %d", rc);
Steve French2dd29d32007-04-23 22:07:35 +00001009 goto psx_create_err;
1010 }
1011
Joe Perchesb6b38f72010-04-21 03:50:45 +00001012 cFYI(1, "copying inode info");
Steve French2dd29d32007-04-23 22:07:35 +00001013 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1014
1015 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1016 rc = -EIO; /* bad smb */
1017 goto psx_create_err;
1018 }
1019
1020 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001021 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001022 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001023
Steve French2dd29d32007-04-23 22:07:35 +00001024 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001025 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001026 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1027 /* Let caller know file was created so we can set the mode. */
1028 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001029 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001030 *pOplock |= CIFS_CREATE_ACTION;
1031 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001032 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1033 pRetData->Type = cpu_to_le32(-1); /* unknown */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001034 cFYI(DBG2, "unknown type");
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001035 } else {
Steve French790fe572007-07-07 19:25:05 +00001036 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001037 + sizeof(FILE_UNIX_BASIC_INFO)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001038 cERROR(1, "Open response data too small");
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001039 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001040 goto psx_create_err;
1041 }
Steve French50c2f752007-07-13 00:33:32 +00001042 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001043 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001044 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001045 }
Steve French2dd29d32007-04-23 22:07:35 +00001046
1047psx_create_err:
1048 cifs_buf_release(pSMB);
1049
Steve French65bc98b2009-07-10 15:27:25 +00001050 if (posix_flags & SMB_O_DIRECTORY)
1051 cifs_stats_inc(&tcon->num_posixmkdirs);
1052 else
1053 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001054
1055 if (rc == -EAGAIN)
1056 goto PsxCreat;
1057
Steve French50c2f752007-07-13 00:33:32 +00001058 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001059}
1060
Steve Frencha9d02ad2005-08-24 23:06:05 -07001061static __u16 convert_disposition(int disposition)
1062{
1063 __u16 ofun = 0;
1064
1065 switch (disposition) {
1066 case FILE_SUPERSEDE:
1067 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1068 break;
1069 case FILE_OPEN:
1070 ofun = SMBOPEN_OAPPEND;
1071 break;
1072 case FILE_CREATE:
1073 ofun = SMBOPEN_OCREATE;
1074 break;
1075 case FILE_OPEN_IF:
1076 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1077 break;
1078 case FILE_OVERWRITE:
1079 ofun = SMBOPEN_OTRUNC;
1080 break;
1081 case FILE_OVERWRITE_IF:
1082 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1083 break;
1084 default:
Joe Perchesb6b38f72010-04-21 03:50:45 +00001085 cFYI(1, "unknown disposition %d", disposition);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001086 ofun = SMBOPEN_OAPPEND; /* regular open */
1087 }
1088 return ofun;
1089}
1090
Jeff Layton35fc37d2008-05-14 10:22:03 -07001091static int
1092access_flags_to_smbopen_mode(const int access_flags)
1093{
1094 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1095
1096 if (masked_flags == GENERIC_READ)
1097 return SMBOPEN_READ;
1098 else if (masked_flags == GENERIC_WRITE)
1099 return SMBOPEN_WRITE;
1100
1101 /* just go for read/write */
1102 return SMBOPEN_READWRITE;
1103}
1104
Steve Frencha9d02ad2005-08-24 23:06:05 -07001105int
1106SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1107 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001108 const int access_flags, const int create_options, __u16 *netfid,
1109 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001110 const struct nls_table *nls_codepage, int remap)
1111{
1112 int rc = -EACCES;
1113 OPENX_REQ *pSMB = NULL;
1114 OPENX_RSP *pSMBr = NULL;
1115 int bytes_returned;
1116 int name_len;
1117 __u16 count;
1118
1119OldOpenRetry:
1120 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1121 (void **) &pSMBr);
1122 if (rc)
1123 return rc;
1124
1125 pSMB->AndXCommand = 0xFF; /* none */
1126
1127 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1128 count = 1; /* account for one byte pad to word boundary */
1129 name_len =
1130 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1131 fileName, PATH_MAX, nls_codepage, remap);
1132 name_len++; /* trailing null */
1133 name_len *= 2;
1134 } else { /* BB improve check for buffer overruns BB */
1135 count = 0; /* no pad */
1136 name_len = strnlen(fileName, PATH_MAX);
1137 name_len++; /* trailing null */
1138 strncpy(pSMB->fileName, fileName, name_len);
1139 }
1140 if (*pOplock & REQ_OPLOCK)
1141 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001142 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001143 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001144
Steve Frencha9d02ad2005-08-24 23:06:05 -07001145 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001146 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001147 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1148 /* set file as system file if special file such
1149 as fifo and server expecting SFU style and
1150 no Unix extensions */
1151
Steve French790fe572007-07-07 19:25:05 +00001152 if (create_options & CREATE_OPTION_SPECIAL)
1153 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001154 else /* BB FIXME BB */
1155 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156
Jeff Layton67750fb2008-05-09 22:28:02 +00001157 if (create_options & CREATE_OPTION_READONLY)
1158 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001159
1160 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001161/* pSMB->CreateOptions = cpu_to_le32(create_options &
1162 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001164
1165 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001166 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167 count += name_len;
1168 pSMB->hdr.smb_buf_length += count;
1169
1170 pSMB->ByteCount = cpu_to_le16(count);
1171 /* long_op set to 1 to allow for oplock break timeouts */
1172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001173 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 cifs_stats_inc(&tcon->num_opens);
1175 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001176 cFYI(1, "Error in Open = %d", rc);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177 } else {
1178 /* BB verify if wct == 15 */
1179
Steve French582d21e2008-05-13 04:54:12 +00001180/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181
1182 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1183 /* Let caller know file was created so we can set the mode. */
1184 /* Do we care about the CreateAction in any other cases? */
1185 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001186/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 *pOplock |= CIFS_CREATE_ACTION; */
1188 /* BB FIXME END */
1189
Steve French790fe572007-07-07 19:25:05 +00001190 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001191 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1192 pfile_info->LastAccessTime = 0; /* BB fixme */
1193 pfile_info->LastWriteTime = 0; /* BB fixme */
1194 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001195 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001196 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001198 pfile_info->AllocationSize =
1199 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1200 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001201 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001202 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001203 }
1204 }
1205
1206 cifs_buf_release(pSMB);
1207 if (rc == -EAGAIN)
1208 goto OldOpenRetry;
1209 return rc;
1210}
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212int
1213CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1214 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001215 const int access_flags, const int create_options, __u16 *netfid,
1216 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001217 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218{
1219 int rc = -EACCES;
1220 OPEN_REQ *pSMB = NULL;
1221 OPEN_RSP *pSMBr = NULL;
1222 int bytes_returned;
1223 int name_len;
1224 __u16 count;
1225
1226openRetry:
1227 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1228 (void **) &pSMBr);
1229 if (rc)
1230 return rc;
1231
1232 pSMB->AndXCommand = 0xFF; /* none */
1233
1234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1235 count = 1; /* account for one byte pad to word boundary */
1236 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001237 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001238 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 name_len++; /* trailing null */
1240 name_len *= 2;
1241 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001242 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 count = 0; /* no pad */
1244 name_len = strnlen(fileName, PATH_MAX);
1245 name_len++; /* trailing null */
1246 pSMB->NameLength = cpu_to_le16(name_len);
1247 strncpy(pSMB->fileName, fileName, name_len);
1248 }
1249 if (*pOplock & REQ_OPLOCK)
1250 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001251 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1254 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001255 /* set file as system file if special file such
1256 as fifo and server expecting SFU style and
1257 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001258 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001259 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1260 else
1261 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 /* XP does not handle ATTR_POSIX_SEMANTICS */
1264 /* but it helps speed up case sensitive checks for other
1265 servers such as Samba */
1266 if (tcon->ses->capabilities & CAP_UNIX)
1267 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1268
Jeff Layton67750fb2008-05-09 22:28:02 +00001269 if (create_options & CREATE_OPTION_READONLY)
1270 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1273 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001274 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001275 /* BB Expirement with various impersonation levels and verify */
1276 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 pSMB->SecurityFlags =
1278 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1279
1280 count += name_len;
1281 pSMB->hdr.smb_buf_length += count;
1282
1283 pSMB->ByteCount = cpu_to_le16(count);
1284 /* long_op set to 1 to allow for oplock break timeouts */
1285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001286 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001287 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001289 cFYI(1, "Error in Open = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 } else {
Steve French09d1db52005-04-28 22:41:08 -07001291 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1293 /* Let caller know file was created so we can set the mode. */
1294 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001295 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001296 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001297 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001298 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1299 36 /* CreationTime to Attributes */);
1300 /* the file_info buf is endian converted by caller */
1301 pfile_info->AllocationSize = pSMBr->AllocationSize;
1302 pfile_info->EndOfFile = pSMBr->EndOfFile;
1303 pfile_info->NumberOfLinks = cpu_to_le32(1);
1304 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 cifs_buf_release(pSMB);
1309 if (rc == -EAGAIN)
1310 goto openRetry;
1311 return rc;
1312}
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314int
Steve French50c2f752007-07-13 00:33:32 +00001315CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1316 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1317 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
1319 int rc = -EACCES;
1320 READ_REQ *pSMB = NULL;
1321 READ_RSP *pSMBr = NULL;
1322 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001323 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001324 int resp_buf_type = 0;
1325 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Joe Perchesb6b38f72010-04-21 03:50:45 +00001327 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
Steve French790fe572007-07-07 19:25:05 +00001328 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001329 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001330 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001331 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001332 if ((lseek >> 32) > 0) {
1333 /* can not handle this big offset for old */
1334 return -EIO;
1335 }
1336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001339 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (rc)
1341 return rc;
1342
1343 /* tcon and ses pointer are checked in smb_init */
1344 if (tcon->ses->server == NULL)
1345 return -ECONNABORTED;
1346
Steve Frenchec637e32005-12-12 20:53:18 -08001347 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 pSMB->Fid = netfid;
1349 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001350 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001351 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001352
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->Remaining = 0;
1354 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1355 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001356 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001357 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1358 else {
1359 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001360 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001361 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001362 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001363 }
Steve Frenchec637e32005-12-12 20:53:18 -08001364
1365 iov[0].iov_base = (char *)pSMB;
1366 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001367 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001368 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001369 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001370 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001372 cERROR(1, "Send error in read = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 } else {
1374 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1375 data_length = data_length << 16;
1376 data_length += le16_to_cpu(pSMBr->DataLength);
1377 *nbytes = data_length;
1378
1379 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001380 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 || (data_length > count)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001382 cFYI(1, "bad length %d for count %d",
1383 data_length, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 rc = -EIO;
1385 *nbytes = 0;
1386 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001387 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001388 le16_to_cpu(pSMBr->DataOffset);
1389/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001390 cERROR(1, "Faulting on read rc = %d",rc);
Steve French50c2f752007-07-13 00:33:32 +00001391 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001392 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001393 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001394 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 }
1396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Steve French4b8f9302006-02-26 16:41:18 +00001398/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001399 if (*buf) {
1400 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001401 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001402 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001403 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001404 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001405 /* return buffer to caller to free */
1406 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001407 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001408 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001409 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001410 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001411 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001412
1413 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 since file handle passed in no longer valid */
1415 return rc;
1416}
1417
Steve Frenchec637e32005-12-12 20:53:18 -08001418
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419int
1420CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1421 const int netfid, const unsigned int count,
1422 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001423 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424{
1425 int rc = -EACCES;
1426 WRITE_REQ *pSMB = NULL;
1427 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001428 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 __u32 bytes_sent;
1430 __u16 byte_count;
1431
Steve Frencha24e2d72010-04-03 17:20:21 +00001432 *nbytes = 0;
1433
Joe Perchesb6b38f72010-04-21 03:50:45 +00001434 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
Steve French790fe572007-07-07 19:25:05 +00001435 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001436 return -ECONNABORTED;
1437
Steve French790fe572007-07-07 19:25:05 +00001438 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001439 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001440 else {
Steve French1c955182005-08-30 20:58:07 -07001441 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001442 if ((offset >> 32) > 0) {
1443 /* can not handle big offset for old srv */
1444 return -EIO;
1445 }
1446 }
Steve French1c955182005-08-30 20:58:07 -07001447
1448 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 (void **) &pSMBr);
1450 if (rc)
1451 return rc;
1452 /* tcon and ses pointer are checked in smb_init */
1453 if (tcon->ses->server == NULL)
1454 return -ECONNABORTED;
1455
1456 pSMB->AndXCommand = 0xFF; /* none */
1457 pSMB->Fid = netfid;
1458 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001459 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001460 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001461
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 pSMB->Reserved = 0xFFFFFFFF;
1463 pSMB->WriteMode = 0;
1464 pSMB->Remaining = 0;
1465
Steve French50c2f752007-07-13 00:33:32 +00001466 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 can send more if LARGE_WRITE_X capability returned by the server and if
1468 our buffer is big enough or if we convert to iovecs on socket writes
1469 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001470 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1472 } else {
1473 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1474 & ~0xFF;
1475 }
1476
1477 if (bytes_sent > count)
1478 bytes_sent = count;
1479 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001480 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001481 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001482 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001483 else if (ubuf) {
1484 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 cifs_buf_release(pSMB);
1486 return -EFAULT;
1487 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001488 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 /* No buffer */
1490 cifs_buf_release(pSMB);
1491 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001492 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001493 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001494 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001495 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001496 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001497
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1499 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001500 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001501
Steve French790fe572007-07-07 19:25:05 +00001502 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001503 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001504 else { /* old style write has byte count 4 bytes earlier
1505 so 4 bytes pad */
1506 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001507 (struct smb_com_writex_req *)pSMB;
1508 pSMBW->ByteCount = cpu_to_le16(byte_count);
1509 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510
1511 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1512 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001513 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00001515 cFYI(1, "Send error in write = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 } else {
1517 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1518 *nbytes = (*nbytes) << 16;
1519 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301520
1521 /*
1522 * Mask off high 16 bits when bytes written as returned by the
1523 * server is greater than bytes requested by the client. Some
1524 * OS/2 servers are known to set incorrect CountHigh values.
1525 */
1526 if (*nbytes > count)
1527 *nbytes &= 0xFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 }
1529
1530 cifs_buf_release(pSMB);
1531
Steve French50c2f752007-07-13 00:33:32 +00001532 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 since file handle passed in no longer valid */
1534
1535 return rc;
1536}
1537
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001538int
1539CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001541 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1542 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543{
1544 int rc = -EACCES;
1545 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001546 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001547 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001548 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001550 *nbytes = 0;
1551
Joe Perchesb6b38f72010-04-21 03:50:45 +00001552 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
Steve Frenchff7feac2005-11-15 16:45:16 -08001553
Steve French4c3130e2008-12-09 00:28:16 +00001554 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001555 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001556 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001557 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001558 if ((offset >> 32) > 0) {
1559 /* can not handle big offset for old srv */
1560 return -EIO;
1561 }
1562 }
Steve French8cc64c62005-10-03 13:49:43 -07001563 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 if (rc)
1565 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 /* tcon and ses pointer are checked in smb_init */
1567 if (tcon->ses->server == NULL)
1568 return -ECONNABORTED;
1569
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001570 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 pSMB->Fid = netfid;
1572 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001573 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001574 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 pSMB->Reserved = 0xFFFFFFFF;
1576 pSMB->WriteMode = 0;
1577 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001580 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
Steve French3e844692005-10-03 13:37:24 -07001582 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1583 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001584 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001585 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001586 pSMB->hdr.smb_buf_length += count+1;
1587 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001588 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1589 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001590 pSMB->ByteCount = cpu_to_le16(count + 1);
1591 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001592 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001593 (struct smb_com_writex_req *)pSMB;
1594 pSMBW->ByteCount = cpu_to_le16(count + 5);
1595 }
Steve French3e844692005-10-03 13:37:24 -07001596 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001597 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001598 iov[0].iov_len = smb_hdr_len + 4;
1599 else /* wct == 12 pad bigger by four bytes */
1600 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001601
Steve French3e844692005-10-03 13:37:24 -07001602
Steve Frenchec637e32005-12-12 20:53:18 -08001603 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001604 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001605 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001607 cFYI(1, "Send error Write2 = %d", rc);
Steve French790fe572007-07-07 19:25:05 +00001608 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001609 /* presumably this can not happen, but best to be safe */
1610 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001611 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001612 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001613 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1614 *nbytes = (*nbytes) << 16;
1615 *nbytes += le16_to_cpu(pSMBr->Count);
Suresh Jayaraman6513a812010-03-31 12:00:03 +05301616
1617 /*
1618 * Mask off high 16 bits when bytes written as returned by the
1619 * server is greater than bytes requested by the client. OS/2
1620 * servers are known to set incorrect CountHigh values.
1621 */
1622 if (*nbytes > count)
1623 *nbytes &= 0xFFFF;
Steve French50c2f752007-07-13 00:33:32 +00001624 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625
Steve French4b8f9302006-02-26 16:41:18 +00001626/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001627 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001628 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001629 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001630 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
Steve French50c2f752007-07-13 00:33:32 +00001632 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 since file handle passed in no longer valid */
1634
1635 return rc;
1636}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001637
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639int
1640CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1641 const __u16 smb_file_id, const __u64 len,
1642 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001643 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644{
1645 int rc = 0;
1646 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001647/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 int bytes_returned;
1649 int timeout = 0;
1650 __u16 count;
1651
Joe Perchesb6b38f72010-04-21 03:50:45 +00001652 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
Steve French46810cb2005-04-28 22:41:09 -07001653 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1654
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 if (rc)
1656 return rc;
1657
Steve French790fe572007-07-07 19:25:05 +00001658 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001659 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001661 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001662 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1664 } else {
1665 pSMB->Timeout = 0;
1666 }
1667
1668 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1669 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1670 pSMB->LockType = lockType;
1671 pSMB->AndXCommand = 0xFF; /* none */
1672 pSMB->Fid = smb_file_id; /* netfid stays le */
1673
Steve French790fe572007-07-07 19:25:05 +00001674 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1676 /* BB where to store pid high? */
1677 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1678 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1679 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1680 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1681 count = sizeof(LOCKING_ANDX_RANGE);
1682 } else {
1683 /* oplock break */
1684 count = 0;
1685 }
1686 pSMB->hdr.smb_buf_length += count;
1687 pSMB->ByteCount = cpu_to_le16(count);
1688
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001689 if (waitFlag) {
1690 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001691 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001692 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001693 } else {
Steve French133672e2007-11-13 22:41:37 +00001694 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1695 timeout);
1696 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001697 }
Steve Frencha4544342005-08-24 13:59:35 -07001698 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001699 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001700 cFYI(1, "Send error in Lock = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Steve French50c2f752007-07-13 00:33:32 +00001702 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 since file handle passed in no longer valid */
1704 return rc;
1705}
1706
1707int
Steve French08547b02006-02-28 22:39:25 +00001708CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1709 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001710 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001711 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001712{
1713 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1714 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001715 struct cifs_posix_lock *parm_data;
1716 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001717 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001718 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001719 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001720 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001721 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001722
Joe Perchesb6b38f72010-04-21 03:50:45 +00001723 cFYI(1, "Posix Lock");
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001724
Steve French790fe572007-07-07 19:25:05 +00001725 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001726 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001727
Steve French08547b02006-02-28 22:39:25 +00001728 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1729
1730 if (rc)
1731 return rc;
1732
1733 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1734
Steve French50c2f752007-07-13 00:33:32 +00001735 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001736 pSMB->MaxSetupCount = 0;
1737 pSMB->Reserved = 0;
1738 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001739 pSMB->Reserved2 = 0;
1740 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1741 offset = param_offset + params;
1742
Steve French08547b02006-02-28 22:39:25 +00001743 count = sizeof(struct cifs_posix_lock);
1744 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001745 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001746 pSMB->SetupCount = 1;
1747 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001748 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001749 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1750 else
1751 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1752 byte_count = 3 /* pad */ + params + count;
1753 pSMB->DataCount = cpu_to_le16(count);
1754 pSMB->ParameterCount = cpu_to_le16(params);
1755 pSMB->TotalDataCount = pSMB->DataCount;
1756 pSMB->TotalParameterCount = pSMB->ParameterCount;
1757 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001758 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001759 (((char *) &pSMB->hdr.Protocol) + offset);
1760
1761 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001762 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001763 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001764 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001765 pSMB->Timeout = cpu_to_le32(-1);
1766 } else
1767 pSMB->Timeout = 0;
1768
Steve French08547b02006-02-28 22:39:25 +00001769 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001770 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001771 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001772
1773 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001774 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001775 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1776 pSMB->Reserved4 = 0;
1777 pSMB->hdr.smb_buf_length += byte_count;
1778 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001779 if (waitFlag) {
1780 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1781 (struct smb_hdr *) pSMBr, &bytes_returned);
1782 } else {
Steve French133672e2007-11-13 22:41:37 +00001783 iov[0].iov_base = (char *)pSMB;
1784 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1785 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1786 &resp_buf_type, timeout);
1787 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1788 not try to free it twice below on exit */
1789 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001790 }
1791
Steve French08547b02006-02-28 22:39:25 +00001792 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00001793 cFYI(1, "Send error in Posix Lock = %d", rc);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001794 } else if (get_flag) {
1795 /* lock structure can be returned on get */
1796 __u16 data_offset;
1797 __u16 data_count;
1798 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001799
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001800 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1801 rc = -EIO; /* bad smb */
1802 goto plk_err_exit;
1803 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001804 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1805 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001806 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001807 rc = -EIO;
1808 goto plk_err_exit;
1809 }
1810 parm_data = (struct cifs_posix_lock *)
1811 ((char *)&pSMBr->hdr.Protocol + data_offset);
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001812 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001813 pLockData->fl_type = F_UNLCK;
Pavel Shilovskyf05337c2010-04-05 09:59:14 +04001814 else {
1815 if (parm_data->lock_type ==
1816 __constant_cpu_to_le16(CIFS_RDLCK))
1817 pLockData->fl_type = F_RDLCK;
1818 else if (parm_data->lock_type ==
1819 __constant_cpu_to_le16(CIFS_WRLCK))
1820 pLockData->fl_type = F_WRLCK;
1821
1822 pLockData->fl_start = parm_data->start;
1823 pLockData->fl_end = parm_data->start +
1824 parm_data->length - 1;
1825 pLockData->fl_pid = parm_data->pid;
1826 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001827 }
Steve French50c2f752007-07-13 00:33:32 +00001828
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001829plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001830 if (pSMB)
1831 cifs_small_buf_release(pSMB);
1832
Steve French133672e2007-11-13 22:41:37 +00001833 if (resp_buf_type == CIFS_SMALL_BUFFER)
1834 cifs_small_buf_release(iov[0].iov_base);
1835 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1836 cifs_buf_release(iov[0].iov_base);
1837
Steve French08547b02006-02-28 22:39:25 +00001838 /* Note: On -EAGAIN error only caller can retry on handle based calls
1839 since file handle passed in no longer valid */
1840
1841 return rc;
1842}
1843
1844
1845int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1847{
1848 int rc = 0;
1849 CLOSE_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001850 cFYI(1, "In CIFSSMBClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851
1852/* do not retry on dead session on close */
1853 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001854 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 return 0;
1856 if (rc)
1857 return rc;
1858
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001860 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001862 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001863 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001865 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 /* EINTR is expected when user ctl-c to kill app */
Joe Perchesb6b38f72010-04-21 03:50:45 +00001867 cERROR(1, "Send error in Close = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 }
1869 }
1870
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001872 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 rc = 0;
1874
1875 return rc;
1876}
1877
1878int
Steve Frenchb298f222009-02-21 21:17:43 +00001879CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1880{
1881 int rc = 0;
1882 FLUSH_REQ *pSMB = NULL;
Joe Perchesb6b38f72010-04-21 03:50:45 +00001883 cFYI(1, "In CIFSSMBFlush");
Steve Frenchb298f222009-02-21 21:17:43 +00001884
1885 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1886 if (rc)
1887 return rc;
1888
1889 pSMB->FileID = (__u16) smb_file_id;
1890 pSMB->ByteCount = 0;
1891 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1892 cifs_stats_inc(&tcon->num_flushes);
1893 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001894 cERROR(1, "Send error in Flush = %d", rc);
Steve Frenchb298f222009-02-21 21:17:43 +00001895
1896 return rc;
1897}
1898
1899int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1901 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001902 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903{
1904 int rc = 0;
1905 RENAME_REQ *pSMB = NULL;
1906 RENAME_RSP *pSMBr = NULL;
1907 int bytes_returned;
1908 int name_len, name_len2;
1909 __u16 count;
1910
Joe Perchesb6b38f72010-04-21 03:50:45 +00001911 cFYI(1, "In CIFSSMBRename");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912renameRetry:
1913 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1914 (void **) &pSMBr);
1915 if (rc)
1916 return rc;
1917
1918 pSMB->BufferFormat = 0x04;
1919 pSMB->SearchAttributes =
1920 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1921 ATTR_DIRECTORY);
1922
1923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1924 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001925 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001926 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 name_len++; /* trailing null */
1928 name_len *= 2;
1929 pSMB->OldFileName[name_len] = 0x04; /* pad */
1930 /* protocol requires ASCII signature byte on Unicode string */
1931 pSMB->OldFileName[name_len + 1] = 0x00;
1932 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001933 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001934 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001935 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1936 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001937 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 name_len = strnlen(fromName, PATH_MAX);
1939 name_len++; /* trailing null */
1940 strncpy(pSMB->OldFileName, fromName, name_len);
1941 name_len2 = strnlen(toName, PATH_MAX);
1942 name_len2++; /* trailing null */
1943 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1944 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1945 name_len2++; /* trailing null */
1946 name_len2++; /* signature byte */
1947 }
1948
1949 count = 1 /* 1st signature byte */ + name_len + name_len2;
1950 pSMB->hdr.smb_buf_length += count;
1951 pSMB->ByteCount = cpu_to_le16(count);
1952
1953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001955 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001956 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00001957 cFYI(1, "Send error in rename = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 cifs_buf_release(pSMB);
1960
1961 if (rc == -EAGAIN)
1962 goto renameRetry;
1963
1964 return rc;
1965}
1966
Steve French50c2f752007-07-13 00:33:32 +00001967int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001968 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001969 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970{
1971 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1972 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001973 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974 char *data_offset;
1975 char dummy_string[30];
1976 int rc = 0;
1977 int bytes_returned = 0;
1978 int len_of_str;
1979 __u16 params, param_offset, offset, count, byte_count;
1980
Joe Perchesb6b38f72010-04-21 03:50:45 +00001981 cFYI(1, "Rename to File by handle");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1983 (void **) &pSMBr);
1984 if (rc)
1985 return rc;
1986
1987 params = 6;
1988 pSMB->MaxSetupCount = 0;
1989 pSMB->Reserved = 0;
1990 pSMB->Flags = 0;
1991 pSMB->Timeout = 0;
1992 pSMB->Reserved2 = 0;
1993 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1994 offset = param_offset + params;
1995
1996 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1997 rename_info = (struct set_file_rename *) data_offset;
1998 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001999 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 pSMB->SetupCount = 1;
2001 pSMB->Reserved3 = 0;
2002 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2003 byte_count = 3 /* pad */ + params;
2004 pSMB->ParameterCount = cpu_to_le16(params);
2005 pSMB->TotalParameterCount = pSMB->ParameterCount;
2006 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2007 pSMB->DataOffset = cpu_to_le16(offset);
2008 /* construct random name ".cifs_tmp<inodenum><mid>" */
2009 rename_info->overwrite = cpu_to_le32(1);
2010 rename_info->root_fid = 0;
2011 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002012 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002013 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2014 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002015 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002017 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002018 target_name, PATH_MAX, nls_codepage,
2019 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 }
2021 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04002022 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 byte_count += count;
2024 pSMB->DataCount = cpu_to_le16(count);
2025 pSMB->TotalDataCount = pSMB->DataCount;
2026 pSMB->Fid = netfid;
2027 pSMB->InformationLevel =
2028 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2029 pSMB->Reserved4 = 0;
2030 pSMB->hdr.smb_buf_length += byte_count;
2031 pSMB->ByteCount = cpu_to_le16(byte_count);
2032 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002033 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002034 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002035 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002036 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
Steve Frencha5a2b482005-08-20 21:42:53 -07002037
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 cifs_buf_release(pSMB);
2039
2040 /* Note: On -EAGAIN error only caller can retry on handle based calls
2041 since file handle passed in no longer valid */
2042
2043 return rc;
2044}
2045
2046int
Steve French50c2f752007-07-13 00:33:32 +00002047CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2048 const __u16 target_tid, const char *toName, const int flags,
2049 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050{
2051 int rc = 0;
2052 COPY_REQ *pSMB = NULL;
2053 COPY_RSP *pSMBr = NULL;
2054 int bytes_returned;
2055 int name_len, name_len2;
2056 __u16 count;
2057
Joe Perchesb6b38f72010-04-21 03:50:45 +00002058 cFYI(1, "In CIFSSMBCopy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059copyRetry:
2060 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2061 (void **) &pSMBr);
2062 if (rc)
2063 return rc;
2064
2065 pSMB->BufferFormat = 0x04;
2066 pSMB->Tid2 = target_tid;
2067
2068 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2069
2070 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002071 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002072 fromName, PATH_MAX, nls_codepage,
2073 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 name_len++; /* trailing null */
2075 name_len *= 2;
2076 pSMB->OldFileName[name_len] = 0x04; /* pad */
2077 /* protocol requires ASCII signature byte on Unicode string */
2078 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002079 name_len2 =
2080 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002081 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2083 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002084 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 name_len = strnlen(fromName, PATH_MAX);
2086 name_len++; /* trailing null */
2087 strncpy(pSMB->OldFileName, fromName, name_len);
2088 name_len2 = strnlen(toName, PATH_MAX);
2089 name_len2++; /* trailing null */
2090 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2091 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2092 name_len2++; /* trailing null */
2093 name_len2++; /* signature byte */
2094 }
2095
2096 count = 1 /* 1st signature byte */ + name_len + name_len2;
2097 pSMB->hdr.smb_buf_length += count;
2098 pSMB->ByteCount = cpu_to_le16(count);
2099
2100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2102 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002103 cFYI(1, "Send error in copy = %d with %d files copied",
2104 rc, le16_to_cpu(pSMBr->CopyCount));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 }
Steve French0d817bc2008-05-22 02:02:03 +00002106 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
2108 if (rc == -EAGAIN)
2109 goto copyRetry;
2110
2111 return rc;
2112}
2113
2114int
2115CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2116 const char *fromName, const char *toName,
2117 const struct nls_table *nls_codepage)
2118{
2119 TRANSACTION2_SPI_REQ *pSMB = NULL;
2120 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2121 char *data_offset;
2122 int name_len;
2123 int name_len_target;
2124 int rc = 0;
2125 int bytes_returned = 0;
2126 __u16 params, param_offset, offset, byte_count;
2127
Joe Perchesb6b38f72010-04-21 03:50:45 +00002128 cFYI(1, "In Symlink Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129createSymLinkRetry:
2130 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2131 (void **) &pSMBr);
2132 if (rc)
2133 return rc;
2134
2135 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2136 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002137 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 /* find define for this maxpathcomponent */
2139 , nls_codepage);
2140 name_len++; /* trailing null */
2141 name_len *= 2;
2142
Steve French50c2f752007-07-13 00:33:32 +00002143 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 name_len = strnlen(fromName, PATH_MAX);
2145 name_len++; /* trailing null */
2146 strncpy(pSMB->FileName, fromName, name_len);
2147 }
2148 params = 6 + name_len;
2149 pSMB->MaxSetupCount = 0;
2150 pSMB->Reserved = 0;
2151 pSMB->Flags = 0;
2152 pSMB->Timeout = 0;
2153 pSMB->Reserved2 = 0;
2154 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002155 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002156 offset = param_offset + params;
2157
2158 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2159 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2160 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002161 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 /* find define for this maxpathcomponent */
2163 , nls_codepage);
2164 name_len_target++; /* trailing null */
2165 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002166 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 name_len_target = strnlen(toName, PATH_MAX);
2168 name_len_target++; /* trailing null */
2169 strncpy(data_offset, toName, name_len_target);
2170 }
2171
2172 pSMB->MaxParameterCount = cpu_to_le16(2);
2173 /* BB find exact max on data count below from sess */
2174 pSMB->MaxDataCount = cpu_to_le16(1000);
2175 pSMB->SetupCount = 1;
2176 pSMB->Reserved3 = 0;
2177 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2178 byte_count = 3 /* pad */ + params + name_len_target;
2179 pSMB->DataCount = cpu_to_le16(name_len_target);
2180 pSMB->ParameterCount = cpu_to_le16(params);
2181 pSMB->TotalDataCount = pSMB->DataCount;
2182 pSMB->TotalParameterCount = pSMB->ParameterCount;
2183 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2184 pSMB->DataOffset = cpu_to_le16(offset);
2185 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2186 pSMB->Reserved4 = 0;
2187 pSMB->hdr.smb_buf_length += byte_count;
2188 pSMB->ByteCount = cpu_to_le16(byte_count);
2189 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2190 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002191 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002192 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002193 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
Steve French0d817bc2008-05-22 02:02:03 +00002195 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196
2197 if (rc == -EAGAIN)
2198 goto createSymLinkRetry;
2199
2200 return rc;
2201}
2202
2203int
2204CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2205 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002206 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207{
2208 TRANSACTION2_SPI_REQ *pSMB = NULL;
2209 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2210 char *data_offset;
2211 int name_len;
2212 int name_len_target;
2213 int rc = 0;
2214 int bytes_returned = 0;
2215 __u16 params, param_offset, offset, byte_count;
2216
Joe Perchesb6b38f72010-04-21 03:50:45 +00002217 cFYI(1, "In Create Hard link Unix style");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218createHardLinkRetry:
2219 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2220 (void **) &pSMBr);
2221 if (rc)
2222 return rc;
2223
2224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002225 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002226 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 name_len++; /* trailing null */
2228 name_len *= 2;
2229
Steve French50c2f752007-07-13 00:33:32 +00002230 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 name_len = strnlen(toName, PATH_MAX);
2232 name_len++; /* trailing null */
2233 strncpy(pSMB->FileName, toName, name_len);
2234 }
2235 params = 6 + name_len;
2236 pSMB->MaxSetupCount = 0;
2237 pSMB->Reserved = 0;
2238 pSMB->Flags = 0;
2239 pSMB->Timeout = 0;
2240 pSMB->Reserved2 = 0;
2241 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002242 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 offset = param_offset + params;
2244
2245 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2247 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002248 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002249 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 name_len_target++; /* trailing null */
2251 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002252 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 name_len_target = strnlen(fromName, PATH_MAX);
2254 name_len_target++; /* trailing null */
2255 strncpy(data_offset, fromName, name_len_target);
2256 }
2257
2258 pSMB->MaxParameterCount = cpu_to_le16(2);
2259 /* BB find exact max on data count below from sess*/
2260 pSMB->MaxDataCount = cpu_to_le16(1000);
2261 pSMB->SetupCount = 1;
2262 pSMB->Reserved3 = 0;
2263 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2264 byte_count = 3 /* pad */ + params + name_len_target;
2265 pSMB->ParameterCount = cpu_to_le16(params);
2266 pSMB->TotalParameterCount = pSMB->ParameterCount;
2267 pSMB->DataCount = cpu_to_le16(name_len_target);
2268 pSMB->TotalDataCount = pSMB->DataCount;
2269 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2270 pSMB->DataOffset = cpu_to_le16(offset);
2271 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2272 pSMB->Reserved4 = 0;
2273 pSMB->hdr.smb_buf_length += byte_count;
2274 pSMB->ByteCount = cpu_to_le16(byte_count);
2275 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2276 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002277 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002278 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002279 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281 cifs_buf_release(pSMB);
2282 if (rc == -EAGAIN)
2283 goto createHardLinkRetry;
2284
2285 return rc;
2286}
2287
2288int
2289CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2290 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002291 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292{
2293 int rc = 0;
2294 NT_RENAME_REQ *pSMB = NULL;
2295 RENAME_RSP *pSMBr = NULL;
2296 int bytes_returned;
2297 int name_len, name_len2;
2298 __u16 count;
2299
Joe Perchesb6b38f72010-04-21 03:50:45 +00002300 cFYI(1, "In CIFSCreateHardLink");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301winCreateHardLinkRetry:
2302
2303 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2304 (void **) &pSMBr);
2305 if (rc)
2306 return rc;
2307
2308 pSMB->SearchAttributes =
2309 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2310 ATTR_DIRECTORY);
2311 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2312 pSMB->ClusterCount = 0;
2313
2314 pSMB->BufferFormat = 0x04;
2315
2316 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2317 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002318 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002319 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 name_len++; /* trailing null */
2321 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002322
2323 /* protocol specifies ASCII buffer format (0x04) for unicode */
2324 pSMB->OldFileName[name_len] = 0x04;
2325 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002327 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002328 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2330 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002331 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002332 name_len = strnlen(fromName, PATH_MAX);
2333 name_len++; /* trailing null */
2334 strncpy(pSMB->OldFileName, fromName, name_len);
2335 name_len2 = strnlen(toName, PATH_MAX);
2336 name_len2++; /* trailing null */
2337 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2338 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2339 name_len2++; /* trailing null */
2340 name_len2++; /* signature byte */
2341 }
2342
2343 count = 1 /* string type byte */ + name_len + name_len2;
2344 pSMB->hdr.smb_buf_length += count;
2345 pSMB->ByteCount = cpu_to_le16(count);
2346
2347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002349 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002350 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002351 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00002352
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 cifs_buf_release(pSMB);
2354 if (rc == -EAGAIN)
2355 goto winCreateHardLinkRetry;
2356
2357 return rc;
2358}
2359
2360int
2361CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002362 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 const struct nls_table *nls_codepage)
2364{
2365/* SMB_QUERY_FILE_UNIX_LINK */
2366 TRANSACTION2_QPI_REQ *pSMB = NULL;
2367 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2368 int rc = 0;
2369 int bytes_returned;
2370 int name_len;
2371 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002372 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Joe Perchesb6b38f72010-04-21 03:50:45 +00002374 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
2376querySymLinkRetry:
2377 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2378 (void **) &pSMBr);
2379 if (rc)
2380 return rc;
2381
2382 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2383 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002384 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2385 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386 name_len++; /* trailing null */
2387 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002388 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 name_len = strnlen(searchName, PATH_MAX);
2390 name_len++; /* trailing null */
2391 strncpy(pSMB->FileName, searchName, name_len);
2392 }
2393
2394 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2395 pSMB->TotalDataCount = 0;
2396 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002397 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398 pSMB->MaxSetupCount = 0;
2399 pSMB->Reserved = 0;
2400 pSMB->Flags = 0;
2401 pSMB->Timeout = 0;
2402 pSMB->Reserved2 = 0;
2403 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002404 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405 pSMB->DataCount = 0;
2406 pSMB->DataOffset = 0;
2407 pSMB->SetupCount = 1;
2408 pSMB->Reserved3 = 0;
2409 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2410 byte_count = params + 1 /* pad */ ;
2411 pSMB->TotalParameterCount = cpu_to_le16(params);
2412 pSMB->ParameterCount = pSMB->TotalParameterCount;
2413 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2414 pSMB->Reserved4 = 0;
2415 pSMB->hdr.smb_buf_length += byte_count;
2416 pSMB->ByteCount = cpu_to_le16(byte_count);
2417
2418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2420 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002421 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 } else {
2423 /* decode response */
2424
2425 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002427 if (rc || (pSMBr->ByteCount < 2))
2428 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002430 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002431 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432
Jeff Layton460b9692009-04-30 07:17:56 -04002433 data_start = ((char *) &pSMBr->hdr.Protocol) +
2434 le16_to_cpu(pSMBr->t2.DataOffset);
2435
Steve French0e0d2cf2009-05-01 05:27:32 +00002436 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2437 is_unicode = true;
2438 else
2439 is_unicode = false;
2440
Steve French737b7582005-04-28 22:41:06 -07002441 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002442 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002443 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002444 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002445 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 }
2447 }
2448 cifs_buf_release(pSMB);
2449 if (rc == -EAGAIN)
2450 goto querySymLinkRetry;
2451 return rc;
2452}
2453
Parag Warudkarc9489772007-10-23 18:09:48 +00002454#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002455/* Initialize NT TRANSACT SMB into small smb request buffer.
2456 This assumes that all NT TRANSACTS that we init here have
2457 total parm and data under about 400 bytes (to fit in small cifs
2458 buffer size), which is the case so far, it easily fits. NB:
2459 Setup words themselves and ByteCount
2460 MaxSetupCount (size of returned setup area) and
2461 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002462static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002463smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002464 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002465 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002466{
2467 int rc;
2468 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002469 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002470
2471 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2472 (void **)&pSMB);
2473 if (rc)
2474 return rc;
2475 *ret_buf = (void *)pSMB;
2476 pSMB->Reserved = 0;
2477 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2478 pSMB->TotalDataCount = 0;
2479 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2480 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2481 pSMB->ParameterCount = pSMB->TotalParameterCount;
2482 pSMB->DataCount = pSMB->TotalDataCount;
2483 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2484 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2485 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2486 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2487 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2488 pSMB->SubCommand = cpu_to_le16(sub_command);
2489 return 0;
2490}
2491
2492static int
Steve French50c2f752007-07-13 00:33:32 +00002493validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002494 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002495{
Steve French50c2f752007-07-13 00:33:32 +00002496 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002497 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002498 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002499
Steve French630f3f0c2007-10-25 21:17:17 +00002500 *pdatalen = 0;
2501 *pparmlen = 0;
2502
Steve French790fe572007-07-07 19:25:05 +00002503 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002504 return -EINVAL;
2505
2506 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2507
2508 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002509 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002510 (char *)&pSMBr->ByteCount;
2511
Steve French0a4b92c2006-01-12 15:44:21 -08002512 data_offset = le32_to_cpu(pSMBr->DataOffset);
2513 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002514 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002515 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2516
2517 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2518 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2519
2520 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002521 if (*ppparm > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002522 cFYI(1, "parms start after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002523 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002524 } else if (parm_count + *ppparm > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002525 cFYI(1, "parm end after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002526 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002527 } else if (*ppdata > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002528 cFYI(1, "data starts after end of smb");
Steve French0a4b92c2006-01-12 15:44:21 -08002529 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002530 } else if (data_count + *ppdata > end_of_smb) {
Steve Frenchf19159d2010-04-21 04:12:10 +00002531 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002532 *ppdata, data_count, (data_count + *ppdata),
Joe Perchesb6b38f72010-04-21 03:50:45 +00002533 end_of_smb, pSMBr);
Steve French0a4b92c2006-01-12 15:44:21 -08002534 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002535 } else if (parm_count + data_count > pSMBr->ByteCount) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002536 cFYI(1, "parm count and data count larger than SMB");
Steve French0a4b92c2006-01-12 15:44:21 -08002537 return -EINVAL;
2538 }
Steve French630f3f0c2007-10-25 21:17:17 +00002539 *pdatalen = data_count;
2540 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002541 return 0;
2542}
2543
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544int
2545CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2546 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002547 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548 const struct nls_table *nls_codepage)
2549{
2550 int rc = 0;
2551 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002552 struct smb_com_transaction_ioctl_req *pSMB;
2553 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
Joe Perchesb6b38f72010-04-21 03:50:45 +00002555 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2557 (void **) &pSMBr);
2558 if (rc)
2559 return rc;
2560
2561 pSMB->TotalParameterCount = 0 ;
2562 pSMB->TotalDataCount = 0;
2563 pSMB->MaxParameterCount = cpu_to_le32(2);
2564 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002565 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2566 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 pSMB->MaxSetupCount = 4;
2568 pSMB->Reserved = 0;
2569 pSMB->ParameterOffset = 0;
2570 pSMB->DataCount = 0;
2571 pSMB->DataOffset = 0;
2572 pSMB->SetupCount = 4;
2573 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2574 pSMB->ParameterCount = pSMB->TotalParameterCount;
2575 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2576 pSMB->IsFsctl = 1; /* FSCTL */
2577 pSMB->IsRootFlag = 0;
2578 pSMB->Fid = fid; /* file handle always le */
2579 pSMB->ByteCount = 0;
2580
2581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2582 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2583 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002584 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002585 } else { /* decode response */
2586 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2587 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002588 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 /* BB also check enough total bytes returned */
2590 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002591 goto qreparse_out;
2592 }
2593 if (data_count && (data_count < 2048)) {
2594 char *end_of_smb = 2 /* sizeof byte count */ +
2595 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596
Steve Frenchafe48c32009-05-02 05:25:46 +00002597 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002598 (struct reparse_data *)
2599 ((char *)&pSMBr->hdr.Protocol
2600 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002601 if ((char *)reparse_buf >= end_of_smb) {
2602 rc = -EIO;
2603 goto qreparse_out;
2604 }
2605 if ((reparse_buf->LinkNamesBuf +
2606 reparse_buf->TargetNameOffset +
2607 reparse_buf->TargetNameLen) > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002608 cFYI(1, "reparse buf beyond SMB");
Steve Frenchafe48c32009-05-02 05:25:46 +00002609 rc = -EIO;
2610 goto qreparse_out;
2611 }
Steve French50c2f752007-07-13 00:33:32 +00002612
Steve Frenchafe48c32009-05-02 05:25:46 +00002613 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2614 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002615 (reparse_buf->LinkNamesBuf +
2616 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002617 buflen,
2618 reparse_buf->TargetNameLen,
2619 nls_codepage, 0);
2620 } else { /* ASCII names */
2621 strncpy(symlinkinfo,
2622 reparse_buf->LinkNamesBuf +
2623 reparse_buf->TargetNameOffset,
2624 min_t(const int, buflen,
2625 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002627 } else {
2628 rc = -EIO;
Joe Perchesb6b38f72010-04-21 03:50:45 +00002629 cFYI(1, "Invalid return data count on "
2630 "get reparse info ioctl");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002632 symlinkinfo[buflen] = 0; /* just in case so the caller
2633 does not go off the end of the buffer */
Joe Perchesb6b38f72010-04-21 03:50:45 +00002634 cFYI(1, "readlink result - %s", symlinkinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 }
Steve French989c7e52009-05-02 05:32:20 +00002636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002638 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639
2640 /* Note: On -EAGAIN error only caller can retry on handle based calls
2641 since file handle passed in no longer valid */
2642
2643 return rc;
2644}
Steve Frenchafe48c32009-05-02 05:25:46 +00002645#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647#ifdef CONFIG_CIFS_POSIX
2648
2649/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002650static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2651 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652{
2653 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002654 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2655 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2656 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002657 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658
2659 return;
2660}
2661
2662/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002663static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2664 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665{
2666 int size = 0;
2667 int i;
2668 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002669 struct cifs_posix_ace *pACE;
2670 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2671 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2674 return -EOPNOTSUPP;
2675
Steve French790fe572007-07-07 19:25:05 +00002676 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 count = le16_to_cpu(cifs_acl->access_entry_count);
2678 pACE = &cifs_acl->ace_array[0];
2679 size = sizeof(struct cifs_posix_acl);
2680 size += sizeof(struct cifs_posix_ace) * count;
2681 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002682 if (size_of_data_area < size) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002683 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
2684 size_of_data_area, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 return -EINVAL;
2686 }
Steve French790fe572007-07-07 19:25:05 +00002687 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 count = le16_to_cpu(cifs_acl->access_entry_count);
2689 size = sizeof(struct cifs_posix_acl);
2690 size += sizeof(struct cifs_posix_ace) * count;
2691/* skip past access ACEs to get to default ACEs */
2692 pACE = &cifs_acl->ace_array[count];
2693 count = le16_to_cpu(cifs_acl->default_entry_count);
2694 size += sizeof(struct cifs_posix_ace) * count;
2695 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002696 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 return -EINVAL;
2698 } else {
2699 /* illegal type */
2700 return -EINVAL;
2701 }
2702
2703 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002704 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002705 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002706 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 return -ERANGE;
2708 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002709 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002710 for (i = 0; i < count ; i++) {
2711 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2712 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 }
2714 }
2715 return size;
2716}
2717
Steve French50c2f752007-07-13 00:33:32 +00002718static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2719 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720{
2721 __u16 rc = 0; /* 0 = ACL converted ok */
2722
Steve Frenchff7feac2005-11-15 16:45:16 -08002723 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2724 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002726 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 /* Probably no need to le convert -1 on any arch but can not hurt */
2728 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002729 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002730 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Joe Perchesb6b38f72010-04-21 03:50:45 +00002731 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 return rc;
2733}
2734
2735/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002736static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2737 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738{
2739 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002740 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2741 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 int count;
2743 int i;
2744
Steve French790fe572007-07-07 19:25:05 +00002745 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 return 0;
2747
2748 count = posix_acl_xattr_count((size_t)buflen);
Joe Perchesb6b38f72010-04-21 03:50:45 +00002749 cFYI(1, "setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002750 "version of %d",
Joe Perchesb6b38f72010-04-21 03:50:45 +00002751 count, buflen, le32_to_cpu(local_acl->a_version));
Steve French790fe572007-07-07 19:25:05 +00002752 if (le32_to_cpu(local_acl->a_version) != 2) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002753 cFYI(1, "unknown POSIX ACL version %d",
2754 le32_to_cpu(local_acl->a_version));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return 0;
2756 }
2757 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002758 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002759 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002760 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002761 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 else {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002763 cFYI(1, "unknown ACL type %d", acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 return 0;
2765 }
Steve French50c2f752007-07-13 00:33:32 +00002766 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2768 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002769 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 /* ACE not converted */
2771 break;
2772 }
2773 }
Steve French790fe572007-07-07 19:25:05 +00002774 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2776 rc += sizeof(struct cifs_posix_acl);
2777 /* BB add check to make sure ACL does not overflow SMB */
2778 }
2779 return rc;
2780}
2781
2782int
2783CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002784 const unsigned char *searchName,
2785 char *acl_inf, const int buflen, const int acl_type,
2786 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787{
2788/* SMB_QUERY_POSIX_ACL */
2789 TRANSACTION2_QPI_REQ *pSMB = NULL;
2790 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2791 int rc = 0;
2792 int bytes_returned;
2793 int name_len;
2794 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002795
Joe Perchesb6b38f72010-04-21 03:50:45 +00002796 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
2798queryAclRetry:
2799 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2800 (void **) &pSMBr);
2801 if (rc)
2802 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2805 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002806 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002807 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 name_len++; /* trailing null */
2809 name_len *= 2;
2810 pSMB->FileName[name_len] = 0;
2811 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002812 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 name_len = strnlen(searchName, PATH_MAX);
2814 name_len++; /* trailing null */
2815 strncpy(pSMB->FileName, searchName, name_len);
2816 }
2817
2818 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2819 pSMB->TotalDataCount = 0;
2820 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002821 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 pSMB->MaxDataCount = cpu_to_le16(4000);
2823 pSMB->MaxSetupCount = 0;
2824 pSMB->Reserved = 0;
2825 pSMB->Flags = 0;
2826 pSMB->Timeout = 0;
2827 pSMB->Reserved2 = 0;
2828 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002829 offsetof(struct smb_com_transaction2_qpi_req,
2830 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 pSMB->DataCount = 0;
2832 pSMB->DataOffset = 0;
2833 pSMB->SetupCount = 1;
2834 pSMB->Reserved3 = 0;
2835 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2836 byte_count = params + 1 /* pad */ ;
2837 pSMB->TotalParameterCount = cpu_to_le16(params);
2838 pSMB->ParameterCount = pSMB->TotalParameterCount;
2839 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2840 pSMB->Reserved4 = 0;
2841 pSMB->hdr.smb_buf_length += byte_count;
2842 pSMB->ByteCount = cpu_to_le16(byte_count);
2843
2844 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2845 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002846 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002848 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 } else {
2850 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002851
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2853 if (rc || (pSMBr->ByteCount < 2))
2854 /* BB also check enough total bytes returned */
2855 rc = -EIO; /* bad smb */
2856 else {
2857 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2858 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2859 rc = cifs_copy_posix_acl(acl_inf,
2860 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002861 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862 }
2863 }
2864 cifs_buf_release(pSMB);
2865 if (rc == -EAGAIN)
2866 goto queryAclRetry;
2867 return rc;
2868}
2869
2870int
2871CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002872 const unsigned char *fileName,
2873 const char *local_acl, const int buflen,
2874 const int acl_type,
2875 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876{
2877 struct smb_com_transaction2_spi_req *pSMB = NULL;
2878 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2879 char *parm_data;
2880 int name_len;
2881 int rc = 0;
2882 int bytes_returned = 0;
2883 __u16 params, byte_count, data_count, param_offset, offset;
2884
Joe Perchesb6b38f72010-04-21 03:50:45 +00002885 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886setAclRetry:
2887 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002888 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 if (rc)
2890 return rc;
2891 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2892 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002893 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002894 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 name_len++; /* trailing null */
2896 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002897 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 name_len = strnlen(fileName, PATH_MAX);
2899 name_len++; /* trailing null */
2900 strncpy(pSMB->FileName, fileName, name_len);
2901 }
2902 params = 6 + name_len;
2903 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002904 /* BB find max SMB size from sess */
2905 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 pSMB->MaxSetupCount = 0;
2907 pSMB->Reserved = 0;
2908 pSMB->Flags = 0;
2909 pSMB->Timeout = 0;
2910 pSMB->Reserved2 = 0;
2911 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002912 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002913 offset = param_offset + params;
2914 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2915 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2916
2917 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002918 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
Steve French790fe572007-07-07 19:25:05 +00002920 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 rc = -EOPNOTSUPP;
2922 goto setACLerrorExit;
2923 }
2924 pSMB->DataOffset = cpu_to_le16(offset);
2925 pSMB->SetupCount = 1;
2926 pSMB->Reserved3 = 0;
2927 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2928 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2929 byte_count = 3 /* pad */ + params + data_count;
2930 pSMB->DataCount = cpu_to_le16(data_count);
2931 pSMB->TotalDataCount = pSMB->DataCount;
2932 pSMB->ParameterCount = cpu_to_le16(params);
2933 pSMB->TotalParameterCount = pSMB->ParameterCount;
2934 pSMB->Reserved4 = 0;
2935 pSMB->hdr.smb_buf_length += byte_count;
2936 pSMB->ByteCount = cpu_to_le16(byte_count);
2937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002939 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00002940 cFYI(1, "Set POSIX ACL returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941
2942setACLerrorExit:
2943 cifs_buf_release(pSMB);
2944 if (rc == -EAGAIN)
2945 goto setAclRetry;
2946 return rc;
2947}
2948
Steve Frenchf654bac2005-04-28 22:41:04 -07002949/* BB fix tabs in this function FIXME BB */
2950int
2951CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002952 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002953{
Steve French50c2f752007-07-13 00:33:32 +00002954 int rc = 0;
2955 struct smb_t2_qfi_req *pSMB = NULL;
2956 struct smb_t2_qfi_rsp *pSMBr = NULL;
2957 int bytes_returned;
2958 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002959
Joe Perchesb6b38f72010-04-21 03:50:45 +00002960 cFYI(1, "In GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00002961 if (tcon == NULL)
2962 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002963
2964GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002965 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2966 (void **) &pSMBr);
2967 if (rc)
2968 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002969
Steve Frenchad7a2922008-02-07 23:25:02 +00002970 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002971 pSMB->t2.TotalDataCount = 0;
2972 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2973 /* BB find exact max data count below from sess structure BB */
2974 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2975 pSMB->t2.MaxSetupCount = 0;
2976 pSMB->t2.Reserved = 0;
2977 pSMB->t2.Flags = 0;
2978 pSMB->t2.Timeout = 0;
2979 pSMB->t2.Reserved2 = 0;
2980 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2981 Fid) - 4);
2982 pSMB->t2.DataCount = 0;
2983 pSMB->t2.DataOffset = 0;
2984 pSMB->t2.SetupCount = 1;
2985 pSMB->t2.Reserved3 = 0;
2986 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2987 byte_count = params + 1 /* pad */ ;
2988 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2989 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2990 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2991 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002992 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002993 pSMB->hdr.smb_buf_length += byte_count;
2994 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002995
Steve French790fe572007-07-07 19:25:05 +00002996 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2997 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2998 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00002999 cFYI(1, "error %d in GetExtAttr", rc);
Steve French790fe572007-07-07 19:25:05 +00003000 } else {
3001 /* decode response */
3002 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3003 if (rc || (pSMBr->ByteCount < 2))
3004 /* BB also check enough total bytes returned */
3005 /* If rc should we check for EOPNOSUPP and
3006 disable the srvino flag? or in caller? */
3007 rc = -EIO; /* bad smb */
3008 else {
3009 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3010 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3011 struct file_chattr_info *pfinfo;
3012 /* BB Do we need a cast or hash here ? */
3013 if (count != 16) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003014 cFYI(1, "Illegal size ret in GetExtAttr");
Steve French790fe572007-07-07 19:25:05 +00003015 rc = -EIO;
3016 goto GetExtAttrOut;
3017 }
3018 pfinfo = (struct file_chattr_info *)
3019 (data_offset + (char *) &pSMBr->hdr.Protocol);
3020 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003021 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003022 }
3023 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003024GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003025 cifs_buf_release(pSMB);
3026 if (rc == -EAGAIN)
3027 goto GetExtAttrRetry;
3028 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003029}
3030
Steve Frenchf654bac2005-04-28 22:41:04 -07003031#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032
Steve French297647c2007-10-12 04:11:59 +00003033#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003034/* Get Security Descriptor (by handle) from remote server for a file or dir */
3035int
3036CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003037 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003038{
3039 int rc = 0;
3040 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003041 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003042 struct kvec iov[1];
3043
Joe Perchesb6b38f72010-04-21 03:50:45 +00003044 cFYI(1, "GetCifsACL");
Steve French0a4b92c2006-01-12 15:44:21 -08003045
Steve French630f3f0c2007-10-25 21:17:17 +00003046 *pbuflen = 0;
3047 *acl_inf = NULL;
3048
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003049 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003050 8 /* parm len */, tcon, (void **) &pSMB);
3051 if (rc)
3052 return rc;
3053
3054 pSMB->MaxParameterCount = cpu_to_le32(4);
3055 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3056 pSMB->MaxSetupCount = 0;
3057 pSMB->Fid = fid; /* file handle always le */
3058 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3059 CIFS_ACL_DACL);
3060 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3061 pSMB->hdr.smb_buf_length += 11;
3062 iov[0].iov_base = (char *)pSMB;
3063 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3064
Steve Frencha761ac52007-10-18 21:45:27 +00003065 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003066 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003067 cifs_stats_inc(&tcon->num_acl_get);
3068 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003069 cFYI(1, "Send error in QuerySecDesc = %d", rc);
Steve French0a4b92c2006-01-12 15:44:21 -08003070 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003071 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003072 __u32 parm_len;
3073 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003074 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003075 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003076
3077/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003078 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003079 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003080 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003081 goto qsec_out;
3082 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3083
Joe Perchesb6b38f72010-04-21 03:50:45 +00003084 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
Steve French0a4b92c2006-01-12 15:44:21 -08003085
3086 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3087 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003088 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003089 goto qsec_out;
3090 }
3091
3092/* BB check that data area is minimum length and as big as acl_len */
3093
Steve Frenchaf6f4612007-10-16 18:40:37 +00003094 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003095 if (acl_len != *pbuflen) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003096 cERROR(1, "acl length %d does not match %d",
3097 acl_len, *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003098 if (*pbuflen > acl_len)
3099 *pbuflen = acl_len;
3100 }
Steve French0a4b92c2006-01-12 15:44:21 -08003101
Steve French630f3f0c2007-10-25 21:17:17 +00003102 /* check if buffer is big enough for the acl
3103 header followed by the smallest SID */
3104 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3105 (*pbuflen >= 64 * 1024)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003106 cERROR(1, "bad acl length %d", *pbuflen);
Steve French630f3f0c2007-10-25 21:17:17 +00003107 rc = -EINVAL;
3108 *pbuflen = 0;
3109 } else {
3110 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3111 if (*acl_inf == NULL) {
3112 *pbuflen = 0;
3113 rc = -ENOMEM;
3114 }
3115 memcpy(*acl_inf, pdata, *pbuflen);
3116 }
Steve French0a4b92c2006-01-12 15:44:21 -08003117 }
3118qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003119 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003120 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003121 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003122 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003123/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003124 return rc;
3125}
Steve French97837582007-12-31 07:47:21 +00003126
3127int
3128CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3129 struct cifs_ntsd *pntsd, __u32 acllen)
3130{
3131 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3132 int rc = 0;
3133 int bytes_returned = 0;
3134 SET_SEC_DESC_REQ *pSMB = NULL;
3135 NTRANSACT_RSP *pSMBr = NULL;
3136
3137setCifsAclRetry:
3138 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3139 (void **) &pSMBr);
3140 if (rc)
3141 return (rc);
3142
3143 pSMB->MaxSetupCount = 0;
3144 pSMB->Reserved = 0;
3145
3146 param_count = 8;
3147 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3148 data_count = acllen;
3149 data_offset = param_offset + param_count;
3150 byte_count = 3 /* pad */ + param_count;
3151
3152 pSMB->DataCount = cpu_to_le32(data_count);
3153 pSMB->TotalDataCount = pSMB->DataCount;
3154 pSMB->MaxParameterCount = cpu_to_le32(4);
3155 pSMB->MaxDataCount = cpu_to_le32(16384);
3156 pSMB->ParameterCount = cpu_to_le32(param_count);
3157 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3158 pSMB->TotalParameterCount = pSMB->ParameterCount;
3159 pSMB->DataOffset = cpu_to_le32(data_offset);
3160 pSMB->SetupCount = 0;
3161 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3162 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3163
3164 pSMB->Fid = fid; /* file handle always le */
3165 pSMB->Reserved2 = 0;
3166 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3167
3168 if (pntsd && acllen) {
3169 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3170 (char *) pntsd,
3171 acllen);
3172 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3173
3174 } else
3175 pSMB->hdr.smb_buf_length += byte_count;
3176
3177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3179
Joe Perchesb6b38f72010-04-21 03:50:45 +00003180 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
Steve French97837582007-12-31 07:47:21 +00003181 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003182 cFYI(1, "Set CIFS ACL returned %d", rc);
Steve French97837582007-12-31 07:47:21 +00003183 cifs_buf_release(pSMB);
3184
3185 if (rc == -EAGAIN)
3186 goto setCifsAclRetry;
3187
3188 return (rc);
3189}
3190
Steve French297647c2007-10-12 04:11:59 +00003191#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003192
Steve French6b8edfe2005-08-23 20:26:03 -07003193/* Legacy Query Path Information call for lookup to old servers such
3194 as Win9x/WinME */
3195int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003196 const unsigned char *searchName,
3197 FILE_ALL_INFO *pFinfo,
3198 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003199{
Steve Frenchad7a2922008-02-07 23:25:02 +00003200 QUERY_INFORMATION_REQ *pSMB;
3201 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003202 int rc = 0;
3203 int bytes_returned;
3204 int name_len;
3205
Joe Perchesb6b38f72010-04-21 03:50:45 +00003206 cFYI(1, "In SMBQPath path %s", searchName);
Steve French6b8edfe2005-08-23 20:26:03 -07003207QInfRetry:
3208 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003209 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003210 if (rc)
3211 return rc;
3212
3213 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3214 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003215 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3216 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003217 name_len++; /* trailing null */
3218 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003219 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003220 name_len = strnlen(searchName, PATH_MAX);
3221 name_len++; /* trailing null */
3222 strncpy(pSMB->FileName, searchName, name_len);
3223 }
3224 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003225 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003226 pSMB->hdr.smb_buf_length += (__u16) name_len;
3227 pSMB->ByteCount = cpu_to_le16(name_len);
3228
3229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003231 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003232 cFYI(1, "Send error in QueryInfo = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003233 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003234 struct timespec ts;
3235 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003236
3237 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003238 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003239 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003240 ts.tv_nsec = 0;
3241 ts.tv_sec = time;
3242 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003243 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003244 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3245 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003246 pFinfo->AllocationSize =
3247 cpu_to_le64(le32_to_cpu(pSMBr->size));
3248 pFinfo->EndOfFile = pFinfo->AllocationSize;
3249 pFinfo->Attributes =
3250 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003251 } else
3252 rc = -EIO; /* bad buffer passed in */
3253
3254 cifs_buf_release(pSMB);
3255
3256 if (rc == -EAGAIN)
3257 goto QInfRetry;
3258
3259 return rc;
3260}
3261
Jeff Laytonbcd53572010-02-12 07:44:16 -05003262int
3263CIFSSMBQFileInfo(const int xid, struct cifsTconInfo *tcon,
3264 u16 netfid, FILE_ALL_INFO *pFindData)
3265{
3266 struct smb_t2_qfi_req *pSMB = NULL;
3267 struct smb_t2_qfi_rsp *pSMBr = NULL;
3268 int rc = 0;
3269 int bytes_returned;
3270 __u16 params, byte_count;
Steve French6b8edfe2005-08-23 20:26:03 -07003271
Jeff Laytonbcd53572010-02-12 07:44:16 -05003272QFileInfoRetry:
3273 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3274 (void **) &pSMBr);
3275 if (rc)
3276 return rc;
Steve French6b8edfe2005-08-23 20:26:03 -07003277
Jeff Laytonbcd53572010-02-12 07:44:16 -05003278 params = 2 /* level */ + 2 /* fid */;
3279 pSMB->t2.TotalDataCount = 0;
3280 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3281 /* BB find exact max data count below from sess structure BB */
3282 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3283 pSMB->t2.MaxSetupCount = 0;
3284 pSMB->t2.Reserved = 0;
3285 pSMB->t2.Flags = 0;
3286 pSMB->t2.Timeout = 0;
3287 pSMB->t2.Reserved2 = 0;
3288 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3289 Fid) - 4);
3290 pSMB->t2.DataCount = 0;
3291 pSMB->t2.DataOffset = 0;
3292 pSMB->t2.SetupCount = 1;
3293 pSMB->t2.Reserved3 = 0;
3294 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3295 byte_count = params + 1 /* pad */ ;
3296 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3297 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3298 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3299 pSMB->Pad = 0;
3300 pSMB->Fid = netfid;
3301 pSMB->hdr.smb_buf_length += byte_count;
3302
3303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3305 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003306 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonbcd53572010-02-12 07:44:16 -05003307 } else { /* decode response */
3308 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3309
3310 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3311 rc = -EIO;
3312 else if (pSMBr->ByteCount < 40)
3313 rc = -EIO; /* bad smb */
3314 else if (pFindData) {
3315 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3316 memcpy((char *) pFindData,
3317 (char *) &pSMBr->hdr.Protocol +
3318 data_offset, sizeof(FILE_ALL_INFO));
3319 } else
3320 rc = -ENOMEM;
3321 }
3322 cifs_buf_release(pSMB);
3323 if (rc == -EAGAIN)
3324 goto QFileInfoRetry;
3325
3326 return rc;
3327}
Steve French6b8edfe2005-08-23 20:26:03 -07003328
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329int
3330CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3331 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003332 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003333 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003334 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335{
3336/* level 263 SMB_QUERY_FILE_ALL_INFO */
3337 TRANSACTION2_QPI_REQ *pSMB = NULL;
3338 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3339 int rc = 0;
3340 int bytes_returned;
3341 int name_len;
3342 __u16 params, byte_count;
3343
Joe Perchesb6b38f72010-04-21 03:50:45 +00003344/* cFYI(1, "In QPathInfo path %s", searchName); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345QPathInfoRetry:
3346 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3347 (void **) &pSMBr);
3348 if (rc)
3349 return rc;
3350
3351 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3352 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003353 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003354 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003355 name_len++; /* trailing null */
3356 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003357 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 name_len = strnlen(searchName, PATH_MAX);
3359 name_len++; /* trailing null */
3360 strncpy(pSMB->FileName, searchName, name_len);
3361 }
3362
Steve French50c2f752007-07-13 00:33:32 +00003363 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 pSMB->TotalDataCount = 0;
3365 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003366 /* BB find exact max SMB PDU from sess structure BB */
3367 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368 pSMB->MaxSetupCount = 0;
3369 pSMB->Reserved = 0;
3370 pSMB->Flags = 0;
3371 pSMB->Timeout = 0;
3372 pSMB->Reserved2 = 0;
3373 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003374 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003375 pSMB->DataCount = 0;
3376 pSMB->DataOffset = 0;
3377 pSMB->SetupCount = 1;
3378 pSMB->Reserved3 = 0;
3379 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3380 byte_count = params + 1 /* pad */ ;
3381 pSMB->TotalParameterCount = cpu_to_le16(params);
3382 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003383 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003384 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3385 else
3386 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 pSMB->Reserved4 = 0;
3388 pSMB->hdr.smb_buf_length += byte_count;
3389 pSMB->ByteCount = cpu_to_le16(byte_count);
3390
3391 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3392 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3393 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003394 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003395 } else { /* decode response */
3396 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3397
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003398 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3399 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003400 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003402 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003403 rc = -EIO; /* 24 or 26 expected but we do not read
3404 last field */
3405 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003406 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003408
3409 /* On legacy responses we do not read the last field,
3410 EAsize, fortunately since it varies by subdialect and
3411 also note it differs on Set vs. Get, ie two bytes or 4
3412 bytes depending but we don't care here */
3413 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003414 size = sizeof(FILE_INFO_STANDARD);
3415 else
3416 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417 memcpy((char *) pFindData,
3418 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003419 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 } else
3421 rc = -ENOMEM;
3422 }
3423 cifs_buf_release(pSMB);
3424 if (rc == -EAGAIN)
3425 goto QPathInfoRetry;
3426
3427 return rc;
3428}
3429
3430int
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003431CIFSSMBUnixQFileInfo(const int xid, struct cifsTconInfo *tcon,
3432 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
3433{
3434 struct smb_t2_qfi_req *pSMB = NULL;
3435 struct smb_t2_qfi_rsp *pSMBr = NULL;
3436 int rc = 0;
3437 int bytes_returned;
3438 __u16 params, byte_count;
3439
3440UnixQFileInfoRetry:
3441 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3442 (void **) &pSMBr);
3443 if (rc)
3444 return rc;
3445
3446 params = 2 /* level */ + 2 /* fid */;
3447 pSMB->t2.TotalDataCount = 0;
3448 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3449 /* BB find exact max data count below from sess structure BB */
3450 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3451 pSMB->t2.MaxSetupCount = 0;
3452 pSMB->t2.Reserved = 0;
3453 pSMB->t2.Flags = 0;
3454 pSMB->t2.Timeout = 0;
3455 pSMB->t2.Reserved2 = 0;
3456 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3457 Fid) - 4);
3458 pSMB->t2.DataCount = 0;
3459 pSMB->t2.DataOffset = 0;
3460 pSMB->t2.SetupCount = 1;
3461 pSMB->t2.Reserved3 = 0;
3462 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3463 byte_count = params + 1 /* pad */ ;
3464 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3465 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3466 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3467 pSMB->Pad = 0;
3468 pSMB->Fid = netfid;
3469 pSMB->hdr.smb_buf_length += byte_count;
3470
3471 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3472 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3473 if (rc) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003474 cFYI(1, "Send error in QPathInfo = %d", rc);
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003475 } else { /* decode response */
3476 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3477
3478 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve Frenchf19159d2010-04-21 04:12:10 +00003479 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003480 "Unix Extensions can be disabled on mount "
Steve Frenchf19159d2010-04-21 04:12:10 +00003481 "by specifying the nosfu mount option.");
Jeff Laytonc8634fd2010-02-12 07:44:17 -05003482 rc = -EIO; /* bad smb */
3483 } else {
3484 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3485 memcpy((char *) pFindData,
3486 (char *) &pSMBr->hdr.Protocol +
3487 data_offset,
3488 sizeof(FILE_UNIX_BASIC_INFO));
3489 }
3490 }
3491
3492 cifs_buf_release(pSMB);
3493 if (rc == -EAGAIN)
3494 goto UnixQFileInfoRetry;
3495
3496 return rc;
3497}
3498
3499int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3501 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003502 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003503 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504{
3505/* SMB_QUERY_FILE_UNIX_BASIC */
3506 TRANSACTION2_QPI_REQ *pSMB = NULL;
3507 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3508 int rc = 0;
3509 int bytes_returned = 0;
3510 int name_len;
3511 __u16 params, byte_count;
3512
Joe Perchesb6b38f72010-04-21 03:50:45 +00003513 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514UnixQPathInfoRetry:
3515 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3516 (void **) &pSMBr);
3517 if (rc)
3518 return rc;
3519
3520 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3521 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003522 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003523 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 name_len++; /* trailing null */
3525 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003526 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 name_len = strnlen(searchName, PATH_MAX);
3528 name_len++; /* trailing null */
3529 strncpy(pSMB->FileName, searchName, name_len);
3530 }
3531
Steve French50c2f752007-07-13 00:33:32 +00003532 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 pSMB->TotalDataCount = 0;
3534 pSMB->MaxParameterCount = cpu_to_le16(2);
3535 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003536 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 pSMB->MaxSetupCount = 0;
3538 pSMB->Reserved = 0;
3539 pSMB->Flags = 0;
3540 pSMB->Timeout = 0;
3541 pSMB->Reserved2 = 0;
3542 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003543 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 pSMB->DataCount = 0;
3545 pSMB->DataOffset = 0;
3546 pSMB->SetupCount = 1;
3547 pSMB->Reserved3 = 0;
3548 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3549 byte_count = params + 1 /* pad */ ;
3550 pSMB->TotalParameterCount = cpu_to_le16(params);
3551 pSMB->ParameterCount = pSMB->TotalParameterCount;
3552 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3553 pSMB->Reserved4 = 0;
3554 pSMB->hdr.smb_buf_length += byte_count;
3555 pSMB->ByteCount = cpu_to_le16(byte_count);
3556
3557 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3558 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3559 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003560 cFYI(1, "Send error in QPathInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 } else { /* decode response */
3562 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3563
3564 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003565 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response.\n"
Steve French1e71f252007-09-20 15:30:07 +00003566 "Unix Extensions can be disabled on mount "
Joe Perchesb6b38f72010-04-21 03:50:45 +00003567 "by specifying the nosfu mount option.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 rc = -EIO; /* bad smb */
3569 } else {
3570 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3571 memcpy((char *) pFindData,
3572 (char *) &pSMBr->hdr.Protocol +
3573 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003574 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 }
3576 }
3577 cifs_buf_release(pSMB);
3578 if (rc == -EAGAIN)
3579 goto UnixQPathInfoRetry;
3580
3581 return rc;
3582}
3583
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584/* xid, tcon, searchName and codepage are input parms, rest are returned */
3585int
3586CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003587 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003589 __u16 *pnetfid,
3590 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591{
3592/* level 257 SMB_ */
3593 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3594 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003595 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 int rc = 0;
3597 int bytes_returned = 0;
3598 int name_len;
3599 __u16 params, byte_count;
3600
Joe Perchesb6b38f72010-04-21 03:50:45 +00003601 cFYI(1, "In FindFirst for %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602
3603findFirstRetry:
3604 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3605 (void **) &pSMBr);
3606 if (rc)
3607 return rc;
3608
3609 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3610 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003611 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003612 PATH_MAX, nls_codepage, remap);
3613 /* We can not add the asterik earlier in case
3614 it got remapped to 0xF03A as if it were part of the
3615 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003617 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003618 pSMB->FileName[name_len+1] = 0;
3619 pSMB->FileName[name_len+2] = '*';
3620 pSMB->FileName[name_len+3] = 0;
3621 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3623 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003624 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003625 } else { /* BB add check for overrun of SMB buf BB */
3626 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003628 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003629 free buffer exit; BB */
3630 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003631 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003632 pSMB->FileName[name_len+1] = '*';
3633 pSMB->FileName[name_len+2] = 0;
3634 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635 }
3636
3637 params = 12 + name_len /* includes null */ ;
3638 pSMB->TotalDataCount = 0; /* no EAs */
3639 pSMB->MaxParameterCount = cpu_to_le16(10);
3640 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3641 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3642 pSMB->MaxSetupCount = 0;
3643 pSMB->Reserved = 0;
3644 pSMB->Flags = 0;
3645 pSMB->Timeout = 0;
3646 pSMB->Reserved2 = 0;
3647 byte_count = params + 1 /* pad */ ;
3648 pSMB->TotalParameterCount = cpu_to_le16(params);
3649 pSMB->ParameterCount = pSMB->TotalParameterCount;
3650 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003651 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3652 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 pSMB->DataCount = 0;
3654 pSMB->DataOffset = 0;
3655 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3656 pSMB->Reserved3 = 0;
3657 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3658 pSMB->SearchAttributes =
3659 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3660 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003661 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3662 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 CIFS_SEARCH_RETURN_RESUME);
3664 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3665
3666 /* BB what should we set StorageType to? Does it matter? BB */
3667 pSMB->SearchStorageType = 0;
3668 pSMB->hdr.smb_buf_length += byte_count;
3669 pSMB->ByteCount = cpu_to_le16(byte_count);
3670
3671 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3672 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003673 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674
Steve French88274812006-03-09 22:21:45 +00003675 if (rc) {/* BB add logic to retry regular search if Unix search
3676 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 /* BB Add code to handle unsupported level rc */
Joe Perchesb6b38f72010-04-21 03:50:45 +00003678 cFYI(1, "Error in FindFirst = %d", rc);
Steve French1982c342005-08-17 12:38:22 -07003679
Steve French88274812006-03-09 22:21:45 +00003680 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
3682 /* BB eventually could optimize out free and realloc of buf */
3683 /* for this case */
3684 if (rc == -EAGAIN)
3685 goto findFirstRetry;
3686 } else { /* decode response */
3687 /* BB remember to free buffer if error BB */
3688 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003689 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003690 unsigned int lnoff;
3691
Linus Torvalds1da177e2005-04-16 15:20:36 -07003692 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003693 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 else
Steve French4b18f2a2008-04-29 00:06:05 +00003695 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696
3697 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003698 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003699 psrch_inf->srch_entries_start =
3700 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003701 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3703 le16_to_cpu(pSMBr->t2.ParameterOffset));
3704
Steve French790fe572007-07-07 19:25:05 +00003705 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003706 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 else
Steve French4b18f2a2008-04-29 00:06:05 +00003708 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
Steve French50c2f752007-07-13 00:33:32 +00003710 psrch_inf->entries_in_buffer =
3711 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003712 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003714 lnoff = le16_to_cpu(parms->LastNameOffset);
3715 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3716 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003717 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003718 psrch_inf->last_entry = NULL;
3719 return rc;
3720 }
3721
Steve French0752f152008-10-07 20:03:33 +00003722 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003723 lnoff;
3724
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 *pnetfid = parms->SearchHandle;
3726 } else {
3727 cifs_buf_release(pSMB);
3728 }
3729 }
3730
3731 return rc;
3732}
3733
3734int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003735 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736{
3737 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3738 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003739 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 char *response_data;
3741 int rc = 0;
3742 int bytes_returned, name_len;
3743 __u16 params, byte_count;
3744
Joe Perchesb6b38f72010-04-21 03:50:45 +00003745 cFYI(1, "In FindNext");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
Steve French4b18f2a2008-04-29 00:06:05 +00003747 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 return -ENOENT;
3749
3750 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3751 (void **) &pSMBr);
3752 if (rc)
3753 return rc;
3754
Steve French50c2f752007-07-13 00:33:32 +00003755 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 byte_count = 0;
3757 pSMB->TotalDataCount = 0; /* no EAs */
3758 pSMB->MaxParameterCount = cpu_to_le16(8);
3759 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003760 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3761 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 pSMB->MaxSetupCount = 0;
3763 pSMB->Reserved = 0;
3764 pSMB->Flags = 0;
3765 pSMB->Timeout = 0;
3766 pSMB->Reserved2 = 0;
3767 pSMB->ParameterOffset = cpu_to_le16(
3768 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3769 pSMB->DataCount = 0;
3770 pSMB->DataOffset = 0;
3771 pSMB->SetupCount = 1;
3772 pSMB->Reserved3 = 0;
3773 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3774 pSMB->SearchHandle = searchHandle; /* always kept as le */
3775 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003776 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3778 pSMB->ResumeKey = psrch_inf->resume_key;
3779 pSMB->SearchFlags =
3780 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3781
3782 name_len = psrch_inf->resume_name_len;
3783 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003784 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3786 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003787 /* 14 byte parm len above enough for 2 byte null terminator */
3788 pSMB->ResumeFileName[name_len] = 0;
3789 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 } else {
3791 rc = -EINVAL;
3792 goto FNext2_err_exit;
3793 }
3794 byte_count = params + 1 /* pad */ ;
3795 pSMB->TotalParameterCount = cpu_to_le16(params);
3796 pSMB->ParameterCount = pSMB->TotalParameterCount;
3797 pSMB->hdr.smb_buf_length += byte_count;
3798 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003799
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3801 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003802 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003803 if (rc) {
3804 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003805 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003806 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003807 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003808 } else
Joe Perchesb6b38f72010-04-21 03:50:45 +00003809 cFYI(1, "FindNext returned = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810 } else { /* decode response */
3811 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003812
Steve French790fe572007-07-07 19:25:05 +00003813 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003814 unsigned int lnoff;
3815
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 /* BB fixme add lock for file (srch_info) struct here */
3817 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003818 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 else
Steve French4b18f2a2008-04-29 00:06:05 +00003820 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003821 response_data = (char *) &pSMBr->hdr.Protocol +
3822 le16_to_cpu(pSMBr->t2.ParameterOffset);
3823 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3824 response_data = (char *)&pSMBr->hdr.Protocol +
3825 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003826 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003827 cifs_small_buf_release(
3828 psrch_inf->ntwrk_buf_start);
3829 else
3830 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003831 psrch_inf->srch_entries_start = response_data;
3832 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003833 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003834 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003835 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 else
Steve French4b18f2a2008-04-29 00:06:05 +00003837 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003838 psrch_inf->entries_in_buffer =
3839 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 psrch_inf->index_of_last_entry +=
3841 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003842 lnoff = le16_to_cpu(parms->LastNameOffset);
3843 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3844 lnoff) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003845 cERROR(1, "ignoring corrupt resume name");
Steve Frenchb77d7532008-10-08 19:13:46 +00003846 psrch_inf->last_entry = NULL;
3847 return rc;
3848 } else
3849 psrch_inf->last_entry =
3850 psrch_inf->srch_entries_start + lnoff;
3851
Joe Perchesb6b38f72010-04-21 03:50:45 +00003852/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
3853 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854
3855 /* BB fixme add unlock here */
3856 }
3857
3858 }
3859
3860 /* BB On error, should we leave previous search buf (and count and
3861 last entry fields) intact or free the previous one? */
3862
3863 /* Note: On -EAGAIN error only caller can retry on handle based calls
3864 since file handle passed in no longer valid */
3865FNext2_err_exit:
3866 if (rc != 0)
3867 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868 return rc;
3869}
3870
3871int
Steve French50c2f752007-07-13 00:33:32 +00003872CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3873 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003874{
3875 int rc = 0;
3876 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877
Joe Perchesb6b38f72010-04-21 03:50:45 +00003878 cFYI(1, "In CIFSSMBFindClose");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3880
3881 /* no sense returning error if session restarted
3882 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003883 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 return 0;
3885 if (rc)
3886 return rc;
3887
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 pSMB->FileID = searchHandle;
3889 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003890 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003891 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00003892 cERROR(1, "Send error in FindClose = %d", rc);
Steve Frenchad7a2922008-02-07 23:25:02 +00003893
Steve Frencha4544342005-08-24 13:59:35 -07003894 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895
3896 /* Since session is dead, search handle closed on server already */
3897 if (rc == -EAGAIN)
3898 rc = 0;
3899
3900 return rc;
3901}
3902
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903int
3904CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003905 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003906 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003907 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908{
3909 int rc = 0;
3910 TRANSACTION2_QPI_REQ *pSMB = NULL;
3911 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3912 int name_len, bytes_returned;
3913 __u16 params, byte_count;
3914
Joe Perchesb6b38f72010-04-21 03:50:45 +00003915 cFYI(1, "In GetSrvInodeNum for %s", searchName);
Steve French790fe572007-07-07 19:25:05 +00003916 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003917 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918
3919GetInodeNumberRetry:
3920 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003921 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 if (rc)
3923 return rc;
3924
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3926 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003927 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003928 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 name_len++; /* trailing null */
3930 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003931 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 name_len = strnlen(searchName, PATH_MAX);
3933 name_len++; /* trailing null */
3934 strncpy(pSMB->FileName, searchName, name_len);
3935 }
3936
3937 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3938 pSMB->TotalDataCount = 0;
3939 pSMB->MaxParameterCount = cpu_to_le16(2);
3940 /* BB find exact max data count below from sess structure BB */
3941 pSMB->MaxDataCount = cpu_to_le16(4000);
3942 pSMB->MaxSetupCount = 0;
3943 pSMB->Reserved = 0;
3944 pSMB->Flags = 0;
3945 pSMB->Timeout = 0;
3946 pSMB->Reserved2 = 0;
3947 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003948 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 pSMB->DataCount = 0;
3950 pSMB->DataOffset = 0;
3951 pSMB->SetupCount = 1;
3952 pSMB->Reserved3 = 0;
3953 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3954 byte_count = params + 1 /* pad */ ;
3955 pSMB->TotalParameterCount = cpu_to_le16(params);
3956 pSMB->ParameterCount = pSMB->TotalParameterCount;
3957 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3958 pSMB->Reserved4 = 0;
3959 pSMB->hdr.smb_buf_length += byte_count;
3960 pSMB->ByteCount = cpu_to_le16(byte_count);
3961
3962 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3963 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3964 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003965 cFYI(1, "error %d in QueryInternalInfo", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 } else {
3967 /* decode response */
3968 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3969 if (rc || (pSMBr->ByteCount < 2))
3970 /* BB also check enough total bytes returned */
3971 /* If rc should we check for EOPNOSUPP and
3972 disable the srvino flag? or in caller? */
3973 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003974 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3976 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003977 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003979 if (count < 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00003980 cFYI(1, "Illegal size ret in QryIntrnlInf");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 rc = -EIO;
3982 goto GetInodeNumOut;
3983 }
3984 pfinfo = (struct file_internal_info *)
3985 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003986 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 }
3988 }
3989GetInodeNumOut:
3990 cifs_buf_release(pSMB);
3991 if (rc == -EAGAIN)
3992 goto GetInodeNumberRetry;
3993 return rc;
3994}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995
Igor Mammedovfec45852008-05-16 13:06:30 +04003996/* parses DFS refferal V3 structure
3997 * caller is responsible for freeing target_nodes
3998 * returns:
3999 * on success - 0
4000 * on failure - errno
4001 */
4002static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00004003parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04004004 unsigned int *num_of_nodes,
4005 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004006 const struct nls_table *nls_codepage, int remap,
4007 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04004008{
4009 int i, rc = 0;
4010 char *data_end;
4011 bool is_unicode;
4012 struct dfs_referral_level_3 *ref;
4013
Harvey Harrison5ca33c62008-07-23 17:45:58 -07004014 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4015 is_unicode = true;
4016 else
4017 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04004018 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4019
4020 if (*num_of_nodes < 1) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004021 cERROR(1, "num_referrals: must be at least > 0,"
4022 "but we get num_referrals = %d\n", *num_of_nodes);
Igor Mammedovfec45852008-05-16 13:06:30 +04004023 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004024 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004025 }
4026
4027 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01004028 if (ref->VersionNumber != cpu_to_le16(3)) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004029 cERROR(1, "Referrals of V%d version are not supported,"
4030 "should be V3", le16_to_cpu(ref->VersionNumber));
Igor Mammedovfec45852008-05-16 13:06:30 +04004031 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004032 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004033 }
4034
4035 /* get the upper boundary of the resp buffer */
4036 data_end = (char *)(&(pSMBr->PathConsumed)) +
4037 le16_to_cpu(pSMBr->t2.DataCount);
4038
Steve Frenchf19159d2010-04-21 04:12:10 +00004039 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
Igor Mammedovfec45852008-05-16 13:06:30 +04004040 *num_of_nodes,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004041 le32_to_cpu(pSMBr->DFSFlags));
Igor Mammedovfec45852008-05-16 13:06:30 +04004042
4043 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4044 *num_of_nodes, GFP_KERNEL);
4045 if (*target_nodes == NULL) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004046 cERROR(1, "Failed to allocate buffer for target_nodes\n");
Igor Mammedovfec45852008-05-16 13:06:30 +04004047 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004048 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04004049 }
4050
Daniel Mack3ad2f3f2010-02-03 08:01:28 +08004051 /* collect necessary data from referrals */
Igor Mammedovfec45852008-05-16 13:06:30 +04004052 for (i = 0; i < *num_of_nodes; i++) {
4053 char *temp;
4054 int max_len;
4055 struct dfs_info3_param *node = (*target_nodes)+i;
4056
Steve French0e0d2cf2009-05-01 05:27:32 +00004057 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04004058 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05004059 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4060 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00004061 if (tmp == NULL) {
4062 rc = -ENOMEM;
4063 goto parse_DFS_referrals_exit;
4064 }
Igor Mammedov2c556082008-10-23 13:58:42 +04004065 cifsConvertToUCS((__le16 *) tmp, searchName,
4066 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04004067 node->path_consumed = cifs_ucs2_bytes(tmp,
4068 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04004069 nls_codepage);
4070 kfree(tmp);
4071 } else
4072 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4073
Igor Mammedovfec45852008-05-16 13:06:30 +04004074 node->server_type = le16_to_cpu(ref->ServerType);
4075 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4076
4077 /* copy DfsPath */
4078 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4079 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004080 node->path_name = cifs_strndup_from_ucs(temp, max_len,
4081 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004082 if (!node->path_name) {
4083 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00004084 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04004085 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004086
4087 /* copy link target UNC */
4088 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4089 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00004090 node->node_name = cifs_strndup_from_ucs(temp, max_len,
4091 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04004092 if (!node->node_name)
4093 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04004094 }
4095
Steve Frencha1fe78f2008-05-16 18:48:38 +00004096parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04004097 if (rc) {
4098 free_dfs_info_array(*target_nodes, *num_of_nodes);
4099 *target_nodes = NULL;
4100 *num_of_nodes = 0;
4101 }
4102 return rc;
4103}
4104
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105int
4106CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
4107 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004108 struct dfs_info3_param **target_nodes,
4109 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07004110 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111{
4112/* TRANS2_GET_DFS_REFERRAL */
4113 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4114 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 int rc = 0;
4116 int bytes_returned;
4117 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004119 *num_of_nodes = 0;
4120 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
Joe Perchesb6b38f72010-04-21 03:50:45 +00004122 cFYI(1, "In GetDFSRefer the path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004123 if (ses == NULL)
4124 return -ENODEV;
4125getDFSRetry:
4126 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4127 (void **) &pSMBr);
4128 if (rc)
4129 return rc;
Steve French50c2f752007-07-13 00:33:32 +00004130
4131 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07004132 but should never be null here anyway */
4133 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134 pSMB->hdr.Tid = ses->ipc_tid;
4135 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00004136 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00004138 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
4141 if (ses->capabilities & CAP_UNICODE) {
4142 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4143 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004144 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07004145 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146 name_len++; /* trailing null */
4147 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004148 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 name_len = strnlen(searchName, PATH_MAX);
4150 name_len++; /* trailing null */
4151 strncpy(pSMB->RequestFileName, searchName, name_len);
4152 }
4153
Steve French790fe572007-07-07 19:25:05 +00004154 if (ses->server) {
4155 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00004156 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4157 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4158 }
4159
Steve French50c2f752007-07-13 00:33:32 +00004160 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004161
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 params = 2 /* level */ + name_len /*includes null */ ;
4163 pSMB->TotalDataCount = 0;
4164 pSMB->DataCount = 0;
4165 pSMB->DataOffset = 0;
4166 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004167 /* BB find exact max SMB PDU from sess structure BB */
4168 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 pSMB->MaxSetupCount = 0;
4170 pSMB->Reserved = 0;
4171 pSMB->Flags = 0;
4172 pSMB->Timeout = 0;
4173 pSMB->Reserved2 = 0;
4174 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004175 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 pSMB->SetupCount = 1;
4177 pSMB->Reserved3 = 0;
4178 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4179 byte_count = params + 3 /* pad */ ;
4180 pSMB->ParameterCount = cpu_to_le16(params);
4181 pSMB->TotalParameterCount = pSMB->ParameterCount;
4182 pSMB->MaxReferralLevel = cpu_to_le16(3);
4183 pSMB->hdr.smb_buf_length += byte_count;
4184 pSMB->ByteCount = cpu_to_le16(byte_count);
4185
4186 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4187 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4188 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004189 cFYI(1, "Send error in GetDFSRefer = %d", rc);
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004190 goto GetDFSRefExit;
4191 }
4192 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004194 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004195 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004196 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004197 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004198 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004199
Joe Perchesb6b38f72010-04-21 03:50:45 +00004200 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
Igor Mammedovfec45852008-05-16 13:06:30 +04004201 pSMBr->ByteCount,
Joe Perchesb6b38f72010-04-21 03:50:45 +00004202 le16_to_cpu(pSMBr->t2.DataOffset));
Igor Mammedovfec45852008-05-16 13:06:30 +04004203
4204 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004205 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004206 target_nodes, nls_codepage, remap,
4207 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004208
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004210 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211
4212 if (rc == -EAGAIN)
4213 goto getDFSRetry;
4214
4215 return rc;
4216}
4217
Steve French20962432005-09-21 22:05:57 -07004218/* Query File System Info such as free space to old servers such as Win 9x */
4219int
4220SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4221{
4222/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4223 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4224 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4225 FILE_SYSTEM_ALLOC_INFO *response_data;
4226 int rc = 0;
4227 int bytes_returned = 0;
4228 __u16 params, byte_count;
4229
Joe Perchesb6b38f72010-04-21 03:50:45 +00004230 cFYI(1, "OldQFSInfo");
Steve French20962432005-09-21 22:05:57 -07004231oldQFSInfoRetry:
4232 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4233 (void **) &pSMBr);
4234 if (rc)
4235 return rc;
Steve French20962432005-09-21 22:05:57 -07004236
4237 params = 2; /* level */
4238 pSMB->TotalDataCount = 0;
4239 pSMB->MaxParameterCount = cpu_to_le16(2);
4240 pSMB->MaxDataCount = cpu_to_le16(1000);
4241 pSMB->MaxSetupCount = 0;
4242 pSMB->Reserved = 0;
4243 pSMB->Flags = 0;
4244 pSMB->Timeout = 0;
4245 pSMB->Reserved2 = 0;
4246 byte_count = params + 1 /* pad */ ;
4247 pSMB->TotalParameterCount = cpu_to_le16(params);
4248 pSMB->ParameterCount = pSMB->TotalParameterCount;
4249 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4250 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4251 pSMB->DataCount = 0;
4252 pSMB->DataOffset = 0;
4253 pSMB->SetupCount = 1;
4254 pSMB->Reserved3 = 0;
4255 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4256 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4257 pSMB->hdr.smb_buf_length += byte_count;
4258 pSMB->ByteCount = cpu_to_le16(byte_count);
4259
4260 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4261 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4262 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004263 cFYI(1, "Send error in QFSInfo = %d", rc);
Steve French20962432005-09-21 22:05:57 -07004264 } else { /* decode response */
4265 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4266
4267 if (rc || (pSMBr->ByteCount < 18))
4268 rc = -EIO; /* bad smb */
4269 else {
4270 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004271 cFYI(1, "qfsinf resp BCC: %d Offset %d",
4272 pSMBr->ByteCount, data_offset);
Steve French20962432005-09-21 22:05:57 -07004273
Steve French50c2f752007-07-13 00:33:32 +00004274 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004275 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4276 FSData->f_bsize =
4277 le16_to_cpu(response_data->BytesPerSector) *
4278 le32_to_cpu(response_data->
4279 SectorsPerAllocationUnit);
4280 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004281 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004282 FSData->f_bfree = FSData->f_bavail =
4283 le32_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004284 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4285 (unsigned long long)FSData->f_blocks,
4286 (unsigned long long)FSData->f_bfree,
4287 FSData->f_bsize);
Steve French20962432005-09-21 22:05:57 -07004288 }
4289 }
4290 cifs_buf_release(pSMB);
4291
4292 if (rc == -EAGAIN)
4293 goto oldQFSInfoRetry;
4294
4295 return rc;
4296}
4297
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298int
Steve French737b7582005-04-28 22:41:06 -07004299CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300{
4301/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4302 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4303 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4304 FILE_SYSTEM_INFO *response_data;
4305 int rc = 0;
4306 int bytes_returned = 0;
4307 __u16 params, byte_count;
4308
Joe Perchesb6b38f72010-04-21 03:50:45 +00004309 cFYI(1, "In QFSInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310QFSInfoRetry:
4311 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4312 (void **) &pSMBr);
4313 if (rc)
4314 return rc;
4315
4316 params = 2; /* level */
4317 pSMB->TotalDataCount = 0;
4318 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004319 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 pSMB->MaxSetupCount = 0;
4321 pSMB->Reserved = 0;
4322 pSMB->Flags = 0;
4323 pSMB->Timeout = 0;
4324 pSMB->Reserved2 = 0;
4325 byte_count = params + 1 /* pad */ ;
4326 pSMB->TotalParameterCount = cpu_to_le16(params);
4327 pSMB->ParameterCount = pSMB->TotalParameterCount;
4328 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004329 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 pSMB->DataCount = 0;
4331 pSMB->DataOffset = 0;
4332 pSMB->SetupCount = 1;
4333 pSMB->Reserved3 = 0;
4334 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4335 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4336 pSMB->hdr.smb_buf_length += byte_count;
4337 pSMB->ByteCount = cpu_to_le16(byte_count);
4338
4339 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4340 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4341 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004342 cFYI(1, "Send error in QFSInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004344 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345
Steve French20962432005-09-21 22:05:57 -07004346 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347 rc = -EIO; /* bad smb */
4348 else {
4349 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350
4351 response_data =
4352 (FILE_SYSTEM_INFO
4353 *) (((char *) &pSMBr->hdr.Protocol) +
4354 data_offset);
4355 FSData->f_bsize =
4356 le32_to_cpu(response_data->BytesPerSector) *
4357 le32_to_cpu(response_data->
4358 SectorsPerAllocationUnit);
4359 FSData->f_blocks =
4360 le64_to_cpu(response_data->TotalAllocationUnits);
4361 FSData->f_bfree = FSData->f_bavail =
4362 le64_to_cpu(response_data->FreeAllocationUnits);
Joe Perchesb6b38f72010-04-21 03:50:45 +00004363 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4364 (unsigned long long)FSData->f_blocks,
4365 (unsigned long long)FSData->f_bfree,
4366 FSData->f_bsize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 }
4368 }
4369 cifs_buf_release(pSMB);
4370
4371 if (rc == -EAGAIN)
4372 goto QFSInfoRetry;
4373
4374 return rc;
4375}
4376
4377int
Steve French737b7582005-04-28 22:41:06 -07004378CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379{
4380/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4381 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4382 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4383 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4384 int rc = 0;
4385 int bytes_returned = 0;
4386 __u16 params, byte_count;
4387
Joe Perchesb6b38f72010-04-21 03:50:45 +00004388 cFYI(1, "In QFSAttributeInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389QFSAttributeRetry:
4390 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4391 (void **) &pSMBr);
4392 if (rc)
4393 return rc;
4394
4395 params = 2; /* level */
4396 pSMB->TotalDataCount = 0;
4397 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004398 /* BB find exact max SMB PDU from sess structure BB */
4399 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 pSMB->MaxSetupCount = 0;
4401 pSMB->Reserved = 0;
4402 pSMB->Flags = 0;
4403 pSMB->Timeout = 0;
4404 pSMB->Reserved2 = 0;
4405 byte_count = params + 1 /* pad */ ;
4406 pSMB->TotalParameterCount = cpu_to_le16(params);
4407 pSMB->ParameterCount = pSMB->TotalParameterCount;
4408 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004409 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 pSMB->DataCount = 0;
4411 pSMB->DataOffset = 0;
4412 pSMB->SetupCount = 1;
4413 pSMB->Reserved3 = 0;
4414 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4415 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4416 pSMB->hdr.smb_buf_length += byte_count;
4417 pSMB->ByteCount = cpu_to_le16(byte_count);
4418
4419 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4420 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4421 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004422 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 } else { /* decode response */
4424 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4425
Steve French50c2f752007-07-13 00:33:32 +00004426 if (rc || (pSMBr->ByteCount < 13)) {
4427 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 rc = -EIO; /* bad smb */
4429 } else {
4430 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4431 response_data =
4432 (FILE_SYSTEM_ATTRIBUTE_INFO
4433 *) (((char *) &pSMBr->hdr.Protocol) +
4434 data_offset);
4435 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004436 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 }
4438 }
4439 cifs_buf_release(pSMB);
4440
4441 if (rc == -EAGAIN)
4442 goto QFSAttributeRetry;
4443
4444 return rc;
4445}
4446
4447int
Steve French737b7582005-04-28 22:41:06 -07004448CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449{
4450/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4451 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4452 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4453 FILE_SYSTEM_DEVICE_INFO *response_data;
4454 int rc = 0;
4455 int bytes_returned = 0;
4456 __u16 params, byte_count;
4457
Joe Perchesb6b38f72010-04-21 03:50:45 +00004458 cFYI(1, "In QFSDeviceInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459QFSDeviceRetry:
4460 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4461 (void **) &pSMBr);
4462 if (rc)
4463 return rc;
4464
4465 params = 2; /* level */
4466 pSMB->TotalDataCount = 0;
4467 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004468 /* BB find exact max SMB PDU from sess structure BB */
4469 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 pSMB->MaxSetupCount = 0;
4471 pSMB->Reserved = 0;
4472 pSMB->Flags = 0;
4473 pSMB->Timeout = 0;
4474 pSMB->Reserved2 = 0;
4475 byte_count = params + 1 /* pad */ ;
4476 pSMB->TotalParameterCount = cpu_to_le16(params);
4477 pSMB->ParameterCount = pSMB->TotalParameterCount;
4478 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004479 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480
4481 pSMB->DataCount = 0;
4482 pSMB->DataOffset = 0;
4483 pSMB->SetupCount = 1;
4484 pSMB->Reserved3 = 0;
4485 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4486 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4487 pSMB->hdr.smb_buf_length += byte_count;
4488 pSMB->ByteCount = cpu_to_le16(byte_count);
4489
4490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4492 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004493 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 } else { /* decode response */
4495 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4496
Steve French630f3f0c2007-10-25 21:17:17 +00004497 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 rc = -EIO; /* bad smb */
4499 else {
4500 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4501 response_data =
Steve French737b7582005-04-28 22:41:06 -07004502 (FILE_SYSTEM_DEVICE_INFO *)
4503 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 data_offset);
4505 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004506 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 }
4508 }
4509 cifs_buf_release(pSMB);
4510
4511 if (rc == -EAGAIN)
4512 goto QFSDeviceRetry;
4513
4514 return rc;
4515}
4516
4517int
Steve French737b7582005-04-28 22:41:06 -07004518CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519{
4520/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4521 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4522 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4523 FILE_SYSTEM_UNIX_INFO *response_data;
4524 int rc = 0;
4525 int bytes_returned = 0;
4526 __u16 params, byte_count;
4527
Joe Perchesb6b38f72010-04-21 03:50:45 +00004528 cFYI(1, "In QFSUnixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529QFSUnixRetry:
4530 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4531 (void **) &pSMBr);
4532 if (rc)
4533 return rc;
4534
4535 params = 2; /* level */
4536 pSMB->TotalDataCount = 0;
4537 pSMB->DataCount = 0;
4538 pSMB->DataOffset = 0;
4539 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004540 /* BB find exact max SMB PDU from sess structure BB */
4541 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004542 pSMB->MaxSetupCount = 0;
4543 pSMB->Reserved = 0;
4544 pSMB->Flags = 0;
4545 pSMB->Timeout = 0;
4546 pSMB->Reserved2 = 0;
4547 byte_count = params + 1 /* pad */ ;
4548 pSMB->ParameterCount = cpu_to_le16(params);
4549 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004550 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4551 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552 pSMB->SetupCount = 1;
4553 pSMB->Reserved3 = 0;
4554 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4555 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4556 pSMB->hdr.smb_buf_length += byte_count;
4557 pSMB->ByteCount = cpu_to_le16(byte_count);
4558
4559 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4560 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4561 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004562 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 } else { /* decode response */
4564 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4565
4566 if (rc || (pSMBr->ByteCount < 13)) {
4567 rc = -EIO; /* bad smb */
4568 } else {
4569 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4570 response_data =
4571 (FILE_SYSTEM_UNIX_INFO
4572 *) (((char *) &pSMBr->hdr.Protocol) +
4573 data_offset);
4574 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004575 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 }
4577 }
4578 cifs_buf_release(pSMB);
4579
4580 if (rc == -EAGAIN)
4581 goto QFSUnixRetry;
4582
4583
4584 return rc;
4585}
4586
Jeremy Allisonac670552005-06-22 17:26:35 -07004587int
Steve French45abc6e2005-06-23 13:42:03 -05004588CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004589{
4590/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4591 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4592 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4593 int rc = 0;
4594 int bytes_returned = 0;
4595 __u16 params, param_offset, offset, byte_count;
4596
Joe Perchesb6b38f72010-04-21 03:50:45 +00004597 cFYI(1, "In SETFSUnixInfo");
Jeremy Allisonac670552005-06-22 17:26:35 -07004598SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004599 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004600 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4601 (void **) &pSMBr);
4602 if (rc)
4603 return rc;
4604
4605 params = 4; /* 2 bytes zero followed by info level. */
4606 pSMB->MaxSetupCount = 0;
4607 pSMB->Reserved = 0;
4608 pSMB->Flags = 0;
4609 pSMB->Timeout = 0;
4610 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004611 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4612 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004613 offset = param_offset + params;
4614
4615 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004616 /* BB find exact max SMB PDU from sess structure BB */
4617 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004618 pSMB->SetupCount = 1;
4619 pSMB->Reserved3 = 0;
4620 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4621 byte_count = 1 /* pad */ + params + 12;
4622
4623 pSMB->DataCount = cpu_to_le16(12);
4624 pSMB->ParameterCount = cpu_to_le16(params);
4625 pSMB->TotalDataCount = pSMB->DataCount;
4626 pSMB->TotalParameterCount = pSMB->ParameterCount;
4627 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4628 pSMB->DataOffset = cpu_to_le16(offset);
4629
4630 /* Params. */
4631 pSMB->FileNum = 0;
4632 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4633
4634 /* Data. */
4635 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4636 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4637 pSMB->ClientUnixCap = cpu_to_le64(cap);
4638
4639 pSMB->hdr.smb_buf_length += byte_count;
4640 pSMB->ByteCount = cpu_to_le16(byte_count);
4641
4642 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4643 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4644 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004645 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
Jeremy Allisonac670552005-06-22 17:26:35 -07004646 } else { /* decode response */
4647 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004648 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004649 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004650 }
4651 cifs_buf_release(pSMB);
4652
4653 if (rc == -EAGAIN)
4654 goto SETFSUnixRetry;
4655
4656 return rc;
4657}
4658
4659
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
4661int
4662CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004663 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664{
4665/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4666 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4667 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4668 FILE_SYSTEM_POSIX_INFO *response_data;
4669 int rc = 0;
4670 int bytes_returned = 0;
4671 __u16 params, byte_count;
4672
Joe Perchesb6b38f72010-04-21 03:50:45 +00004673 cFYI(1, "In QFSPosixInfo");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674QFSPosixRetry:
4675 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4676 (void **) &pSMBr);
4677 if (rc)
4678 return rc;
4679
4680 params = 2; /* level */
4681 pSMB->TotalDataCount = 0;
4682 pSMB->DataCount = 0;
4683 pSMB->DataOffset = 0;
4684 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004685 /* BB find exact max SMB PDU from sess structure BB */
4686 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 pSMB->MaxSetupCount = 0;
4688 pSMB->Reserved = 0;
4689 pSMB->Flags = 0;
4690 pSMB->Timeout = 0;
4691 pSMB->Reserved2 = 0;
4692 byte_count = params + 1 /* pad */ ;
4693 pSMB->ParameterCount = cpu_to_le16(params);
4694 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004695 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4696 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 pSMB->SetupCount = 1;
4698 pSMB->Reserved3 = 0;
4699 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4700 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4701 pSMB->hdr.smb_buf_length += byte_count;
4702 pSMB->ByteCount = cpu_to_le16(byte_count);
4703
4704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4706 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004707 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708 } else { /* decode response */
4709 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4710
4711 if (rc || (pSMBr->ByteCount < 13)) {
4712 rc = -EIO; /* bad smb */
4713 } else {
4714 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4715 response_data =
4716 (FILE_SYSTEM_POSIX_INFO
4717 *) (((char *) &pSMBr->hdr.Protocol) +
4718 data_offset);
4719 FSData->f_bsize =
4720 le32_to_cpu(response_data->BlockSize);
4721 FSData->f_blocks =
4722 le64_to_cpu(response_data->TotalBlocks);
4723 FSData->f_bfree =
4724 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004725 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 FSData->f_bavail = FSData->f_bfree;
4727 } else {
4728 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004729 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730 }
Steve French790fe572007-07-07 19:25:05 +00004731 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004733 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004734 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004736 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 }
4738 }
4739 cifs_buf_release(pSMB);
4740
4741 if (rc == -EAGAIN)
4742 goto QFSPosixRetry;
4743
4744 return rc;
4745}
4746
4747
Steve French50c2f752007-07-13 00:33:32 +00004748/* We can not use write of zero bytes trick to
4749 set file size due to need for large file support. Also note that
4750 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 routine which is only needed to work around a sharing violation bug
4752 in Samba which this routine can run into */
4753
4754int
4755CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004756 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004757 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758{
4759 struct smb_com_transaction2_spi_req *pSMB = NULL;
4760 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4761 struct file_end_of_file_info *parm_data;
4762 int name_len;
4763 int rc = 0;
4764 int bytes_returned = 0;
4765 __u16 params, byte_count, data_count, param_offset, offset;
4766
Joe Perchesb6b38f72010-04-21 03:50:45 +00004767 cFYI(1, "In SetEOF");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768SetEOFRetry:
4769 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4770 (void **) &pSMBr);
4771 if (rc)
4772 return rc;
4773
4774 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4775 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004776 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004777 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778 name_len++; /* trailing null */
4779 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004780 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 name_len = strnlen(fileName, PATH_MAX);
4782 name_len++; /* trailing null */
4783 strncpy(pSMB->FileName, fileName, name_len);
4784 }
4785 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004786 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004788 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 pSMB->MaxSetupCount = 0;
4790 pSMB->Reserved = 0;
4791 pSMB->Flags = 0;
4792 pSMB->Timeout = 0;
4793 pSMB->Reserved2 = 0;
4794 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004795 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004797 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004798 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4799 pSMB->InformationLevel =
4800 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4801 else
4802 pSMB->InformationLevel =
4803 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4804 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4806 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004807 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 else
4809 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004810 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 }
4812
4813 parm_data =
4814 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4815 offset);
4816 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4817 pSMB->DataOffset = cpu_to_le16(offset);
4818 pSMB->SetupCount = 1;
4819 pSMB->Reserved3 = 0;
4820 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4821 byte_count = 3 /* pad */ + params + data_count;
4822 pSMB->DataCount = cpu_to_le16(data_count);
4823 pSMB->TotalDataCount = pSMB->DataCount;
4824 pSMB->ParameterCount = cpu_to_le16(params);
4825 pSMB->TotalParameterCount = pSMB->ParameterCount;
4826 pSMB->Reserved4 = 0;
4827 pSMB->hdr.smb_buf_length += byte_count;
4828 parm_data->FileSize = cpu_to_le64(size);
4829 pSMB->ByteCount = cpu_to_le16(byte_count);
4830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004832 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004833 cFYI(1, "SetPathInfo (file size) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834
4835 cifs_buf_release(pSMB);
4836
4837 if (rc == -EAGAIN)
4838 goto SetEOFRetry;
4839
4840 return rc;
4841}
4842
4843int
Steve French50c2f752007-07-13 00:33:32 +00004844CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004845 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846{
4847 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848 char *data_offset;
4849 struct file_end_of_file_info *parm_data;
4850 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851 __u16 params, param_offset, offset, byte_count, count;
4852
Joe Perchesb6b38f72010-04-21 03:50:45 +00004853 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
4854 (long long)size);
Steve Frenchcd634992005-04-28 22:41:10 -07004855 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4856
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 if (rc)
4858 return rc;
4859
4860 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4861 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004862
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 params = 6;
4864 pSMB->MaxSetupCount = 0;
4865 pSMB->Reserved = 0;
4866 pSMB->Flags = 0;
4867 pSMB->Timeout = 0;
4868 pSMB->Reserved2 = 0;
4869 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4870 offset = param_offset + params;
4871
Steve French50c2f752007-07-13 00:33:32 +00004872 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873
4874 count = sizeof(struct file_end_of_file_info);
4875 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004876 /* BB find exact max SMB PDU from sess structure BB */
4877 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 pSMB->SetupCount = 1;
4879 pSMB->Reserved3 = 0;
4880 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4881 byte_count = 3 /* pad */ + params + count;
4882 pSMB->DataCount = cpu_to_le16(count);
4883 pSMB->ParameterCount = cpu_to_le16(params);
4884 pSMB->TotalDataCount = pSMB->DataCount;
4885 pSMB->TotalParameterCount = pSMB->ParameterCount;
4886 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4887 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004888 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4889 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 pSMB->DataOffset = cpu_to_le16(offset);
4891 parm_data->FileSize = cpu_to_le64(size);
4892 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004893 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004894 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4895 pSMB->InformationLevel =
4896 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4897 else
4898 pSMB->InformationLevel =
4899 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004900 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4902 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004903 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 else
4905 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004906 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 }
4908 pSMB->Reserved4 = 0;
4909 pSMB->hdr.smb_buf_length += byte_count;
4910 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004911 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00004913 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004914 }
4915
Steve French50c2f752007-07-13 00:33:32 +00004916 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 since file handle passed in no longer valid */
4918
4919 return rc;
4920}
4921
Steve French50c2f752007-07-13 00:33:32 +00004922/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004923 an open handle, rather than by pathname - this is awkward due to
4924 potential access conflicts on the open, but it is unavoidable for these
4925 old servers since the only other choice is to go from 100 nanosecond DCE
4926 time and resort to the original setpathinfo level which takes the ancient
4927 DOS time format with 2 second granularity */
4928int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004929CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4930 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931{
4932 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004933 char *data_offset;
4934 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935 __u16 params, param_offset, offset, byte_count, count;
4936
Joe Perchesb6b38f72010-04-21 03:50:45 +00004937 cFYI(1, "Set Times (via SetFileInfo)");
Steve Frenchcd634992005-04-28 22:41:10 -07004938 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4939
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 if (rc)
4941 return rc;
4942
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004943 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4944 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004945
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 params = 6;
4947 pSMB->MaxSetupCount = 0;
4948 pSMB->Reserved = 0;
4949 pSMB->Flags = 0;
4950 pSMB->Timeout = 0;
4951 pSMB->Reserved2 = 0;
4952 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4953 offset = param_offset + params;
4954
Steve French50c2f752007-07-13 00:33:32 +00004955 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956
Steve French26f57362007-08-30 22:09:15 +00004957 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004958 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004959 /* BB find max SMB PDU from sess */
4960 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004961 pSMB->SetupCount = 1;
4962 pSMB->Reserved3 = 0;
4963 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4964 byte_count = 3 /* pad */ + params + count;
4965 pSMB->DataCount = cpu_to_le16(count);
4966 pSMB->ParameterCount = cpu_to_le16(params);
4967 pSMB->TotalDataCount = pSMB->DataCount;
4968 pSMB->TotalParameterCount = pSMB->ParameterCount;
4969 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4970 pSMB->DataOffset = cpu_to_le16(offset);
4971 pSMB->Fid = fid;
4972 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4973 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4974 else
4975 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4976 pSMB->Reserved4 = 0;
4977 pSMB->hdr.smb_buf_length += byte_count;
4978 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004979 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004980 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004981 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00004982 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983
Steve French50c2f752007-07-13 00:33:32 +00004984 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 since file handle passed in no longer valid */
4986
4987 return rc;
4988}
4989
Jeff Layton6d22f092008-09-23 11:48:35 -04004990int
4991CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4992 bool delete_file, __u16 fid, __u32 pid_of_opener)
4993{
4994 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4995 char *data_offset;
4996 int rc = 0;
4997 __u16 params, param_offset, offset, byte_count, count;
4998
Joe Perchesb6b38f72010-04-21 03:50:45 +00004999 cFYI(1, "Set File Disposition (via SetFileInfo)");
Jeff Layton6d22f092008-09-23 11:48:35 -04005000 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5001
5002 if (rc)
5003 return rc;
5004
5005 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5006 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5007
5008 params = 6;
5009 pSMB->MaxSetupCount = 0;
5010 pSMB->Reserved = 0;
5011 pSMB->Flags = 0;
5012 pSMB->Timeout = 0;
5013 pSMB->Reserved2 = 0;
5014 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5015 offset = param_offset + params;
5016
5017 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5018
5019 count = 1;
5020 pSMB->MaxParameterCount = cpu_to_le16(2);
5021 /* BB find max SMB PDU from sess */
5022 pSMB->MaxDataCount = cpu_to_le16(1000);
5023 pSMB->SetupCount = 1;
5024 pSMB->Reserved3 = 0;
5025 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5026 byte_count = 3 /* pad */ + params + count;
5027 pSMB->DataCount = cpu_to_le16(count);
5028 pSMB->ParameterCount = cpu_to_le16(params);
5029 pSMB->TotalDataCount = pSMB->DataCount;
5030 pSMB->TotalParameterCount = pSMB->ParameterCount;
5031 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5032 pSMB->DataOffset = cpu_to_le16(offset);
5033 pSMB->Fid = fid;
5034 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5035 pSMB->Reserved4 = 0;
5036 pSMB->hdr.smb_buf_length += byte_count;
5037 pSMB->ByteCount = cpu_to_le16(byte_count);
5038 *data_offset = delete_file ? 1 : 0;
5039 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5040 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005041 cFYI(1, "Send error in SetFileDisposition = %d", rc);
Jeff Layton6d22f092008-09-23 11:48:35 -04005042
5043 return rc;
5044}
Linus Torvalds1da177e2005-04-16 15:20:36 -07005045
5046int
Jeff Layton6fc000e2008-08-02 07:26:12 -04005047CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
5048 const char *fileName, const FILE_BASIC_INFO *data,
5049 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050{
5051 TRANSACTION2_SPI_REQ *pSMB = NULL;
5052 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5053 int name_len;
5054 int rc = 0;
5055 int bytes_returned = 0;
5056 char *data_offset;
5057 __u16 params, param_offset, offset, byte_count, count;
5058
Joe Perchesb6b38f72010-04-21 03:50:45 +00005059 cFYI(1, "In SetTimes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060
5061SetTimesRetry:
5062 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5063 (void **) &pSMBr);
5064 if (rc)
5065 return rc;
5066
5067 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5068 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005069 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005070 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 name_len++; /* trailing null */
5072 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005073 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005074 name_len = strnlen(fileName, PATH_MAX);
5075 name_len++; /* trailing null */
5076 strncpy(pSMB->FileName, fileName, name_len);
5077 }
5078
5079 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005080 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005081 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005082 /* BB find max SMB PDU from sess structure BB */
5083 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 pSMB->MaxSetupCount = 0;
5085 pSMB->Reserved = 0;
5086 pSMB->Flags = 0;
5087 pSMB->Timeout = 0;
5088 pSMB->Reserved2 = 0;
5089 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005090 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 offset = param_offset + params;
5092 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5093 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5094 pSMB->DataOffset = cpu_to_le16(offset);
5095 pSMB->SetupCount = 1;
5096 pSMB->Reserved3 = 0;
5097 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5098 byte_count = 3 /* pad */ + params + count;
5099
5100 pSMB->DataCount = cpu_to_le16(count);
5101 pSMB->ParameterCount = cpu_to_le16(params);
5102 pSMB->TotalDataCount = pSMB->DataCount;
5103 pSMB->TotalParameterCount = pSMB->ParameterCount;
5104 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5105 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5106 else
5107 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5108 pSMB->Reserved4 = 0;
5109 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00005110 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 pSMB->ByteCount = cpu_to_le16(byte_count);
5112 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5113 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005114 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005115 cFYI(1, "SetPathInfo (times) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005116
5117 cifs_buf_release(pSMB);
5118
5119 if (rc == -EAGAIN)
5120 goto SetTimesRetry;
5121
5122 return rc;
5123}
5124
5125/* Can not be used to set time stamps yet (due to old DOS time format) */
5126/* Can be used to set attributes */
5127#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5128 handling it anyway and NT4 was what we thought it would be needed for
5129 Do not delete it until we prove whether needed for Win9x though */
5130int
5131CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
5132 __u16 dos_attrs, const struct nls_table *nls_codepage)
5133{
5134 SETATTR_REQ *pSMB = NULL;
5135 SETATTR_RSP *pSMBr = NULL;
5136 int rc = 0;
5137 int bytes_returned;
5138 int name_len;
5139
Joe Perchesb6b38f72010-04-21 03:50:45 +00005140 cFYI(1, "In SetAttrLegacy");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005141
5142SetAttrLgcyRetry:
5143 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5144 (void **) &pSMBr);
5145 if (rc)
5146 return rc;
5147
5148 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5149 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005150 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005151 PATH_MAX, nls_codepage);
5152 name_len++; /* trailing null */
5153 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005154 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 name_len = strnlen(fileName, PATH_MAX);
5156 name_len++; /* trailing null */
5157 strncpy(pSMB->fileName, fileName, name_len);
5158 }
5159 pSMB->attr = cpu_to_le16(dos_attrs);
5160 pSMB->BufferFormat = 0x04;
5161 pSMB->hdr.smb_buf_length += name_len + 1;
5162 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5163 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5164 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005165 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005166 cFYI(1, "Error in LegacySetAttr = %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005167
5168 cifs_buf_release(pSMB);
5169
5170 if (rc == -EAGAIN)
5171 goto SetAttrLgcyRetry;
5172
5173 return rc;
5174}
5175#endif /* temporarily unneeded SetAttr legacy function */
5176
Jeff Layton654cf142009-07-09 20:02:49 -04005177static void
5178cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5179 const struct cifs_unix_set_info_args *args)
5180{
5181 u64 mode = args->mode;
5182
5183 /*
5184 * Samba server ignores set of file size to zero due to bugs in some
5185 * older clients, but we should be precise - we use SetFileSize to
5186 * set file size and do not want to truncate file size to zero
5187 * accidently as happened on one Samba server beta by putting
5188 * zero instead of -1 here
5189 */
5190 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5191 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5192 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5193 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5194 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5195 data_offset->Uid = cpu_to_le64(args->uid);
5196 data_offset->Gid = cpu_to_le64(args->gid);
5197 /* better to leave device as zero when it is */
5198 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5199 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5200 data_offset->Permissions = cpu_to_le64(mode);
5201
5202 if (S_ISREG(mode))
5203 data_offset->Type = cpu_to_le32(UNIX_FILE);
5204 else if (S_ISDIR(mode))
5205 data_offset->Type = cpu_to_le32(UNIX_DIR);
5206 else if (S_ISLNK(mode))
5207 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5208 else if (S_ISCHR(mode))
5209 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5210 else if (S_ISBLK(mode))
5211 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5212 else if (S_ISFIFO(mode))
5213 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5214 else if (S_ISSOCK(mode))
5215 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5216}
5217
Linus Torvalds1da177e2005-04-16 15:20:36 -07005218int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005219CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5220 const struct cifs_unix_set_info_args *args,
5221 u16 fid, u32 pid_of_opener)
5222{
5223 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5224 FILE_UNIX_BASIC_INFO *data_offset;
5225 int rc = 0;
5226 u16 params, param_offset, offset, byte_count, count;
5227
Joe Perchesb6b38f72010-04-21 03:50:45 +00005228 cFYI(1, "Set Unix Info (via SetFileInfo)");
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005229 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5230
5231 if (rc)
5232 return rc;
5233
5234 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5235 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5236
5237 params = 6;
5238 pSMB->MaxSetupCount = 0;
5239 pSMB->Reserved = 0;
5240 pSMB->Flags = 0;
5241 pSMB->Timeout = 0;
5242 pSMB->Reserved2 = 0;
5243 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5244 offset = param_offset + params;
5245
5246 data_offset = (FILE_UNIX_BASIC_INFO *)
5247 ((char *)(&pSMB->hdr.Protocol) + offset);
5248 count = sizeof(FILE_UNIX_BASIC_INFO);
5249
5250 pSMB->MaxParameterCount = cpu_to_le16(2);
5251 /* BB find max SMB PDU from sess */
5252 pSMB->MaxDataCount = cpu_to_le16(1000);
5253 pSMB->SetupCount = 1;
5254 pSMB->Reserved3 = 0;
5255 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5256 byte_count = 3 /* pad */ + params + count;
5257 pSMB->DataCount = cpu_to_le16(count);
5258 pSMB->ParameterCount = cpu_to_le16(params);
5259 pSMB->TotalDataCount = pSMB->DataCount;
5260 pSMB->TotalParameterCount = pSMB->ParameterCount;
5261 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5262 pSMB->DataOffset = cpu_to_le16(offset);
5263 pSMB->Fid = fid;
5264 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5265 pSMB->Reserved4 = 0;
5266 pSMB->hdr.smb_buf_length += byte_count;
5267 pSMB->ByteCount = cpu_to_le16(byte_count);
5268
5269 cifs_fill_unix_set_info(data_offset, args);
5270
5271 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5272 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005273 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005274
5275 /* Note: On -EAGAIN error only caller can retry on handle based calls
5276 since file handle passed in no longer valid */
5277
5278 return rc;
5279}
5280
5281int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005282CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5283 const struct cifs_unix_set_info_args *args,
5284 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005285{
5286 TRANSACTION2_SPI_REQ *pSMB = NULL;
5287 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5288 int name_len;
5289 int rc = 0;
5290 int bytes_returned = 0;
5291 FILE_UNIX_BASIC_INFO *data_offset;
5292 __u16 params, param_offset, offset, count, byte_count;
5293
Joe Perchesb6b38f72010-04-21 03:50:45 +00005294 cFYI(1, "In SetUID/GID/Mode");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295setPermsRetry:
5296 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5297 (void **) &pSMBr);
5298 if (rc)
5299 return rc;
5300
5301 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5302 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005303 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005304 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305 name_len++; /* trailing null */
5306 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005307 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 name_len = strnlen(fileName, PATH_MAX);
5309 name_len++; /* trailing null */
5310 strncpy(pSMB->FileName, fileName, name_len);
5311 }
5312
5313 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005314 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005316 /* BB find max SMB PDU from sess structure BB */
5317 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005318 pSMB->MaxSetupCount = 0;
5319 pSMB->Reserved = 0;
5320 pSMB->Flags = 0;
5321 pSMB->Timeout = 0;
5322 pSMB->Reserved2 = 0;
5323 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005324 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 offset = param_offset + params;
5326 data_offset =
5327 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5328 offset);
5329 memset(data_offset, 0, count);
5330 pSMB->DataOffset = cpu_to_le16(offset);
5331 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5332 pSMB->SetupCount = 1;
5333 pSMB->Reserved3 = 0;
5334 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5335 byte_count = 3 /* pad */ + params + count;
5336 pSMB->ParameterCount = cpu_to_le16(params);
5337 pSMB->DataCount = cpu_to_le16(count);
5338 pSMB->TotalParameterCount = pSMB->ParameterCount;
5339 pSMB->TotalDataCount = pSMB->DataCount;
5340 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5341 pSMB->Reserved4 = 0;
5342 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005343
Jeff Layton654cf142009-07-09 20:02:49 -04005344 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345
5346 pSMB->ByteCount = cpu_to_le16(byte_count);
5347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005349 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005350 cFYI(1, "SetPathInfo (perms) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351
Steve French0d817bc2008-05-22 02:02:03 +00005352 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 if (rc == -EAGAIN)
5354 goto setPermsRetry;
5355 return rc;
5356}
5357
Steve French50c2f752007-07-13 00:33:32 +00005358int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005359 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005360 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005361 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005362{
5363 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005364 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5365 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005366 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 int bytes_returned;
5368
Joe Perchesb6b38f72010-04-21 03:50:45 +00005369 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005370 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005371 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005372 if (rc)
5373 return rc;
5374
5375 pSMB->TotalParameterCount = 0 ;
5376 pSMB->TotalDataCount = 0;
5377 pSMB->MaxParameterCount = cpu_to_le32(2);
5378 /* BB find exact data count max from sess structure BB */
5379 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005380/* BB VERIFY verify which is correct for above BB */
5381 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5382 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5383
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 pSMB->MaxSetupCount = 4;
5385 pSMB->Reserved = 0;
5386 pSMB->ParameterOffset = 0;
5387 pSMB->DataCount = 0;
5388 pSMB->DataOffset = 0;
5389 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5390 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5391 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005392 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5394 pSMB->Reserved2 = 0;
5395 pSMB->CompletionFilter = cpu_to_le32(filter);
5396 pSMB->Fid = netfid; /* file handle always le */
5397 pSMB->ByteCount = 0;
5398
5399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005400 (struct smb_hdr *)pSMBr, &bytes_returned,
5401 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005403 cFYI(1, "Error in Notify = %d", rc);
Steve Frenchff5dbd92005-08-24 17:10:36 -07005404 } else {
5405 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005406 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005407 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005408 sizeof(struct dir_notify_req),
5409 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005410 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005411 dnotify_req->Pid = pSMB->hdr.Pid;
5412 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5413 dnotify_req->Mid = pSMB->hdr.Mid;
5414 dnotify_req->Tid = pSMB->hdr.Tid;
5415 dnotify_req->Uid = pSMB->hdr.Uid;
5416 dnotify_req->netfid = netfid;
5417 dnotify_req->pfile = pfile;
5418 dnotify_req->filter = filter;
5419 dnotify_req->multishot = multishot;
5420 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005421 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005422 &GlobalDnotifyReqList);
5423 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005424 } else
Steve French47c786e2005-10-11 20:03:18 -07005425 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426 }
5427 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005428 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429}
Jeff Layton31c05192010-02-10 16:18:26 -05005430
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431#ifdef CONFIG_CIFS_XATTR
Jeff Layton31c05192010-02-10 16:18:26 -05005432/*
5433 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
5434 * function used by listxattr and getxattr type calls. When ea_name is set,
5435 * it looks for that attribute name and stuffs that value into the EAData
5436 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
5437 * buffer. In both cases, the return value is either the length of the
5438 * resulting data or a negative error code. If EAData is a NULL pointer then
5439 * the data isn't copied to it, but the length is returned.
5440 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005441ssize_t
5442CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
Jeff Layton31c05192010-02-10 16:18:26 -05005443 const unsigned char *searchName, const unsigned char *ea_name,
5444 char *EAData, size_t buf_size,
5445 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446{
5447 /* BB assumes one setup word */
5448 TRANSACTION2_QPI_REQ *pSMB = NULL;
5449 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5450 int rc = 0;
5451 int bytes_returned;
Jeff Layton6e462b92010-02-10 16:18:26 -05005452 int list_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005453 struct fealist *ea_response_data;
Steve French50c2f752007-07-13 00:33:32 +00005454 struct fea *temp_fea;
5455 char *temp_ptr;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005456 char *end_of_smb;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005457 __u16 params, byte_count, data_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005458
Joe Perchesb6b38f72010-04-21 03:50:45 +00005459 cFYI(1, "In Query All EAs path %s", searchName);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460QAllEAsRetry:
5461 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5462 (void **) &pSMBr);
5463 if (rc)
5464 return rc;
5465
5466 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Jeff Layton6e462b92010-02-10 16:18:26 -05005467 list_len =
Steve French50c2f752007-07-13 00:33:32 +00005468 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005469 PATH_MAX, nls_codepage, remap);
Jeff Layton6e462b92010-02-10 16:18:26 -05005470 list_len++; /* trailing null */
5471 list_len *= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005472 } else { /* BB improve the check for buffer overruns BB */
Jeff Layton6e462b92010-02-10 16:18:26 -05005473 list_len = strnlen(searchName, PATH_MAX);
5474 list_len++; /* trailing null */
5475 strncpy(pSMB->FileName, searchName, list_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476 }
5477
Jeff Layton6e462b92010-02-10 16:18:26 -05005478 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005479 pSMB->TotalDataCount = 0;
5480 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005481 /* BB find exact max SMB PDU from sess structure BB */
Jeff Laytone5296142010-02-10 16:18:26 -05005482 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 pSMB->MaxSetupCount = 0;
5484 pSMB->Reserved = 0;
5485 pSMB->Flags = 0;
5486 pSMB->Timeout = 0;
5487 pSMB->Reserved2 = 0;
5488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005489 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005490 pSMB->DataCount = 0;
5491 pSMB->DataOffset = 0;
5492 pSMB->SetupCount = 1;
5493 pSMB->Reserved3 = 0;
5494 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5495 byte_count = params + 1 /* pad */ ;
5496 pSMB->TotalParameterCount = cpu_to_le16(params);
5497 pSMB->ParameterCount = pSMB->TotalParameterCount;
5498 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5499 pSMB->Reserved4 = 0;
5500 pSMB->hdr.smb_buf_length += byte_count;
5501 pSMB->ByteCount = cpu_to_le16(byte_count);
5502
5503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5505 if (rc) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005506 cFYI(1, "Send error in QueryAllEAs = %d", rc);
Jeff Laytonf0d38682010-02-10 16:18:26 -05005507 goto QAllEAsOut;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005508 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005509
5510
5511 /* BB also check enough total bytes returned */
5512 /* BB we need to improve the validity checking
5513 of these trans2 responses */
5514
5515 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5516 if (rc || (pSMBr->ByteCount < 4)) {
5517 rc = -EIO; /* bad smb */
5518 goto QAllEAsOut;
5519 }
5520
5521 /* check that length of list is not more than bcc */
5522 /* check that each entry does not go beyond length
5523 of list */
5524 /* check that each element of each entry does not
5525 go beyond end of list */
5526 /* validate_trans2_offsets() */
5527 /* BB check if start of smb + data_offset > &bcc+ bcc */
5528
5529 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5530 ea_response_data = (struct fealist *)
5531 (((char *) &pSMBr->hdr.Protocol) + data_offset);
5532
Jeff Layton6e462b92010-02-10 16:18:26 -05005533 list_len = le32_to_cpu(ea_response_data->list_len);
Joe Perchesb6b38f72010-04-21 03:50:45 +00005534 cFYI(1, "ea length %d", list_len);
Jeff Layton6e462b92010-02-10 16:18:26 -05005535 if (list_len <= 8) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005536 cFYI(1, "empty EA list returned from server");
Jeff Laytonf0d38682010-02-10 16:18:26 -05005537 goto QAllEAsOut;
5538 }
5539
Jeff Layton0cd126b2010-02-10 16:18:26 -05005540 /* make sure list_len doesn't go past end of SMB */
5541 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + BCC(&pSMBr->hdr);
5542 if ((char *)ea_response_data + list_len > end_of_smb) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005543 cFYI(1, "EA list appears to go beyond SMB");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005544 rc = -EIO;
5545 goto QAllEAsOut;
5546 }
5547
Jeff Laytonf0d38682010-02-10 16:18:26 -05005548 /* account for ea list len */
Jeff Layton6e462b92010-02-10 16:18:26 -05005549 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005550 temp_fea = ea_response_data->list;
5551 temp_ptr = (char *)temp_fea;
Jeff Layton6e462b92010-02-10 16:18:26 -05005552 while (list_len > 0) {
Steve French122ca002010-02-24 21:56:48 +00005553 unsigned int name_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005554 __u16 value_len;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005555
Jeff Layton6e462b92010-02-10 16:18:26 -05005556 list_len -= 4;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005557 temp_ptr += 4;
Jeff Layton0cd126b2010-02-10 16:18:26 -05005558 /* make sure we can read name_len and value_len */
5559 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005560 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005561 rc = -EIO;
5562 goto QAllEAsOut;
5563 }
5564
5565 name_len = temp_fea->name_len;
5566 value_len = le16_to_cpu(temp_fea->value_len);
5567 list_len -= name_len + 1 + value_len;
5568 if (list_len < 0) {
Joe Perchesb6b38f72010-04-21 03:50:45 +00005569 cFYI(1, "EA entry goes beyond length of list");
Jeff Layton0cd126b2010-02-10 16:18:26 -05005570 rc = -EIO;
5571 goto QAllEAsOut;
5572 }
5573
Jeff Layton31c05192010-02-10 16:18:26 -05005574 if (ea_name) {
5575 if (strncmp(ea_name, temp_ptr, name_len) == 0) {
5576 temp_ptr += name_len + 1;
5577 rc = value_len;
5578 if (buf_size == 0)
5579 goto QAllEAsOut;
5580 if ((size_t)value_len > buf_size) {
5581 rc = -ERANGE;
5582 goto QAllEAsOut;
5583 }
5584 memcpy(EAData, temp_ptr, value_len);
5585 goto QAllEAsOut;
5586 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005587 } else {
Jeff Layton31c05192010-02-10 16:18:26 -05005588 /* account for prefix user. and trailing null */
5589 rc += (5 + 1 + name_len);
5590 if (rc < (int) buf_size) {
5591 memcpy(EAData, "user.", 5);
5592 EAData += 5;
5593 memcpy(EAData, temp_ptr, name_len);
5594 EAData += name_len;
5595 /* null terminate name */
5596 *EAData = 0;
5597 ++EAData;
5598 } else if (buf_size == 0) {
5599 /* skip copy - calc size only */
5600 } else {
5601 /* stop before overrun buffer */
5602 rc = -ERANGE;
5603 break;
5604 }
Jeff Laytonf0d38682010-02-10 16:18:26 -05005605 }
Jeff Layton0cd126b2010-02-10 16:18:26 -05005606 temp_ptr += name_len + 1 + value_len;
Jeff Laytonf0d38682010-02-10 16:18:26 -05005607 temp_fea = (struct fea *)temp_ptr;
5608 }
5609
Jeff Layton31c05192010-02-10 16:18:26 -05005610 /* didn't find the named attribute */
5611 if (ea_name)
5612 rc = -ENODATA;
5613
Jeff Laytonf0d38682010-02-10 16:18:26 -05005614QAllEAsOut:
Steve French0d817bc2008-05-22 02:02:03 +00005615 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 if (rc == -EAGAIN)
5617 goto QAllEAsRetry;
5618
5619 return (ssize_t)rc;
5620}
5621
Linus Torvalds1da177e2005-04-16 15:20:36 -07005622int
5623CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005624 const char *ea_name, const void *ea_value,
5625 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5626 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005627{
5628 struct smb_com_transaction2_spi_req *pSMB = NULL;
5629 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5630 struct fealist *parm_data;
5631 int name_len;
5632 int rc = 0;
5633 int bytes_returned = 0;
5634 __u16 params, param_offset, byte_count, offset, count;
5635
Joe Perchesb6b38f72010-04-21 03:50:45 +00005636 cFYI(1, "In SetEA");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005637SetEARetry:
5638 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5639 (void **) &pSMBr);
5640 if (rc)
5641 return rc;
5642
5643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5644 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005645 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005646 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005647 name_len++; /* trailing null */
5648 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005649 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005650 name_len = strnlen(fileName, PATH_MAX);
5651 name_len++; /* trailing null */
5652 strncpy(pSMB->FileName, fileName, name_len);
5653 }
5654
5655 params = 6 + name_len;
5656
5657 /* done calculating parms using name_len of file name,
5658 now use name_len to calculate length of ea name
5659 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005660 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 name_len = 0;
5662 else
Steve French50c2f752007-07-13 00:33:32 +00005663 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005664
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005665 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005666 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005667 /* BB find max SMB PDU from sess */
5668 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005669 pSMB->MaxSetupCount = 0;
5670 pSMB->Reserved = 0;
5671 pSMB->Flags = 0;
5672 pSMB->Timeout = 0;
5673 pSMB->Reserved2 = 0;
5674 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005675 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005676 offset = param_offset + params;
5677 pSMB->InformationLevel =
5678 cpu_to_le16(SMB_SET_FILE_EA);
5679
5680 parm_data =
5681 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5682 offset);
5683 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5684 pSMB->DataOffset = cpu_to_le16(offset);
5685 pSMB->SetupCount = 1;
5686 pSMB->Reserved3 = 0;
5687 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5688 byte_count = 3 /* pad */ + params + count;
5689 pSMB->DataCount = cpu_to_le16(count);
5690 parm_data->list_len = cpu_to_le32(count);
5691 parm_data->list[0].EA_flags = 0;
5692 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005693 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005694 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005695 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005696 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005697 parm_data->list[0].name[name_len] = 0;
5698 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5699 /* caller ensures that ea_value_len is less than 64K but
5700 we need to ensure that it fits within the smb */
5701
Steve French50c2f752007-07-13 00:33:32 +00005702 /*BB add length check to see if it would fit in
5703 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005704 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5705 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005706 memcpy(parm_data->list[0].name+name_len+1,
5707 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005708
5709 pSMB->TotalDataCount = pSMB->DataCount;
5710 pSMB->ParameterCount = cpu_to_le16(params);
5711 pSMB->TotalParameterCount = pSMB->ParameterCount;
5712 pSMB->Reserved4 = 0;
5713 pSMB->hdr.smb_buf_length += byte_count;
5714 pSMB->ByteCount = cpu_to_le16(byte_count);
5715 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5716 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005717 if (rc)
Joe Perchesb6b38f72010-04-21 03:50:45 +00005718 cFYI(1, "SetPathInfo (EA) returned %d", rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005719
5720 cifs_buf_release(pSMB);
5721
5722 if (rc == -EAGAIN)
5723 goto SetEARetry;
5724
5725 return rc;
5726}
5727
5728#endif