CIFS: Extend credit mechanism to process request type
[linux-2.6-block.git] / fs / cifs / cifssmb.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/cifssmb.c
3 *
f19159dc 4 * Copyright (C) International Business Machines Corp., 2002,2010
1da177e4
LT
5 * 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 */
2dd29d31
SF
27 /* 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 */
1da177e4
LT
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
5a0e3ad6 33#include <linux/slab.h>
1da177e4 34#include <linux/posix_acl_xattr.h>
c28c89fc 35#include <linux/pagemap.h>
e28bc5b1
JL
36#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
1da177e4
LT
38#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
d0d66c44 41#include "cifsacl.h"
1da177e4
LT
42#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
e28bc5b1 45#include "fscache.h"
1da177e4
LT
46
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
3979877e
SF
52#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
9ac00b7d 54 {LANMAN2_PROT, "\2LANMAN2.1"},
3979877e 55#endif /* weak password hashing for legacy clients */
50c2f753 56 {CIFS_PROT, "\2NT LM 0.12"},
3979877e 57 {POSIX_PROT, "\2POSIX 2"},
1da177e4
LT
58 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
3979877e
SF
65#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
18f75ca0 67 {LANMAN2_PROT, "\2LANMAN2.1"},
3979877e 68#endif /* weak password hashing for legacy clients */
790fe579 69 {CIFS_PROT, "\2NT LM 0.12"},
1da177e4
LT
70 {BAD_PROT, "\2"}
71};
72#endif
73
3979877e
SF
74/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
9ac00b7d 77#define CIFS_NUM_PROT 4
3979877e
SF
78#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
9ac00b7d 83#define CIFS_NUM_PROT 3
3979877e
SF
84#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
3cf003c0
JL
89#ifdef CONFIG_HIGHMEM
90/*
91 * On arches that have high memory, kmap address space is limited. By
92 * serializing the kmap operations on those arches, we ensure that we don't
93 * end up with a bunch of threads in writeback with partially mapped page
94 * arrays, stuck waiting for kmap to come back. That situation prevents
95 * progress and can deadlock.
96 */
97static DEFINE_MUTEX(cifs_kmap_mutex);
98
99static inline void
100cifs_kmap_lock(void)
101{
102 mutex_lock(&cifs_kmap_mutex);
103}
104
105static inline void
106cifs_kmap_unlock(void)
107{
108 mutex_unlock(&cifs_kmap_mutex);
109}
110#else /* !CONFIG_HIGHMEM */
111#define cifs_kmap_lock() do { ; } while(0)
112#define cifs_kmap_unlock() do { ; } while(0)
113#endif /* CONFIG_HIGHMEM */
e28bc5b1 114
1da177e4
LT
115/* Mark as invalid, all open files on tree connections since they
116 were closed when session to server was lost */
96daf2b0 117static void mark_open_files_invalid(struct cifs_tcon *pTcon)
1da177e4
LT
118{
119 struct cifsFileInfo *open_file = NULL;
790fe579
SF
120 struct list_head *tmp;
121 struct list_head *tmp1;
1da177e4
LT
122
123/* list all files open on tree connection and mark them invalid */
4477288a 124 spin_lock(&cifs_file_list_lock);
1da177e4 125 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
790fe579 126 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
ad8b15f0 127 open_file->invalidHandle = true;
3bc303c2 128 open_file->oplock_break_cancelled = true;
1da177e4 129 }
4477288a 130 spin_unlock(&cifs_file_list_lock);
09d1db5c
SF
131 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
132 to this tcon */
1da177e4
LT
133}
134
9162ab20
JL
135/* reconnect the socket, tcon, and smb session if needed */
136static int
96daf2b0 137cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
9162ab20 138{
c4a5534a 139 int rc;
96daf2b0 140 struct cifs_ses *ses;
9162ab20
JL
141 struct TCP_Server_Info *server;
142 struct nls_table *nls_codepage;
143
144 /*
145 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
146 * tcp and smb session status done differently for those three - in the
147 * calling routine
148 */
149 if (!tcon)
150 return 0;
151
152 ses = tcon->ses;
153 server = ses->server;
154
155 /*
156 * only tree disconnect, open, and write, (and ulogoff which does not
157 * have tcon) are allowed as we start force umount
158 */
159 if (tcon->tidStatus == CifsExiting) {
160 if (smb_command != SMB_COM_WRITE_ANDX &&
161 smb_command != SMB_COM_OPEN_ANDX &&
162 smb_command != SMB_COM_TREE_DISCONNECT) {
b6b38f70
JP
163 cFYI(1, "can not send cmd %d while umounting",
164 smb_command);
9162ab20
JL
165 return -ENODEV;
166 }
167 }
168
9162ab20
JL
169 /*
170 * Give demultiplex thread up to 10 seconds to reconnect, should be
171 * greater than cifs socket timeout which is 7 seconds
172 */
173 while (server->tcpStatus == CifsNeedReconnect) {
174 wait_event_interruptible_timeout(server->response_q,
fd88ce93 175 (server->tcpStatus != CifsNeedReconnect), 10 * HZ);
9162ab20 176
fd88ce93 177 /* are we still trying to reconnect? */
9162ab20
JL
178 if (server->tcpStatus != CifsNeedReconnect)
179 break;
180
181 /*
182 * on "soft" mounts we wait once. Hard mounts keep
183 * retrying until process is killed or server comes
184 * back on-line
185 */
d402539b 186 if (!tcon->retry) {
b6b38f70 187 cFYI(1, "gave up waiting on reconnect in smb_init");
9162ab20
JL
188 return -EHOSTDOWN;
189 }
190 }
191
192 if (!ses->need_reconnect && !tcon->need_reconnect)
193 return 0;
194
195 nls_codepage = load_nls_default();
196
197 /*
198 * need to prevent multiple threads trying to simultaneously
199 * reconnect the same SMB session
200 */
d7b619cf 201 mutex_lock(&ses->session_mutex);
198b5682
JL
202 rc = cifs_negotiate_protocol(0, ses);
203 if (rc == 0 && ses->need_reconnect)
9162ab20
JL
204 rc = cifs_setup_session(0, ses, nls_codepage);
205
206 /* do we need to reconnect tcon? */
207 if (rc || !tcon->need_reconnect) {
d7b619cf 208 mutex_unlock(&ses->session_mutex);
9162ab20
JL
209 goto out;
210 }
211
212 mark_open_files_invalid(tcon);
213 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
d7b619cf 214 mutex_unlock(&ses->session_mutex);
b6b38f70 215 cFYI(1, "reconnect tcon rc = %d", rc);
9162ab20
JL
216
217 if (rc)
218 goto out;
219
220 /*
221 * FIXME: check if wsize needs updated due to negotiated smb buffer
222 * size shrinking
223 */
224 atomic_inc(&tconInfoReconnectCount);
225
226 /* tell server Unix caps we support */
227 if (ses->capabilities & CAP_UNIX)
228 reset_cifs_unix_caps(0, tcon, NULL, NULL);
229
230 /*
231 * Removed call to reopen open files here. It is safer (and faster) to
232 * reopen files one at a time as needed in read and write.
233 *
234 * FIXME: what about file locks? don't we need to reclaim them ASAP?
235 */
236
237out:
238 /*
239 * Check if handle based operation so we know whether we can continue
240 * or not without returning to caller to reset file handle
241 */
242 switch (smb_command) {
243 case SMB_COM_READ_ANDX:
244 case SMB_COM_WRITE_ANDX:
245 case SMB_COM_CLOSE:
246 case SMB_COM_FIND_CLOSE2:
247 case SMB_COM_LOCKING_ANDX:
248 rc = -EAGAIN;
249 }
250
251 unload_nls(nls_codepage);
252 return rc;
253}
254
ad7a2926
SF
255/* Allocate and return pointer to an SMB request buffer, and set basic
256 SMB information in the SMB header. If the return code is zero, this
257 function must have filled in request_buf pointer */
1da177e4 258static int
96daf2b0 259small_smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
ad7a2926 260 void **request_buf)
1da177e4 261{
f569599a 262 int rc;
1da177e4 263
9162ab20 264 rc = cifs_reconnect_tcon(tcon, smb_command);
790fe579 265 if (rc)
1da177e4
LT
266 return rc;
267
268 *request_buf = cifs_small_buf_get();
269 if (*request_buf == NULL) {
270 /* BB should we add a retry in here if not a writepage? */
271 return -ENOMEM;
272 }
273
63135e08 274 header_assemble((struct smb_hdr *) *request_buf, smb_command,
c18c842b 275 tcon, wct);
1da177e4 276
790fe579
SF
277 if (tcon != NULL)
278 cifs_stats_inc(&tcon->num_smbs_sent);
a4544347 279
f569599a 280 return 0;
5815449d
SF
281}
282
12b3b8ff 283int
50c2f753 284small_smb_init_no_tc(const int smb_command, const int wct,
96daf2b0 285 struct cifs_ses *ses, void **request_buf)
12b3b8ff
SF
286{
287 int rc;
50c2f753 288 struct smb_hdr *buffer;
12b3b8ff 289
5815449d 290 rc = small_smb_init(smb_command, wct, NULL, request_buf);
790fe579 291 if (rc)
12b3b8ff
SF
292 return rc;
293
04fdabe1 294 buffer = (struct smb_hdr *)*request_buf;
88257360 295 buffer->Mid = get_next_mid(ses->server);
12b3b8ff
SF
296 if (ses->capabilities & CAP_UNICODE)
297 buffer->Flags2 |= SMBFLG2_UNICODE;
04fdabe1 298 if (ses->capabilities & CAP_STATUS32)
12b3b8ff
SF
299 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
300
301 /* uid, tid can stay at zero as set in header assemble */
302
50c2f753 303 /* BB add support for turning on the signing when
12b3b8ff
SF
304 this function is used after 1st of session setup requests */
305
306 return rc;
307}
1da177e4
LT
308
309/* If the return code is zero, this function must fill in request_buf pointer */
310static int
96daf2b0 311__smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
f569599a 312 void **request_buf, void **response_buf)
1da177e4 313{
1da177e4
LT
314 *request_buf = cifs_buf_get();
315 if (*request_buf == NULL) {
316 /* BB should we add a retry in here if not a writepage? */
317 return -ENOMEM;
318 }
319 /* Although the original thought was we needed the response buf for */
320 /* potential retries of smb operations it turns out we can determine */
321 /* from the mid flags when the request buffer can be resent without */
322 /* having to use a second distinct buffer for the response */
790fe579 323 if (response_buf)
50c2f753 324 *response_buf = *request_buf;
1da177e4
LT
325
326 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
ad7a2926 327 wct);
1da177e4 328
790fe579
SF
329 if (tcon != NULL)
330 cifs_stats_inc(&tcon->num_smbs_sent);
a4544347 331
f569599a
JL
332 return 0;
333}
334
335/* If the return code is zero, this function must fill in request_buf pointer */
336static int
96daf2b0 337smb_init(int smb_command, int wct, struct cifs_tcon *tcon,
f569599a
JL
338 void **request_buf, void **response_buf)
339{
340 int rc;
341
342 rc = cifs_reconnect_tcon(tcon, smb_command);
343 if (rc)
344 return rc;
345
346 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
347}
348
349static int
96daf2b0 350smb_init_no_reconnect(int smb_command, int wct, struct cifs_tcon *tcon,
f569599a
JL
351 void **request_buf, void **response_buf)
352{
353 if (tcon->ses->need_reconnect || tcon->need_reconnect)
354 return -EHOSTDOWN;
355
356 return __smb_init(smb_command, wct, tcon, request_buf, response_buf);
1da177e4
LT
357}
358
50c2f753 359static int validate_t2(struct smb_t2_rsp *pSMB)
1da177e4 360{
12df83c9
JL
361 unsigned int total_size;
362
363 /* check for plausible wct */
364 if (pSMB->hdr.WordCount < 10)
365 goto vt2_err;
1da177e4 366
1da177e4 367 /* check for parm and data offset going beyond end of smb */
12df83c9
JL
368 if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 ||
369 get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024)
370 goto vt2_err;
371
12df83c9
JL
372 total_size = get_unaligned_le16(&pSMB->t2_rsp.ParameterCount);
373 if (total_size >= 512)
374 goto vt2_err;
375
fd5707e1
JL
376 /* check that bcc is at least as big as parms + data, and that it is
377 * less than negotiated smb buffer
378 */
12df83c9
JL
379 total_size += get_unaligned_le16(&pSMB->t2_rsp.DataCount);
380 if (total_size > get_bcc(&pSMB->hdr) ||
381 total_size >= CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
382 goto vt2_err;
383
384 return 0;
385vt2_err:
50c2f753 386 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
1da177e4 387 sizeof(struct smb_t2_rsp) + 16);
12df83c9 388 return -EINVAL;
1da177e4 389}
690c522f 390
be8e3b00
SF
391static inline void inc_rfc1001_len(void *pSMB, int count)
392{
393 struct smb_hdr *hdr = (struct smb_hdr *)pSMB;
394
395 be32_add_cpu(&hdr->smb_buf_length, count);
396}
397
1da177e4 398int
96daf2b0 399CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses)
1da177e4
LT
400{
401 NEGOTIATE_REQ *pSMB;
402 NEGOTIATE_RSP *pSMBr;
403 int rc = 0;
404 int bytes_returned;
3979877e 405 int i;
50c2f753 406 struct TCP_Server_Info *server;
1da177e4 407 u16 count;
750d1151 408 unsigned int secFlags;
1da177e4 409
790fe579 410 if (ses->server)
1da177e4
LT
411 server = ses->server;
412 else {
413 rc = -EIO;
414 return rc;
415 }
416 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
417 (void **) &pSMB, (void **) &pSMBr);
418 if (rc)
419 return rc;
750d1151
SF
420
421 /* if any of auth flags (ie not sign or seal) are overriden use them */
790fe579 422 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
762e5ab7 423 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
750d1151 424 else /* if override flags set only sign/seal OR them with global auth */
04912d6a 425 secFlags = global_secflags | ses->overrideSecFlg;
750d1151 426
b6b38f70 427 cFYI(1, "secFlags 0x%x", secFlags);
f40c5628 428
88257360 429 pSMB->hdr.Mid = get_next_mid(server);
100c1ddc 430 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
a013689d 431
100c1ddc 432 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
254e55ed 433 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
a013689d 434 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
b6b38f70 435 cFYI(1, "Kerberos only mechanism, enable extended security");
a013689d 436 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
b4d6fcf1 437 } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
ac683924
SF
438 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
439 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
b6b38f70 440 cFYI(1, "NTLMSSP only mechanism, enable extended security");
ac683924
SF
441 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
442 }
50c2f753 443
3979877e 444 count = 0;
50c2f753 445 for (i = 0; i < CIFS_NUM_PROT; i++) {
3979877e
SF
446 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
447 count += strlen(protocols[i].name) + 1;
448 /* null at end of source and target buffers anyway */
449 }
be8e3b00 450 inc_rfc1001_len(pSMB, count);
1da177e4
LT
451 pSMB->ByteCount = cpu_to_le16(count);
452
453 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
454 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
50c2f753 455 if (rc != 0)
254e55ed
SF
456 goto neg_err_exit;
457
9bf67e51
JL
458 server->dialect = le16_to_cpu(pSMBr->DialectIndex);
459 cFYI(1, "Dialect: %d", server->dialect);
254e55ed 460 /* Check wct = 1 error case */
9bf67e51 461 if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) {
254e55ed 462 /* core returns wct = 1, but we do not ask for core - otherwise
50c2f753 463 small wct just comes when dialect index is -1 indicating we
254e55ed
SF
464 could not negotiate a common dialect */
465 rc = -EOPNOTSUPP;
466 goto neg_err_exit;
50c2f753 467#ifdef CONFIG_CIFS_WEAK_PW_HASH
790fe579 468 } else if ((pSMBr->hdr.WordCount == 13)
9bf67e51
JL
469 && ((server->dialect == LANMAN_PROT)
470 || (server->dialect == LANMAN2_PROT))) {
b815f1e5 471 __s16 tmp;
50c2f753 472 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
254e55ed 473
790fe579 474 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
750d1151 475 (secFlags & CIFSSEC_MAY_PLNTXT))
254e55ed
SF
476 server->secType = LANMAN;
477 else {
b6b38f70
JP
478 cERROR(1, "mount failed weak security disabled"
479 " in /proc/fs/cifs/SecurityFlags");
3979877e
SF
480 rc = -EOPNOTSUPP;
481 goto neg_err_exit;
50c2f753 482 }
96daf2b0 483 server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode);
10b9b98e
PS
484 server->maxReq = min_t(unsigned int,
485 le16_to_cpu(rsp->MaxMpxCount),
486 cifs_max_pending);
45275789 487 set_credits(server, server->maxReq);
c974befa 488 server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
eca6acf9 489 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
254e55ed
SF
490 /* even though we do not use raw we might as well set this
491 accurately, in case we ever find a need for it */
790fe579 492 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
eca6acf9 493 server->max_rw = 0xFF00;
254e55ed
SF
494 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
495 } else {
eca6acf9 496 server->max_rw = 0;/* do not need to use raw anyway */
254e55ed
SF
497 server->capabilities = CAP_MPX_MODE;
498 }
b815f1e5 499 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
1a70d652 500 if (tmp == -1) {
25ee4a98
SF
501 /* OS/2 often does not set timezone therefore
502 * we must use server time to calc time zone.
b815f1e5
SF
503 * Could deviate slightly from the right zone.
504 * Smallest defined timezone difference is 15 minutes
505 * (i.e. Nepal). Rounding up/down is done to match
506 * this requirement.
25ee4a98 507 */
b815f1e5 508 int val, seconds, remain, result;
25ee4a98
SF
509 struct timespec ts, utc;
510 utc = CURRENT_TIME;
c4a2c08d
JL
511 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
512 rsp->SrvTime.Time, 0);
b6b38f70 513 cFYI(1, "SrvTime %d sec since 1970 (utc: %d) diff: %d",
50c2f753 514 (int)ts.tv_sec, (int)utc.tv_sec,
b6b38f70 515 (int)(utc.tv_sec - ts.tv_sec));
b815f1e5 516 val = (int)(utc.tv_sec - ts.tv_sec);
8594c15a 517 seconds = abs(val);
947a5067 518 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
b815f1e5 519 remain = seconds % MIN_TZ_ADJ;
790fe579 520 if (remain >= (MIN_TZ_ADJ / 2))
b815f1e5 521 result += MIN_TZ_ADJ;
790fe579 522 if (val < 0)
ad7a2926 523 result = -result;
b815f1e5 524 server->timeAdj = result;
25ee4a98 525 } else {
b815f1e5
SF
526 server->timeAdj = (int)tmp;
527 server->timeAdj *= 60; /* also in seconds */
25ee4a98 528 }
b6b38f70 529 cFYI(1, "server->timeAdj: %d seconds", server->timeAdj);
25ee4a98 530
3979877e 531
254e55ed 532 /* BB get server time for time conversions and add
50c2f753 533 code to use it and timezone since this is not UTC */
3979877e 534
50c2f753 535 if (rsp->EncryptionKeyLength ==
25ee4a98 536 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
d3ba50b1 537 memcpy(ses->server->cryptkey, rsp->EncryptionKey,
254e55ed 538 CIFS_CRYPTO_KEY_SIZE);
96daf2b0 539 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
254e55ed
SF
540 rc = -EIO; /* need cryptkey unless plain text */
541 goto neg_err_exit;
542 }
3979877e 543
f19159dc 544 cFYI(1, "LANMAN negotiated");
254e55ed
SF
545 /* we will not end up setting signing flags - as no signing
546 was in LANMAN and server did not return the flags on */
547 goto signing_check;
7c7b25bc 548#else /* weak security disabled */
790fe579 549 } else if (pSMBr->hdr.WordCount == 13) {
f19159dc
SF
550 cERROR(1, "mount failed, cifs module not built "
551 "with CIFS_WEAK_PW_HASH support");
8212cf75 552 rc = -EOPNOTSUPP;
7c7b25bc 553#endif /* WEAK_PW_HASH */
254e55ed 554 goto neg_err_exit;
790fe579 555 } else if (pSMBr->hdr.WordCount != 17) {
254e55ed
SF
556 /* unknown wct */
557 rc = -EOPNOTSUPP;
558 goto neg_err_exit;
559 }
560 /* else wct == 17 NTLM */
96daf2b0
SF
561 server->sec_mode = pSMBr->SecurityMode;
562 if ((server->sec_mode & SECMODE_USER) == 0)
b6b38f70 563 cFYI(1, "share mode security");
bdc4bf6e 564
96daf2b0 565 if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
bdc4bf6e 566#ifdef CONFIG_CIFS_WEAK_PW_HASH
750d1151 567 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
bdc4bf6e 568#endif /* CIFS_WEAK_PW_HASH */
b6b38f70
JP
569 cERROR(1, "Server requests plain text password"
570 " but client support disabled");
9312f675 571
790fe579 572 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
254e55ed 573 server->secType = NTLMv2;
790fe579 574 else if (secFlags & CIFSSEC_MAY_NTLM)
254e55ed 575 server->secType = NTLM;
790fe579 576 else if (secFlags & CIFSSEC_MAY_NTLMV2)
f40c5628 577 server->secType = NTLMv2;
a013689d
SF
578 else if (secFlags & CIFSSEC_MAY_KRB5)
579 server->secType = Kerberos;
ac683924 580 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
f46c7234 581 server->secType = RawNTLMSSP;
a013689d
SF
582 else if (secFlags & CIFSSEC_MAY_LANMAN)
583 server->secType = LANMAN;
a013689d
SF
584 else {
585 rc = -EOPNOTSUPP;
b6b38f70 586 cERROR(1, "Invalid security type");
a013689d
SF
587 goto neg_err_exit;
588 }
589 /* else ... any others ...? */
254e55ed
SF
590
591 /* one byte, so no need to convert this or EncryptionKeyLen from
592 little endian */
10b9b98e
PS
593 server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
594 cifs_max_pending);
45275789 595 set_credits(server, server->maxReq);
254e55ed 596 /* probably no need to store and check maxvcs */
c974befa 597 server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize);
eca6acf9 598 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
b6b38f70 599 cFYI(DBG2, "Max buf = %d", ses->server->maxBuf);
254e55ed 600 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
b815f1e5
SF
601 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
602 server->timeAdj *= 60;
254e55ed 603 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
d3ba50b1 604 memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
254e55ed 605 CIFS_CRYPTO_KEY_SIZE);
07cc6cf9
SF
606 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
607 server->capabilities & CAP_EXTENDED_SECURITY) &&
608 (pSMBr->EncryptionKeyLength == 0)) {
254e55ed 609 /* decode security blob */
820a803f 610 count = get_bcc(&pSMBr->hdr);
e187e44e 611 if (count < 16) {
254e55ed 612 rc = -EIO;
e187e44e
JL
613 goto neg_err_exit;
614 }
3f9bcca7 615 spin_lock(&cifs_tcp_ses_lock);
e7ddee90 616 if (server->srv_count > 1) {
3f9bcca7 617 spin_unlock(&cifs_tcp_ses_lock);
e187e44e
JL
618 if (memcmp(server->server_GUID,
619 pSMBr->u.extended_response.
620 GUID, 16) != 0) {
b6b38f70 621 cFYI(1, "server UID changed");
254e55ed 622 memcpy(server->server_GUID,
e187e44e
JL
623 pSMBr->u.extended_response.GUID,
624 16);
625 }
e7ddee90 626 } else {
3f9bcca7 627 spin_unlock(&cifs_tcp_ses_lock);
e187e44e
JL
628 memcpy(server->server_GUID,
629 pSMBr->u.extended_response.GUID, 16);
e7ddee90 630 }
e187e44e
JL
631
632 if (count == 16) {
633 server->secType = RawNTLMSSP;
254e55ed
SF
634 } else {
635 rc = decode_negTokenInit(pSMBr->u.extended_response.
26efa0ba
JL
636 SecurityBlob, count - 16,
637 server);
ef571cad 638 if (rc == 1)
e545937a 639 rc = 0;
ef571cad 640 else
254e55ed 641 rc = -EINVAL;
2b149f11
SP
642 if (server->secType == Kerberos) {
643 if (!server->sec_kerberos &&
644 !server->sec_mskerberos)
645 rc = -EOPNOTSUPP;
646 } else if (server->secType == RawNTLMSSP) {
647 if (!server->sec_ntlmssp)
648 rc = -EOPNOTSUPP;
649 } else
650 rc = -EOPNOTSUPP;
1da177e4 651 }
96daf2b0 652 } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
07cc6cf9
SF
653 rc = -EIO; /* no crypt key only if plain text pwd */
654 goto neg_err_exit;
254e55ed
SF
655 } else
656 server->capabilities &= ~CAP_EXTENDED_SECURITY;
657
6344a423 658#ifdef CONFIG_CIFS_WEAK_PW_HASH
254e55ed 659signing_check:
6344a423 660#endif
762e5ab7
SF
661 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
662 /* MUST_SIGN already includes the MAY_SIGN FLAG
663 so if this is zero it means that signing is disabled */
b6b38f70 664 cFYI(1, "Signing disabled");
96daf2b0 665 if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
b6b38f70 666 cERROR(1, "Server requires "
7111d214 667 "packet signing to be enabled in "
b6b38f70 668 "/proc/fs/cifs/SecurityFlags.");
abb63d6c
SF
669 rc = -EOPNOTSUPP;
670 }
96daf2b0 671 server->sec_mode &=
254e55ed 672 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
762e5ab7
SF
673 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
674 /* signing required */
b6b38f70 675 cFYI(1, "Must sign - secFlags 0x%x", secFlags);
96daf2b0 676 if ((server->sec_mode &
762e5ab7 677 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
b6b38f70 678 cERROR(1, "signing required but server lacks support");
38c10a1d 679 rc = -EOPNOTSUPP;
762e5ab7 680 } else
96daf2b0 681 server->sec_mode |= SECMODE_SIGN_REQUIRED;
762e5ab7
SF
682 } else {
683 /* signing optional ie CIFSSEC_MAY_SIGN */
96daf2b0
SF
684 if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
685 server->sec_mode &=
254e55ed 686 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
1da177e4 687 }
50c2f753
SF
688
689neg_err_exit:
4a6d87f1 690 cifs_buf_release(pSMB);
254e55ed 691
b6b38f70 692 cFYI(1, "negprot rc %d", rc);
1da177e4
LT
693 return rc;
694}
695
696int
96daf2b0 697CIFSSMBTDis(const int xid, struct cifs_tcon *tcon)
1da177e4
LT
698{
699 struct smb_hdr *smb_buffer;
1da177e4 700 int rc = 0;
1da177e4 701
b6b38f70 702 cFYI(1, "In tree disconnect");
1da177e4 703
f1987b44
JL
704 /* BB: do we need to check this? These should never be NULL. */
705 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
706 return -EIO;
1da177e4 707
f1987b44
JL
708 /*
709 * No need to return error on this operation if tid invalidated and
710 * closed on server already e.g. due to tcp session crashing. Also,
711 * the tcon is no longer on the list, so no need to take lock before
712 * checking this.
713 */
268875b9 714 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
50c2f753 715 return 0;
1da177e4 716
50c2f753 717 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
09d1db5c 718 (void **)&smb_buffer);
f1987b44 719 if (rc)
1da177e4 720 return rc;
133672ef 721
792af7b0 722 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)smb_buffer, 0);
1da177e4 723 if (rc)
b6b38f70 724 cFYI(1, "Tree disconnect failed %d", rc);
1da177e4 725
50c2f753 726 /* No need to return error on this operation if tid invalidated and
f1987b44 727 closed on server already e.g. due to tcp session crashing */
1da177e4
LT
728 if (rc == -EAGAIN)
729 rc = 0;
730
731 return rc;
732}
733
766fdbb5
JL
734/*
735 * This is a no-op for now. We're not really interested in the reply, but
736 * rather in the fact that the server sent one and that server->lstrp
737 * gets updated.
738 *
739 * FIXME: maybe we should consider checking that the reply matches request?
740 */
741static void
742cifs_echo_callback(struct mid_q_entry *mid)
743{
744 struct TCP_Server_Info *server = mid->callback_data;
745
746 DeleteMidQEntry(mid);
a891f0f8 747 add_credits(server, 1, CIFS_ECHO_OP);
766fdbb5
JL
748}
749
750int
751CIFSSMBEcho(struct TCP_Server_Info *server)
752{
753 ECHO_REQ *smb;
754 int rc = 0;
fcc31cb6 755 struct kvec iov;
766fdbb5
JL
756
757 cFYI(1, "In echo request");
758
759 rc = small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb);
760 if (rc)
761 return rc;
762
763 /* set up echo request */
5443d130 764 smb->hdr.Tid = 0xffff;
99d86c8f
JL
765 smb->hdr.WordCount = 1;
766 put_unaligned_le16(1, &smb->EchoCount);
820a803f 767 put_bcc(1, &smb->hdr);
766fdbb5 768 smb->Data[0] = 'a';
be8e3b00 769 inc_rfc1001_len(smb, 3);
fcc31cb6
JL
770 iov.iov_base = smb;
771 iov.iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
766fdbb5 772
44d22d84 773 rc = cifs_call_async(server, &iov, 1, NULL, cifs_echo_callback,
a891f0f8 774 server, CIFS_ASYNC_OP | CIFS_ECHO_OP);
766fdbb5
JL
775 if (rc)
776 cFYI(1, "Echo request failed: %d", rc);
777
778 cifs_small_buf_release(smb);
779
780 return rc;
781}
782
1da177e4 783int
96daf2b0 784CIFSSMBLogoff(const int xid, struct cifs_ses *ses)
1da177e4 785{
1da177e4
LT
786 LOGOFF_ANDX_REQ *pSMB;
787 int rc = 0;
1da177e4 788
b6b38f70 789 cFYI(1, "In SMBLogoff for session disconnect");
3b795210 790
14fbf50d
JL
791 /*
792 * BB: do we need to check validity of ses and server? They should
793 * always be valid since we have an active reference. If not, that
794 * should probably be a BUG()
795 */
796 if (!ses || !ses->server)
3b795210
SF
797 return -EIO;
798
d7b619cf 799 mutex_lock(&ses->session_mutex);
3b795210
SF
800 if (ses->need_reconnect)
801 goto session_already_dead; /* no need to send SMBlogoff if uid
802 already closed due to reconnect */
1da177e4
LT
803 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
804 if (rc) {
d7b619cf 805 mutex_unlock(&ses->session_mutex);
1da177e4
LT
806 return rc;
807 }
808
88257360 809 pSMB->hdr.Mid = get_next_mid(ses->server);
1982c344 810
96daf2b0 811 if (ses->server->sec_mode &
1da177e4
LT
812 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
813 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
1da177e4
LT
814
815 pSMB->hdr.Uid = ses->Suid;
816
817 pSMB->AndXCommand = 0xFF;
792af7b0 818 rc = SendReceiveNoRsp(xid, ses, (char *) pSMB, 0);
3b795210 819session_already_dead:
d7b619cf 820 mutex_unlock(&ses->session_mutex);
1da177e4
LT
821
822 /* if session dead then we do not need to do ulogoff,
50c2f753 823 since server closed smb session, no sense reporting
1da177e4
LT
824 error */
825 if (rc == -EAGAIN)
826 rc = 0;
827 return rc;
828}
829
2d785a50 830int
96daf2b0 831CIFSPOSIXDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
2d785a50
SF
832 __u16 type, const struct nls_table *nls_codepage, int remap)
833{
834 TRANSACTION2_SPI_REQ *pSMB = NULL;
835 TRANSACTION2_SPI_RSP *pSMBr = NULL;
836 struct unlink_psx_rq *pRqD;
837 int name_len;
838 int rc = 0;
839 int bytes_returned = 0;
840 __u16 params, param_offset, offset, byte_count;
841
b6b38f70 842 cFYI(1, "In POSIX delete");
2d785a50
SF
843PsxDelete:
844 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
845 (void **) &pSMBr);
846 if (rc)
847 return rc;
848
849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
850 name_len =
acbbb76a
SF
851 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
852 PATH_MAX, nls_codepage, remap);
2d785a50
SF
853 name_len++; /* trailing null */
854 name_len *= 2;
855 } else { /* BB add path length overrun check */
856 name_len = strnlen(fileName, PATH_MAX);
857 name_len++; /* trailing null */
858 strncpy(pSMB->FileName, fileName, name_len);
859 }
860
861 params = 6 + name_len;
862 pSMB->MaxParameterCount = cpu_to_le16(2);
863 pSMB->MaxDataCount = 0; /* BB double check this with jra */
864 pSMB->MaxSetupCount = 0;
865 pSMB->Reserved = 0;
866 pSMB->Flags = 0;
867 pSMB->Timeout = 0;
868 pSMB->Reserved2 = 0;
869 param_offset = offsetof(struct smb_com_transaction2_spi_req,
870 InformationLevel) - 4;
871 offset = param_offset + params;
872
873 /* Setup pointer to Request Data (inode type) */
874 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
875 pRqD->type = cpu_to_le16(type);
876 pSMB->ParameterOffset = cpu_to_le16(param_offset);
877 pSMB->DataOffset = cpu_to_le16(offset);
878 pSMB->SetupCount = 1;
879 pSMB->Reserved3 = 0;
880 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
881 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
882
883 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
884 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
885 pSMB->ParameterCount = cpu_to_le16(params);
886 pSMB->TotalParameterCount = pSMB->ParameterCount;
887 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
888 pSMB->Reserved4 = 0;
be8e3b00 889 inc_rfc1001_len(pSMB, byte_count);
2d785a50
SF
890 pSMB->ByteCount = cpu_to_le16(byte_count);
891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 893 if (rc)
b6b38f70 894 cFYI(1, "Posix delete returned %d", rc);
2d785a50
SF
895 cifs_buf_release(pSMB);
896
897 cifs_stats_inc(&tcon->num_deletes);
898
899 if (rc == -EAGAIN)
900 goto PsxDelete;
901
902 return rc;
903}
904
1da177e4 905int
96daf2b0 906CIFSSMBDelFile(const int xid, struct cifs_tcon *tcon, const char *fileName,
737b758c 907 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
908{
909 DELETE_FILE_REQ *pSMB = NULL;
910 DELETE_FILE_RSP *pSMBr = NULL;
911 int rc = 0;
912 int bytes_returned;
913 int name_len;
914
915DelFileRetry:
916 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
917 (void **) &pSMBr);
918 if (rc)
919 return rc;
920
921 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
922 name_len =
acbbb76a
SF
923 cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
924 PATH_MAX, nls_codepage, remap);
1da177e4
LT
925 name_len++; /* trailing null */
926 name_len *= 2;
09d1db5c 927 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
928 name_len = strnlen(fileName, PATH_MAX);
929 name_len++; /* trailing null */
930 strncpy(pSMB->fileName, fileName, name_len);
931 }
932 pSMB->SearchAttributes =
933 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
934 pSMB->BufferFormat = 0x04;
be8e3b00 935 inc_rfc1001_len(pSMB, name_len + 1);
1da177e4
LT
936 pSMB->ByteCount = cpu_to_le16(name_len + 1);
937 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
938 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 939 cifs_stats_inc(&tcon->num_deletes);
ad7a2926 940 if (rc)
b6b38f70 941 cFYI(1, "Error in RMFile = %d", rc);
1da177e4
LT
942
943 cifs_buf_release(pSMB);
944 if (rc == -EAGAIN)
945 goto DelFileRetry;
946
947 return rc;
948}
949
950int
96daf2b0 951CIFSSMBRmDir(const int xid, struct cifs_tcon *tcon, const char *dirName,
737b758c 952 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
953{
954 DELETE_DIRECTORY_REQ *pSMB = NULL;
955 DELETE_DIRECTORY_RSP *pSMBr = NULL;
956 int rc = 0;
957 int bytes_returned;
958 int name_len;
959
b6b38f70 960 cFYI(1, "In CIFSSMBRmDir");
1da177e4
LT
961RmDirRetry:
962 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
963 (void **) &pSMBr);
964 if (rc)
965 return rc;
966
967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
acbbb76a
SF
968 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
969 PATH_MAX, nls_codepage, remap);
1da177e4
LT
970 name_len++; /* trailing null */
971 name_len *= 2;
09d1db5c 972 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
973 name_len = strnlen(dirName, PATH_MAX);
974 name_len++; /* trailing null */
975 strncpy(pSMB->DirName, dirName, name_len);
976 }
977
978 pSMB->BufferFormat = 0x04;
be8e3b00 979 inc_rfc1001_len(pSMB, name_len + 1);
1da177e4
LT
980 pSMB->ByteCount = cpu_to_le16(name_len + 1);
981 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
982 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 983 cifs_stats_inc(&tcon->num_rmdirs);
ad7a2926 984 if (rc)
b6b38f70 985 cFYI(1, "Error in RMDir = %d", rc);
1da177e4
LT
986
987 cifs_buf_release(pSMB);
988 if (rc == -EAGAIN)
989 goto RmDirRetry;
990 return rc;
991}
992
993int
96daf2b0 994CIFSSMBMkDir(const int xid, struct cifs_tcon *tcon,
737b758c 995 const char *name, const struct nls_table *nls_codepage, int remap)
1da177e4
LT
996{
997 int rc = 0;
998 CREATE_DIRECTORY_REQ *pSMB = NULL;
999 CREATE_DIRECTORY_RSP *pSMBr = NULL;
1000 int bytes_returned;
1001 int name_len;
1002
b6b38f70 1003 cFYI(1, "In CIFSSMBMkDir");
1da177e4
LT
1004MkDirRetry:
1005 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1006 (void **) &pSMBr);
1007 if (rc)
1008 return rc;
1009
1010 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
acbbb76a
SF
1011 name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
1012 PATH_MAX, nls_codepage, remap);
1da177e4
LT
1013 name_len++; /* trailing null */
1014 name_len *= 2;
09d1db5c 1015 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
1016 name_len = strnlen(name, PATH_MAX);
1017 name_len++; /* trailing null */
1018 strncpy(pSMB->DirName, name, name_len);
1019 }
1020
1021 pSMB->BufferFormat = 0x04;
be8e3b00 1022 inc_rfc1001_len(pSMB, name_len + 1);
1da177e4
LT
1023 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 1026 cifs_stats_inc(&tcon->num_mkdirs);
ad7a2926 1027 if (rc)
b6b38f70 1028 cFYI(1, "Error in Mkdir = %d", rc);
a5a2b489 1029
1da177e4
LT
1030 cifs_buf_release(pSMB);
1031 if (rc == -EAGAIN)
1032 goto MkDirRetry;
1033 return rc;
1034}
1035
2dd29d31 1036int
96daf2b0 1037CIFSPOSIXCreate(const int xid, struct cifs_tcon *tcon, __u32 posix_flags,
ad7a2926 1038 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
50c2f753 1039 __u32 *pOplock, const char *name,
2dd29d31
SF
1040 const struct nls_table *nls_codepage, int remap)
1041{
1042 TRANSACTION2_SPI_REQ *pSMB = NULL;
1043 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1044 int name_len;
1045 int rc = 0;
1046 int bytes_returned = 0;
2dd29d31 1047 __u16 params, param_offset, offset, byte_count, count;
ad7a2926
SF
1048 OPEN_PSX_REQ *pdata;
1049 OPEN_PSX_RSP *psx_rsp;
2dd29d31 1050
b6b38f70 1051 cFYI(1, "In POSIX Create");
2dd29d31
SF
1052PsxCreat:
1053 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1054 (void **) &pSMBr);
1055 if (rc)
1056 return rc;
1057
1058 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1059 name_len =
acbbb76a
SF
1060 cifsConvertToUTF16((__le16 *) pSMB->FileName, name,
1061 PATH_MAX, nls_codepage, remap);
2dd29d31
SF
1062 name_len++; /* trailing null */
1063 name_len *= 2;
1064 } else { /* BB improve the check for buffer overruns BB */
1065 name_len = strnlen(name, PATH_MAX);
1066 name_len++; /* trailing null */
1067 strncpy(pSMB->FileName, name, name_len);
1068 }
1069
1070 params = 6 + name_len;
1071 count = sizeof(OPEN_PSX_REQ);
1072 pSMB->MaxParameterCount = cpu_to_le16(2);
1073 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1074 pSMB->MaxSetupCount = 0;
1075 pSMB->Reserved = 0;
1076 pSMB->Flags = 0;
1077 pSMB->Timeout = 0;
1078 pSMB->Reserved2 = 0;
1079 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 1080 InformationLevel) - 4;
2dd29d31 1081 offset = param_offset + params;
2dd29d31 1082 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
8f2376ad 1083 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2dd29d31 1084 pdata->Permissions = cpu_to_le64(mode);
50c2f753 1085 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
2dd29d31
SF
1086 pdata->OpenFlags = cpu_to_le32(*pOplock);
1087 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1088 pSMB->DataOffset = cpu_to_le16(offset);
1089 pSMB->SetupCount = 1;
1090 pSMB->Reserved3 = 0;
1091 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1092 byte_count = 3 /* pad */ + params + count;
1093
1094 pSMB->DataCount = cpu_to_le16(count);
1095 pSMB->ParameterCount = cpu_to_le16(params);
1096 pSMB->TotalDataCount = pSMB->DataCount;
1097 pSMB->TotalParameterCount = pSMB->ParameterCount;
1098 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1099 pSMB->Reserved4 = 0;
be8e3b00 1100 inc_rfc1001_len(pSMB, byte_count);
2dd29d31
SF
1101 pSMB->ByteCount = cpu_to_le16(byte_count);
1102 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1103 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1104 if (rc) {
b6b38f70 1105 cFYI(1, "Posix create returned %d", rc);
2dd29d31
SF
1106 goto psx_create_err;
1107 }
1108
b6b38f70 1109 cFYI(1, "copying inode info");
2dd29d31
SF
1110 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1111
820a803f 1112 if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) {
2dd29d31
SF
1113 rc = -EIO; /* bad smb */
1114 goto psx_create_err;
1115 }
1116
1117 /* copy return information to pRetData */
50c2f753 1118 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
2dd29d31 1119 + le16_to_cpu(pSMBr->t2.DataOffset));
50c2f753 1120
2dd29d31 1121 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
790fe579 1122 if (netfid)
2dd29d31
SF
1123 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1124 /* Let caller know file was created so we can set the mode. */
1125 /* Do we care about the CreateAction in any other cases? */
790fe579 1126 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
2dd29d31
SF
1127 *pOplock |= CIFS_CREATE_ACTION;
1128 /* check to make sure response data is there */
8f2376ad
CG
1129 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1130 pRetData->Type = cpu_to_le32(-1); /* unknown */
b6b38f70 1131 cFYI(DBG2, "unknown type");
cbac3cba 1132 } else {
820a803f 1133 if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)
2dd29d31 1134 + sizeof(FILE_UNIX_BASIC_INFO)) {
b6b38f70 1135 cERROR(1, "Open response data too small");
8f2376ad 1136 pRetData->Type = cpu_to_le32(-1);
2dd29d31
SF
1137 goto psx_create_err;
1138 }
50c2f753 1139 memcpy((char *) pRetData,
cbac3cba 1140 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
26f57364 1141 sizeof(FILE_UNIX_BASIC_INFO));
2dd29d31 1142 }
2dd29d31
SF
1143
1144psx_create_err:
1145 cifs_buf_release(pSMB);
1146
65bc98b0
SF
1147 if (posix_flags & SMB_O_DIRECTORY)
1148 cifs_stats_inc(&tcon->num_posixmkdirs);
1149 else
1150 cifs_stats_inc(&tcon->num_posixopens);
2dd29d31
SF
1151
1152 if (rc == -EAGAIN)
1153 goto PsxCreat;
1154
50c2f753 1155 return rc;
2dd29d31
SF
1156}
1157
a9d02ad4
SF
1158static __u16 convert_disposition(int disposition)
1159{
1160 __u16 ofun = 0;
1161
1162 switch (disposition) {
1163 case FILE_SUPERSEDE:
1164 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1165 break;
1166 case FILE_OPEN:
1167 ofun = SMBOPEN_OAPPEND;
1168 break;
1169 case FILE_CREATE:
1170 ofun = SMBOPEN_OCREATE;
1171 break;
1172 case FILE_OPEN_IF:
1173 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1174 break;
1175 case FILE_OVERWRITE:
1176 ofun = SMBOPEN_OTRUNC;
1177 break;
1178 case FILE_OVERWRITE_IF:
1179 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1180 break;
1181 default:
b6b38f70 1182 cFYI(1, "unknown disposition %d", disposition);
a9d02ad4
SF
1183 ofun = SMBOPEN_OAPPEND; /* regular open */
1184 }
1185 return ofun;
1186}
1187
35fc37d5
JL
1188static int
1189access_flags_to_smbopen_mode(const int access_flags)
1190{
1191 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1192
1193 if (masked_flags == GENERIC_READ)
1194 return SMBOPEN_READ;
1195 else if (masked_flags == GENERIC_WRITE)
1196 return SMBOPEN_WRITE;
1197
1198 /* just go for read/write */
1199 return SMBOPEN_READWRITE;
1200}
1201
a9d02ad4 1202int
96daf2b0 1203SMBLegacyOpen(const int xid, struct cifs_tcon *tcon,
a9d02ad4 1204 const char *fileName, const int openDisposition,
ad7a2926
SF
1205 const int access_flags, const int create_options, __u16 *netfid,
1206 int *pOplock, FILE_ALL_INFO *pfile_info,
a9d02ad4
SF
1207 const struct nls_table *nls_codepage, int remap)
1208{
1209 int rc = -EACCES;
1210 OPENX_REQ *pSMB = NULL;
1211 OPENX_RSP *pSMBr = NULL;
1212 int bytes_returned;
1213 int name_len;
1214 __u16 count;
1215
1216OldOpenRetry:
1217 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1218 (void **) &pSMBr);
1219 if (rc)
1220 return rc;
1221
1222 pSMB->AndXCommand = 0xFF; /* none */
1223
1224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1225 count = 1; /* account for one byte pad to word boundary */
1226 name_len =
acbbb76a
SF
1227 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1228 fileName, PATH_MAX, nls_codepage, remap);
a9d02ad4
SF
1229 name_len++; /* trailing null */
1230 name_len *= 2;
1231 } else { /* BB improve check for buffer overruns BB */
1232 count = 0; /* no pad */
1233 name_len = strnlen(fileName, PATH_MAX);
1234 name_len++; /* trailing null */
1235 strncpy(pSMB->fileName, fileName, name_len);
1236 }
1237 if (*pOplock & REQ_OPLOCK)
1238 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
26f57364 1239 else if (*pOplock & REQ_BATCHOPLOCK)
a9d02ad4 1240 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
26f57364 1241
a9d02ad4 1242 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
35fc37d5 1243 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
a9d02ad4
SF
1244 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1245 /* set file as system file if special file such
1246 as fifo and server expecting SFU style and
1247 no Unix extensions */
1248
790fe579
SF
1249 if (create_options & CREATE_OPTION_SPECIAL)
1250 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
ad7a2926
SF
1251 else /* BB FIXME BB */
1252 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
a9d02ad4 1253
67750fb9
JL
1254 if (create_options & CREATE_OPTION_READONLY)
1255 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
a9d02ad4
SF
1256
1257 /* BB FIXME BB */
50c2f753
SF
1258/* pSMB->CreateOptions = cpu_to_le32(create_options &
1259 CREATE_OPTIONS_MASK); */
a9d02ad4 1260 /* BB FIXME END BB */
3e87d803
SF
1261
1262 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
70ca734a 1263 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
a9d02ad4 1264 count += name_len;
be8e3b00 1265 inc_rfc1001_len(pSMB, count);
a9d02ad4
SF
1266
1267 pSMB->ByteCount = cpu_to_le16(count);
1268 /* long_op set to 1 to allow for oplock break timeouts */
1269 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
7749981e 1270 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
a9d02ad4
SF
1271 cifs_stats_inc(&tcon->num_opens);
1272 if (rc) {
b6b38f70 1273 cFYI(1, "Error in Open = %d", rc);
a9d02ad4
SF
1274 } else {
1275 /* BB verify if wct == 15 */
1276
582d21e5 1277/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
a9d02ad4
SF
1278
1279 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1280 /* Let caller know file was created so we can set the mode. */
1281 /* Do we care about the CreateAction in any other cases? */
1282 /* BB FIXME BB */
790fe579 1283/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
a9d02ad4
SF
1284 *pOplock |= CIFS_CREATE_ACTION; */
1285 /* BB FIXME END */
1286
790fe579 1287 if (pfile_info) {
a9d02ad4
SF
1288 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1289 pfile_info->LastAccessTime = 0; /* BB fixme */
1290 pfile_info->LastWriteTime = 0; /* BB fixme */
1291 pfile_info->ChangeTime = 0; /* BB fixme */
70ca734a 1292 pfile_info->Attributes =
50c2f753 1293 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
a9d02ad4 1294 /* the file_info buf is endian converted by caller */
70ca734a
SF
1295 pfile_info->AllocationSize =
1296 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1297 pfile_info->EndOfFile = pfile_info->AllocationSize;
a9d02ad4 1298 pfile_info->NumberOfLinks = cpu_to_le32(1);
9a8165fc 1299 pfile_info->DeletePending = 0;
a9d02ad4
SF
1300 }
1301 }
1302
1303 cifs_buf_release(pSMB);
1304 if (rc == -EAGAIN)
1305 goto OldOpenRetry;
1306 return rc;
1307}
1308
1da177e4 1309int
96daf2b0 1310CIFSSMBOpen(const int xid, struct cifs_tcon *tcon,
1da177e4 1311 const char *fileName, const int openDisposition,
ad7a2926
SF
1312 const int access_flags, const int create_options, __u16 *netfid,
1313 int *pOplock, FILE_ALL_INFO *pfile_info,
737b758c 1314 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
1315{
1316 int rc = -EACCES;
1317 OPEN_REQ *pSMB = NULL;
1318 OPEN_RSP *pSMBr = NULL;
1319 int bytes_returned;
1320 int name_len;
1321 __u16 count;
1322
1323openRetry:
1324 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1325 (void **) &pSMBr);
1326 if (rc)
1327 return rc;
1328
1329 pSMB->AndXCommand = 0xFF; /* none */
1330
1331 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1332 count = 1; /* account for one byte pad to word boundary */
1333 name_len =
acbbb76a
SF
1334 cifsConvertToUTF16((__le16 *) (pSMB->fileName + 1),
1335 fileName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
1336 name_len++; /* trailing null */
1337 name_len *= 2;
1338 pSMB->NameLength = cpu_to_le16(name_len);
09d1db5c 1339 } else { /* BB improve check for buffer overruns BB */
1da177e4
LT
1340 count = 0; /* no pad */
1341 name_len = strnlen(fileName, PATH_MAX);
1342 name_len++; /* trailing null */
1343 pSMB->NameLength = cpu_to_le16(name_len);
1344 strncpy(pSMB->fileName, fileName, name_len);
1345 }
1346 if (*pOplock & REQ_OPLOCK)
1347 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
26f57364 1348 else if (*pOplock & REQ_BATCHOPLOCK)
1da177e4 1349 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1da177e4
LT
1350 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1351 pSMB->AllocationSize = 0;
eda3c029
SF
1352 /* set file as system file if special file such
1353 as fifo and server expecting SFU style and
1354 no Unix extensions */
790fe579 1355 if (create_options & CREATE_OPTION_SPECIAL)
eda3c029
SF
1356 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1357 else
1358 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
67750fb9 1359
1da177e4
LT
1360 /* XP does not handle ATTR_POSIX_SEMANTICS */
1361 /* but it helps speed up case sensitive checks for other
1362 servers such as Samba */
1363 if (tcon->ses->capabilities & CAP_UNIX)
1364 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1365
67750fb9
JL
1366 if (create_options & CREATE_OPTION_READONLY)
1367 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1368
1da177e4
LT
1369 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1370 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
eda3c029 1371 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
09d1db5c
SF
1372 /* BB Expirement with various impersonation levels and verify */
1373 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
1da177e4
LT
1374 pSMB->SecurityFlags =
1375 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1376
1377 count += name_len;
be8e3b00 1378 inc_rfc1001_len(pSMB, count);
1da177e4
LT
1379
1380 pSMB->ByteCount = cpu_to_le16(count);
1381 /* long_op set to 1 to allow for oplock break timeouts */
1382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
7749981e 1383 (struct smb_hdr *)pSMBr, &bytes_returned, 0);
a4544347 1384 cifs_stats_inc(&tcon->num_opens);
1da177e4 1385 if (rc) {
b6b38f70 1386 cFYI(1, "Error in Open = %d", rc);
1da177e4 1387 } else {
09d1db5c 1388 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
1da177e4
LT
1389 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1390 /* Let caller know file was created so we can set the mode. */
1391 /* Do we care about the CreateAction in any other cases? */
790fe579 1392 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
50c2f753 1393 *pOplock |= CIFS_CREATE_ACTION;
790fe579 1394 if (pfile_info) {
61e74801
SF
1395 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1396 36 /* CreationTime to Attributes */);
1397 /* the file_info buf is endian converted by caller */
1398 pfile_info->AllocationSize = pSMBr->AllocationSize;
1399 pfile_info->EndOfFile = pSMBr->EndOfFile;
1400 pfile_info->NumberOfLinks = cpu_to_le32(1);
1401 pfile_info->DeletePending = 0;
1da177e4 1402 }
1da177e4 1403 }
a5a2b489 1404
1da177e4
LT
1405 cifs_buf_release(pSMB);
1406 if (rc == -EAGAIN)
1407 goto openRetry;
1408 return rc;
1409}
1410
e28bc5b1
JL
1411/*
1412 * Discard any remaining data in the current SMB. To do this, we borrow the
1413 * current bigbuf.
1414 */
1415static int
1416cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1417{
5ffef7bf 1418 unsigned int rfclen = get_rfc1002_length(server->smallbuf);
e28bc5b1
JL
1419 int remaining = rfclen + 4 - server->total_read;
1420 struct cifs_readdata *rdata = mid->callback_data;
1421
1422 while (remaining > 0) {
1423 int length;
1424
1425 length = cifs_read_from_socket(server, server->bigbuf,
1426 min_t(unsigned int, remaining,
1887f601 1427 CIFSMaxBufSize + MAX_HEADER_SIZE(server)));
e28bc5b1
JL
1428 if (length < 0)
1429 return length;
1430 server->total_read += length;
1431 remaining -= length;
1432 }
1433
1434 dequeue_mid(mid, rdata->result);
1435 return 0;
1436}
1437
1438static int
1439cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
1440{
1441 int length, len;
8d5ce4d2 1442 unsigned int data_offset, data_len;
e28bc5b1 1443 struct cifs_readdata *rdata = mid->callback_data;
5ffef7bf
PS
1444 char *buf = server->smallbuf;
1445 unsigned int buflen = get_rfc1002_length(buf) + 4;
e28bc5b1 1446
7c9421e1 1447 cFYI(1, "%s: mid=%llu offset=%llu bytes=%u", __func__,
e28bc5b1
JL
1448 mid->mid, rdata->offset, rdata->bytes);
1449
1450 /*
1451 * read the rest of READ_RSP header (sans Data array), or whatever we
1452 * can if there's not enough data. At this point, we've read down to
1453 * the Mid.
1454 */
eb378711 1455 len = min_t(unsigned int, buflen, server->vals->read_rsp_size) -
1887f601 1456 HEADER_SIZE(server) + 1;
e28bc5b1 1457
1887f601 1458 rdata->iov[0].iov_base = buf + HEADER_SIZE(server) - 1;
e28bc5b1
JL
1459 rdata->iov[0].iov_len = len;
1460
1461 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1462 if (length < 0)
1463 return length;
1464 server->total_read += length;
1465
1466 /* Was the SMB read successful? */
eb378711 1467 rdata->result = server->ops->map_error(buf, false);
e28bc5b1
JL
1468 if (rdata->result != 0) {
1469 cFYI(1, "%s: server returned error %d", __func__,
1470 rdata->result);
1471 return cifs_readv_discard(server, mid);
1472 }
1473
1474 /* Is there enough to get to the rest of the READ_RSP header? */
eb378711 1475 if (server->total_read < server->vals->read_rsp_size) {
e28bc5b1 1476 cFYI(1, "%s: server returned short header. got=%u expected=%zu",
eb378711
PS
1477 __func__, server->total_read,
1478 server->vals->read_rsp_size);
e28bc5b1
JL
1479 rdata->result = -EIO;
1480 return cifs_readv_discard(server, mid);
1481 }
1482
eb378711 1483 data_offset = server->ops->read_data_offset(buf) + 4;
e28bc5b1
JL
1484 if (data_offset < server->total_read) {
1485 /*
1486 * win2k8 sometimes sends an offset of 0 when the read
1487 * is beyond the EOF. Treat it as if the data starts just after
1488 * the header.
1489 */
1490 cFYI(1, "%s: data offset (%u) inside read response header",
1491 __func__, data_offset);
1492 data_offset = server->total_read;
1493 } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
1494 /* data_offset is beyond the end of smallbuf */
1495 cFYI(1, "%s: data offset (%u) beyond end of smallbuf",
1496 __func__, data_offset);
1497 rdata->result = -EIO;
1498 return cifs_readv_discard(server, mid);
1499 }
1500
1501 cFYI(1, "%s: total_read=%u data_offset=%u", __func__,
1502 server->total_read, data_offset);
1503
1504 len = data_offset - server->total_read;
1505 if (len > 0) {
1506 /* read any junk before data into the rest of smallbuf */
5ffef7bf 1507 rdata->iov[0].iov_base = buf + server->total_read;
e28bc5b1
JL
1508 rdata->iov[0].iov_len = len;
1509 length = cifs_readv_from_socket(server, rdata->iov, 1, len);
1510 if (length < 0)
1511 return length;
1512 server->total_read += length;
1513 }
1514
1515 /* set up first iov for signature check */
5ffef7bf 1516 rdata->iov[0].iov_base = buf;
e28bc5b1
JL
1517 rdata->iov[0].iov_len = server->total_read;
1518 cFYI(1, "0: iov_base=%p iov_len=%zu",
1519 rdata->iov[0].iov_base, rdata->iov[0].iov_len);
1520
1521 /* how much data is in the response? */
eb378711 1522 data_len = server->ops->read_data_length(buf);
5ffef7bf 1523 if (data_offset + data_len > buflen) {
e28bc5b1
JL
1524 /* data_len is corrupt -- discard frame */
1525 rdata->result = -EIO;
1526 return cifs_readv_discard(server, mid);
1527 }
1528
1529 /* marshal up the page array */
3cf003c0 1530 cifs_kmap_lock();
8d5ce4d2 1531 len = rdata->marshal_iov(rdata, data_len);
3cf003c0 1532 cifs_kmap_unlock();
8d5ce4d2 1533 data_len -= len;
e28bc5b1
JL
1534
1535 /* issue the read if we have any iovecs left to fill */
1536 if (rdata->nr_iov > 1) {
1537 length = cifs_readv_from_socket(server, &rdata->iov[1],
1538 rdata->nr_iov - 1, len);
1539 if (length < 0)
1540 return length;
1541 server->total_read += length;
1542 } else {
1543 length = 0;
1544 }
1545
1546 rdata->bytes = length;
1547
5ffef7bf 1548 cFYI(1, "total_read=%u buflen=%u remaining=%u", server->total_read,
8d5ce4d2 1549 buflen, data_len);
e28bc5b1
JL
1550
1551 /* discard anything left over */
5ffef7bf 1552 if (server->total_read < buflen)
e28bc5b1
JL
1553 return cifs_readv_discard(server, mid);
1554
1555 dequeue_mid(mid, false);
1556 return length;
1557}
1558
e28bc5b1
JL
1559static void
1560cifs_readv_callback(struct mid_q_entry *mid)
1561{
1562 struct cifs_readdata *rdata = mid->callback_data;
1563 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1564 struct TCP_Server_Info *server = tcon->ses->server;
1565
7c9421e1
PS
1566 cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
1567 mid->mid, mid->mid_state, rdata->result, rdata->bytes);
e28bc5b1 1568
7c9421e1 1569 switch (mid->mid_state) {
e28bc5b1
JL
1570 case MID_RESPONSE_RECEIVED:
1571 /* result already set, check signature */
1572 if (server->sec_mode &
1573 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
1574 if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
1575 server, mid->sequence_number + 1))
1576 cERROR(1, "Unexpected SMB signature");
1577 }
1578 /* FIXME: should this be counted toward the initiating task? */
1579 task_io_account_read(rdata->bytes);
1580 cifs_stats_bytes_read(tcon, rdata->bytes);
1581 break;
1582 case MID_REQUEST_SUBMITTED:
1583 case MID_RETRY_NEEDED:
1584 rdata->result = -EAGAIN;
1585 break;
1586 default:
1587 rdata->result = -EIO;
1588 }
1589
da472fc8 1590 queue_work(cifsiod_wq, &rdata->work);
e28bc5b1 1591 DeleteMidQEntry(mid);
a891f0f8 1592 add_credits(server, 1, 0);
e28bc5b1
JL
1593}
1594
1595/* cifs_async_readv - send an async write, and set up mid to handle result */
1596int
1597cifs_async_readv(struct cifs_readdata *rdata)
1598{
1599 int rc;
1600 READ_REQ *smb = NULL;
1601 int wct;
1602 struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
1603
1604 cFYI(1, "%s: offset=%llu bytes=%u", __func__,
1605 rdata->offset, rdata->bytes);
1606
1607 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1608 wct = 12;
1609 else {
1610 wct = 10; /* old style read */
1611 if ((rdata->offset >> 32) > 0) {
1612 /* can not handle this big offset for old */
1613 return -EIO;
1614 }
1615 }
1616
1617 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb);
1618 if (rc)
1619 return rc;
1620
1621 smb->hdr.Pid = cpu_to_le16((__u16)rdata->pid);
1622 smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
1623
1624 smb->AndXCommand = 0xFF; /* none */
1625 smb->Fid = rdata->cfile->netfid;
1626 smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
1627 if (wct == 12)
1628 smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
1629 smb->Remaining = 0;
1630 smb->MaxCount = cpu_to_le16(rdata->bytes & 0xFFFF);
1631 smb->MaxCountHigh = cpu_to_le32(rdata->bytes >> 16);
1632 if (wct == 12)
1633 smb->ByteCount = 0;
1634 else {
1635 /* old style read */
1636 struct smb_com_readx_req *smbr =
1637 (struct smb_com_readx_req *)smb;
1638 smbr->ByteCount = 0;
1639 }
1640
1641 /* 4 for RFC1001 length + 1 for BCC */
1642 rdata->iov[0].iov_base = smb;
1643 rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
1644
6993f74a 1645 kref_get(&rdata->refcount);
e28bc5b1
JL
1646 rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
1647 cifs_readv_receive, cifs_readv_callback,
a891f0f8 1648 rdata, 0);
e28bc5b1
JL
1649
1650 if (rc == 0)
1651 cifs_stats_inc(&tcon->num_reads);
6993f74a
JL
1652 else
1653 kref_put(&rdata->refcount, cifs_readdata_release);
e28bc5b1
JL
1654
1655 cifs_small_buf_release(smb);
1656 return rc;
1657}
1658
1da177e4 1659int
d4ffff1f 1660CIFSSMBRead(const int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes,
50c2f753 1661 char **buf, int *pbuf_type)
1da177e4
LT
1662{
1663 int rc = -EACCES;
1664 READ_REQ *pSMB = NULL;
1665 READ_RSP *pSMBr = NULL;
1666 char *pReadData = NULL;
bfa0d75a 1667 int wct;
ec637e3f
SF
1668 int resp_buf_type = 0;
1669 struct kvec iov[1];
d4ffff1f
PS
1670 __u32 pid = io_parms->pid;
1671 __u16 netfid = io_parms->netfid;
1672 __u64 offset = io_parms->offset;
96daf2b0 1673 struct cifs_tcon *tcon = io_parms->tcon;
d4ffff1f 1674 unsigned int count = io_parms->length;
1da177e4 1675
b6b38f70 1676 cFYI(1, "Reading %d bytes on fid %d", count, netfid);
790fe579 1677 if (tcon->ses->capabilities & CAP_LARGE_FILES)
bfa0d75a 1678 wct = 12;
4c3130ef 1679 else {
bfa0d75a 1680 wct = 10; /* old style read */
d4ffff1f 1681 if ((offset >> 32) > 0) {
4c3130ef
SF
1682 /* can not handle this big offset for old */
1683 return -EIO;
1684 }
1685 }
1da177e4
LT
1686
1687 *nbytes = 0;
ec637e3f 1688 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
1da177e4
LT
1689 if (rc)
1690 return rc;
1691
d4ffff1f
PS
1692 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1693 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1694
1da177e4
LT
1695 /* tcon and ses pointer are checked in smb_init */
1696 if (tcon->ses->server == NULL)
1697 return -ECONNABORTED;
1698
ec637e3f 1699 pSMB->AndXCommand = 0xFF; /* none */
1da177e4 1700 pSMB->Fid = netfid;
d4ffff1f 1701 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
790fe579 1702 if (wct == 12)
d4ffff1f 1703 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
bfa0d75a 1704
1da177e4
LT
1705 pSMB->Remaining = 0;
1706 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1707 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
790fe579 1708 if (wct == 12)
bfa0d75a
SF
1709 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1710 else {
1711 /* old style read */
50c2f753 1712 struct smb_com_readx_req *pSMBW =
bfa0d75a 1713 (struct smb_com_readx_req *)pSMB;
ec637e3f 1714 pSMBW->ByteCount = 0;
bfa0d75a 1715 }
ec637e3f
SF
1716
1717 iov[0].iov_base = (char *)pSMB;
be8e3b00 1718 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
a761ac57 1719 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
7749981e 1720 &resp_buf_type, CIFS_LOG_ERROR);
a4544347 1721 cifs_stats_inc(&tcon->num_reads);
ec637e3f 1722 pSMBr = (READ_RSP *)iov[0].iov_base;
1da177e4 1723 if (rc) {
b6b38f70 1724 cERROR(1, "Send error in read = %d", rc);
1da177e4
LT
1725 } else {
1726 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1727 data_length = data_length << 16;
1728 data_length += le16_to_cpu(pSMBr->DataLength);
1729 *nbytes = data_length;
1730
1731 /*check that DataLength would not go beyond end of SMB */
ec637e3f 1732 if ((data_length > CIFSMaxBufSize)
1da177e4 1733 || (data_length > count)) {
b6b38f70
JP
1734 cFYI(1, "bad length %d for count %d",
1735 data_length, count);
1da177e4
LT
1736 rc = -EIO;
1737 *nbytes = 0;
1738 } else {
ec637e3f 1739 pReadData = (char *) (&pSMBr->hdr.Protocol) +
26f57364
SF
1740 le16_to_cpu(pSMBr->DataOffset);
1741/* if (rc = copy_to_user(buf, pReadData, data_length)) {
b6b38f70 1742 cERROR(1, "Faulting on read rc = %d",rc);
50c2f753 1743 rc = -EFAULT;
26f57364 1744 }*/ /* can not use copy_to_user when using page cache*/
790fe579 1745 if (*buf)
50c2f753 1746 memcpy(*buf, pReadData, data_length);
1da177e4
LT
1747 }
1748 }
1da177e4 1749
4b8f930f 1750/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
790fe579
SF
1751 if (*buf) {
1752 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1753 cifs_small_buf_release(iov[0].iov_base);
790fe579 1754 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1755 cifs_buf_release(iov[0].iov_base);
790fe579 1756 } else if (resp_buf_type != CIFS_NO_BUFFER) {
50c2f753
SF
1757 /* return buffer to caller to free */
1758 *buf = iov[0].iov_base;
790fe579 1759 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 1760 *pbuf_type = CIFS_SMALL_BUFFER;
790fe579 1761 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 1762 *pbuf_type = CIFS_LARGE_BUFFER;
6cec2aed 1763 } /* else no valid buffer on return - leave as null */
ec637e3f
SF
1764
1765 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1766 since file handle passed in no longer valid */
1767 return rc;
1768}
1769
ec637e3f 1770
1da177e4 1771int
fa2989f4
PS
1772CIFSSMBWrite(const int xid, struct cifs_io_parms *io_parms,
1773 unsigned int *nbytes, const char *buf,
50c2f753 1774 const char __user *ubuf, const int long_op)
1da177e4
LT
1775{
1776 int rc = -EACCES;
1777 WRITE_REQ *pSMB = NULL;
1778 WRITE_RSP *pSMBr = NULL;
1c955187 1779 int bytes_returned, wct;
1da177e4
LT
1780 __u32 bytes_sent;
1781 __u16 byte_count;
fa2989f4
PS
1782 __u32 pid = io_parms->pid;
1783 __u16 netfid = io_parms->netfid;
1784 __u64 offset = io_parms->offset;
96daf2b0 1785 struct cifs_tcon *tcon = io_parms->tcon;
fa2989f4 1786 unsigned int count = io_parms->length;
1da177e4 1787
a24e2d7d
SF
1788 *nbytes = 0;
1789
b6b38f70 1790 /* cFYI(1, "write at %lld %d bytes", offset, count);*/
790fe579 1791 if (tcon->ses == NULL)
1c955187
SF
1792 return -ECONNABORTED;
1793
790fe579 1794 if (tcon->ses->capabilities & CAP_LARGE_FILES)
1c955187 1795 wct = 14;
4c3130ef 1796 else {
1c955187 1797 wct = 12;
4c3130ef
SF
1798 if ((offset >> 32) > 0) {
1799 /* can not handle big offset for old srv */
1800 return -EIO;
1801 }
1802 }
1c955187
SF
1803
1804 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1da177e4
LT
1805 (void **) &pSMBr);
1806 if (rc)
1807 return rc;
fa2989f4
PS
1808
1809 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
1810 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
1811
1da177e4
LT
1812 /* tcon and ses pointer are checked in smb_init */
1813 if (tcon->ses->server == NULL)
1814 return -ECONNABORTED;
1815
1816 pSMB->AndXCommand = 0xFF; /* none */
1817 pSMB->Fid = netfid;
1818 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
790fe579 1819 if (wct == 14)
1c955187 1820 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
50c2f753 1821
1da177e4
LT
1822 pSMB->Reserved = 0xFFFFFFFF;
1823 pSMB->WriteMode = 0;
1824 pSMB->Remaining = 0;
1825
50c2f753 1826 /* Can increase buffer size if buffer is big enough in some cases ie we
1da177e4
LT
1827 can send more if LARGE_WRITE_X capability returned by the server and if
1828 our buffer is big enough or if we convert to iovecs on socket writes
1829 and eliminate the copy to the CIFS buffer */
790fe579 1830 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1da177e4
LT
1831 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1832 } else {
1833 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1834 & ~0xFF;
1835 }
1836
1837 if (bytes_sent > count)
1838 bytes_sent = count;
1839 pSMB->DataOffset =
50c2f753 1840 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
790fe579 1841 if (buf)
61e74801 1842 memcpy(pSMB->Data, buf, bytes_sent);
790fe579
SF
1843 else if (ubuf) {
1844 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
1da177e4
LT
1845 cifs_buf_release(pSMB);
1846 return -EFAULT;
1847 }
e30dcf3a 1848 } else if (count != 0) {
1da177e4
LT
1849 /* No buffer */
1850 cifs_buf_release(pSMB);
1851 return -EINVAL;
e30dcf3a 1852 } /* else setting file size with write of zero bytes */
790fe579 1853 if (wct == 14)
e30dcf3a 1854 byte_count = bytes_sent + 1; /* pad */
ad7a2926 1855 else /* wct == 12 */
e30dcf3a 1856 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
ad7a2926 1857
1da177e4
LT
1858 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1859 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
be8e3b00 1860 inc_rfc1001_len(pSMB, byte_count);
1c955187 1861
790fe579 1862 if (wct == 14)
1c955187 1863 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753
SF
1864 else { /* old style write has byte count 4 bytes earlier
1865 so 4 bytes pad */
1866 struct smb_com_writex_req *pSMBW =
1c955187
SF
1867 (struct smb_com_writex_req *)pSMB;
1868 pSMBW->ByteCount = cpu_to_le16(byte_count);
1869 }
1da177e4
LT
1870
1871 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1872 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
a4544347 1873 cifs_stats_inc(&tcon->num_writes);
1da177e4 1874 if (rc) {
f19159dc 1875 cFYI(1, "Send error in write = %d", rc);
1da177e4
LT
1876 } else {
1877 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1878 *nbytes = (*nbytes) << 16;
1879 *nbytes += le16_to_cpu(pSMBr->Count);
6513a81e
SJ
1880
1881 /*
1882 * Mask off high 16 bits when bytes written as returned by the
1883 * server is greater than bytes requested by the client. Some
1884 * OS/2 servers are known to set incorrect CountHigh values.
1885 */
1886 if (*nbytes > count)
1887 *nbytes &= 0xFFFF;
1da177e4
LT
1888 }
1889
1890 cifs_buf_release(pSMB);
1891
50c2f753 1892 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
1893 since file handle passed in no longer valid */
1894
1895 return rc;
1896}
1897
c28c89fc
JL
1898void
1899cifs_writedata_release(struct kref *refcount)
1900{
1901 struct cifs_writedata *wdata = container_of(refcount,
1902 struct cifs_writedata, refcount);
1903
1904 if (wdata->cfile)
1905 cifsFileInfo_put(wdata->cfile);
1906
1907 kfree(wdata);
1908}
1909
1910/*
1911 * Write failed with a retryable error. Resend the write request. It's also
1912 * possible that the page was redirtied so re-clean the page.
1913 */
1914static void
1915cifs_writev_requeue(struct cifs_writedata *wdata)
1916{
1917 int i, rc;
1918 struct inode *inode = wdata->cfile->dentry->d_inode;
1919
1920 for (i = 0; i < wdata->nr_pages; i++) {
1921 lock_page(wdata->pages[i]);
1922 clear_page_dirty_for_io(wdata->pages[i]);
1923 }
1924
1925 do {
1926 rc = cifs_async_writev(wdata);
1927 } while (rc == -EAGAIN);
1928
1929 for (i = 0; i < wdata->nr_pages; i++) {
1930 if (rc != 0)
1931 SetPageError(wdata->pages[i]);
1932 unlock_page(wdata->pages[i]);
1933 }
1934
1935 mapping_set_error(inode->i_mapping, rc);
1936 kref_put(&wdata->refcount, cifs_writedata_release);
1937}
1938
c2e87640 1939void
c28c89fc
JL
1940cifs_writev_complete(struct work_struct *work)
1941{
1942 struct cifs_writedata *wdata = container_of(work,
1943 struct cifs_writedata, work);
1944 struct inode *inode = wdata->cfile->dentry->d_inode;
1945 int i = 0;
1946
1947 if (wdata->result == 0) {
597b027f 1948 spin_lock(&inode->i_lock);
c28c89fc 1949 cifs_update_eof(CIFS_I(inode), wdata->offset, wdata->bytes);
597b027f 1950 spin_unlock(&inode->i_lock);
c28c89fc
JL
1951 cifs_stats_bytes_written(tlink_tcon(wdata->cfile->tlink),
1952 wdata->bytes);
1953 } else if (wdata->sync_mode == WB_SYNC_ALL && wdata->result == -EAGAIN)
1954 return cifs_writev_requeue(wdata);
1955
1956 for (i = 0; i < wdata->nr_pages; i++) {
1957 struct page *page = wdata->pages[i];
1958 if (wdata->result == -EAGAIN)
1959 __set_page_dirty_nobuffers(page);
1960 else if (wdata->result < 0)
1961 SetPageError(page);
1962 end_page_writeback(page);
1963 page_cache_release(page);
1964 }
1965 if (wdata->result != -EAGAIN)
1966 mapping_set_error(inode->i_mapping, wdata->result);
1967 kref_put(&wdata->refcount, cifs_writedata_release);
1968}
1969
1970struct cifs_writedata *
c2e87640 1971cifs_writedata_alloc(unsigned int nr_pages, work_func_t complete)
c28c89fc
JL
1972{
1973 struct cifs_writedata *wdata;
1974
1975 /* this would overflow */
1976 if (nr_pages == 0) {
1977 cERROR(1, "%s: called with nr_pages == 0!", __func__);
1978 return NULL;
1979 }
1980
1981 /* writedata + number of page pointers */
1982 wdata = kzalloc(sizeof(*wdata) +
1983 sizeof(struct page *) * (nr_pages - 1), GFP_NOFS);
1984 if (wdata != NULL) {
c28c89fc 1985 kref_init(&wdata->refcount);
da82f7e7
JL
1986 INIT_LIST_HEAD(&wdata->list);
1987 init_completion(&wdata->done);
1988 INIT_WORK(&wdata->work, complete);
c28c89fc
JL
1989 }
1990 return wdata;
1991}
1992
1993/*
7c9421e1 1994 * Check the mid_state and signature on received buffer (if any), and queue the
c28c89fc
JL
1995 * workqueue completion task.
1996 */
1997static void
1998cifs_writev_callback(struct mid_q_entry *mid)
1999{
2000 struct cifs_writedata *wdata = mid->callback_data;
96daf2b0 2001 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
c28c89fc
JL
2002 unsigned int written;
2003 WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf;
2004
7c9421e1 2005 switch (mid->mid_state) {
c28c89fc
JL
2006 case MID_RESPONSE_RECEIVED:
2007 wdata->result = cifs_check_receive(mid, tcon->ses->server, 0);
2008 if (wdata->result != 0)
2009 break;
2010
2011 written = le16_to_cpu(smb->CountHigh);
2012 written <<= 16;
2013 written += le16_to_cpu(smb->Count);
2014 /*
2015 * Mask off high 16 bits when bytes written as returned
2016 * by the server is greater than bytes requested by the
2017 * client. OS/2 servers are known to set incorrect
2018 * CountHigh values.
2019 */
2020 if (written > wdata->bytes)
2021 written &= 0xFFFF;
2022
2023 if (written < wdata->bytes)
2024 wdata->result = -ENOSPC;
2025 else
2026 wdata->bytes = written;
2027 break;
2028 case MID_REQUEST_SUBMITTED:
2029 case MID_RETRY_NEEDED:
2030 wdata->result = -EAGAIN;
2031 break;
2032 default:
2033 wdata->result = -EIO;
2034 break;
2035 }
2036
da472fc8 2037 queue_work(cifsiod_wq, &wdata->work);
c28c89fc 2038 DeleteMidQEntry(mid);
a891f0f8 2039 add_credits(tcon->ses->server, 1, 0);
c28c89fc
JL
2040}
2041
2042/* cifs_async_writev - send an async write, and set up mid to handle result */
2043int
2044cifs_async_writev(struct cifs_writedata *wdata)
2045{
2046 int i, rc = -EACCES;
2047 WRITE_REQ *smb = NULL;
2048 int wct;
96daf2b0 2049 struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
c28c89fc
JL
2050 struct kvec *iov = NULL;
2051
2052 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
2053 wct = 14;
2054 } else {
2055 wct = 12;
2056 if (wdata->offset >> 32 > 0) {
2057 /* can not handle big offset for old srv */
2058 return -EIO;
2059 }
2060 }
2061
2062 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&smb);
2063 if (rc)
2064 goto async_writev_out;
2065
2066 /* 1 iov per page + 1 for header */
2067 iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
2068 if (iov == NULL) {
2069 rc = -ENOMEM;
2070 goto async_writev_out;
2071 }
2072
fe5f5d2e
JL
2073 smb->hdr.Pid = cpu_to_le16((__u16)wdata->pid);
2074 smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
fa2989f4 2075
c28c89fc
JL
2076 smb->AndXCommand = 0xFF; /* none */
2077 smb->Fid = wdata->cfile->netfid;
2078 smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
2079 if (wct == 14)
2080 smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
2081 smb->Reserved = 0xFFFFFFFF;
2082 smb->WriteMode = 0;
2083 smb->Remaining = 0;
2084
2085 smb->DataOffset =
2086 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
2087
2088 /* 4 for RFC1001 length + 1 for BCC */
2089 iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4 + 1;
2090 iov[0].iov_base = smb;
2091
e9492871
JL
2092 /*
2093 * This function should marshal up the page array into the kvec
2094 * array, reserving [0] for the header. It should kmap the pages
2095 * and set the iov_len properly for each one. It may also set
2096 * wdata->bytes too.
2097 */
3cf003c0 2098 cifs_kmap_lock();
e9492871 2099 wdata->marshal_iov(iov, wdata);
3cf003c0 2100 cifs_kmap_unlock();
c28c89fc
JL
2101
2102 cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
2103
2104 smb->DataLengthLow = cpu_to_le16(wdata->bytes & 0xFFFF);
2105 smb->DataLengthHigh = cpu_to_le16(wdata->bytes >> 16);
2106
2107 if (wct == 14) {
2108 inc_rfc1001_len(&smb->hdr, wdata->bytes + 1);
2109 put_bcc(wdata->bytes + 1, &smb->hdr);
2110 } else {
2111 /* wct == 12 */
2112 struct smb_com_writex_req *smbw =
2113 (struct smb_com_writex_req *)smb;
2114 inc_rfc1001_len(&smbw->hdr, wdata->bytes + 5);
2115 put_bcc(wdata->bytes + 5, &smbw->hdr);
2116 iov[0].iov_len += 4; /* pad bigger by four bytes */
2117 }
2118
2119 kref_get(&wdata->refcount);
2120 rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
a891f0f8 2121 NULL, cifs_writev_callback, wdata, 0);
c28c89fc
JL
2122
2123 if (rc == 0)
2124 cifs_stats_inc(&tcon->num_writes);
2125 else
2126 kref_put(&wdata->refcount, cifs_writedata_release);
2127
2128 /* send is done, unmap pages */
2129 for (i = 0; i < wdata->nr_pages; i++)
2130 kunmap(wdata->pages[i]);
2131
2132async_writev_out:
2133 cifs_small_buf_release(smb);
2134 kfree(iov);
2135 return rc;
2136}
2137
d6e04ae6 2138int
fa2989f4
PS
2139CIFSSMBWrite2(const int xid, struct cifs_io_parms *io_parms,
2140 unsigned int *nbytes, struct kvec *iov, int n_vec,
2141 const int long_op)
1da177e4
LT
2142{
2143 int rc = -EACCES;
2144 WRITE_REQ *pSMB = NULL;
ec637e3f 2145 int wct;
d6e04ae6 2146 int smb_hdr_len;
ec637e3f 2147 int resp_buf_type = 0;
fa2989f4
PS
2148 __u32 pid = io_parms->pid;
2149 __u16 netfid = io_parms->netfid;
2150 __u64 offset = io_parms->offset;
96daf2b0 2151 struct cifs_tcon *tcon = io_parms->tcon;
fa2989f4 2152 unsigned int count = io_parms->length;
1da177e4 2153
fbec9ab9
JL
2154 *nbytes = 0;
2155
b6b38f70 2156 cFYI(1, "write2 at %lld %d bytes", (long long)offset, count);
ff7feac9 2157
4c3130ef 2158 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
8cc64c6e 2159 wct = 14;
4c3130ef 2160 } else {
8cc64c6e 2161 wct = 12;
4c3130ef
SF
2162 if ((offset >> 32) > 0) {
2163 /* can not handle big offset for old srv */
2164 return -EIO;
2165 }
2166 }
8cc64c6e 2167 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
1da177e4
LT
2168 if (rc)
2169 return rc;
fa2989f4
PS
2170
2171 pSMB->hdr.Pid = cpu_to_le16((__u16)pid);
2172 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid >> 16));
2173
1da177e4
LT
2174 /* tcon and ses pointer are checked in smb_init */
2175 if (tcon->ses->server == NULL)
2176 return -ECONNABORTED;
2177
d6e04ae6 2178 pSMB->AndXCommand = 0xFF; /* none */
1da177e4
LT
2179 pSMB->Fid = netfid;
2180 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
790fe579 2181 if (wct == 14)
8cc64c6e 2182 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1da177e4
LT
2183 pSMB->Reserved = 0xFFFFFFFF;
2184 pSMB->WriteMode = 0;
2185 pSMB->Remaining = 0;
d6e04ae6 2186
1da177e4 2187 pSMB->DataOffset =
50c2f753 2188 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
1da177e4 2189
3e84469d
SF
2190 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
2191 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
be8e3b00
SF
2192 /* header + 1 byte pad */
2193 smb_hdr_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 1;
790fe579 2194 if (wct == 14)
be8e3b00 2195 inc_rfc1001_len(pSMB, count + 1);
8cc64c6e 2196 else /* wct == 12 */
be8e3b00 2197 inc_rfc1001_len(pSMB, count + 5); /* smb data starts later */
790fe579 2198 if (wct == 14)
8cc64c6e
SF
2199 pSMB->ByteCount = cpu_to_le16(count + 1);
2200 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
50c2f753 2201 struct smb_com_writex_req *pSMBW =
8cc64c6e
SF
2202 (struct smb_com_writex_req *)pSMB;
2203 pSMBW->ByteCount = cpu_to_le16(count + 5);
2204 }
3e84469d 2205 iov[0].iov_base = pSMB;
790fe579 2206 if (wct == 14)
ec637e3f
SF
2207 iov[0].iov_len = smb_hdr_len + 4;
2208 else /* wct == 12 pad bigger by four bytes */
2209 iov[0].iov_len = smb_hdr_len + 8;
50c2f753 2210
1da177e4 2211
ec637e3f 2212 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
133672ef 2213 long_op);
a4544347 2214 cifs_stats_inc(&tcon->num_writes);
1da177e4 2215 if (rc) {
b6b38f70 2216 cFYI(1, "Send error Write2 = %d", rc);
790fe579 2217 } else if (resp_buf_type == 0) {
ec637e3f
SF
2218 /* presumably this can not happen, but best to be safe */
2219 rc = -EIO;
d6e04ae6 2220 } else {
ad7a2926 2221 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
d6e04ae6
SF
2222 *nbytes = le16_to_cpu(pSMBr->CountHigh);
2223 *nbytes = (*nbytes) << 16;
2224 *nbytes += le16_to_cpu(pSMBr->Count);
6513a81e
SJ
2225
2226 /*
2227 * Mask off high 16 bits when bytes written as returned by the
2228 * server is greater than bytes requested by the client. OS/2
2229 * servers are known to set incorrect CountHigh values.
2230 */
2231 if (*nbytes > count)
2232 *nbytes &= 0xFFFF;
50c2f753 2233 }
1da177e4 2234
4b8f930f 2235/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
790fe579 2236 if (resp_buf_type == CIFS_SMALL_BUFFER)
ec637e3f 2237 cifs_small_buf_release(iov[0].iov_base);
790fe579 2238 else if (resp_buf_type == CIFS_LARGE_BUFFER)
ec637e3f 2239 cifs_buf_release(iov[0].iov_base);
1da177e4 2240
50c2f753 2241 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
2242 since file handle passed in no longer valid */
2243
2244 return rc;
2245}
d6e04ae6 2246
9ee305b7
PS
2247int cifs_lockv(const int xid, struct cifs_tcon *tcon, const __u16 netfid,
2248 const __u8 lock_type, const __u32 num_unlock,
2249 const __u32 num_lock, LOCKING_ANDX_RANGE *buf)
2250{
2251 int rc = 0;
2252 LOCK_REQ *pSMB = NULL;
2253 struct kvec iov[2];
2254 int resp_buf_type;
2255 __u16 count;
2256
2257 cFYI(1, "cifs_lockv num lock %d num unlock %d", num_lock, num_unlock);
2258
2259 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2260 if (rc)
2261 return rc;
2262
2263 pSMB->Timeout = 0;
2264 pSMB->NumberOfLocks = cpu_to_le16(num_lock);
2265 pSMB->NumberOfUnlocks = cpu_to_le16(num_unlock);
2266 pSMB->LockType = lock_type;
2267 pSMB->AndXCommand = 0xFF; /* none */
2268 pSMB->Fid = netfid; /* netfid stays le */
2269
2270 count = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2271 inc_rfc1001_len(pSMB, count);
2272 pSMB->ByteCount = cpu_to_le16(count);
2273
2274 iov[0].iov_base = (char *)pSMB;
2275 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4 -
2276 (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2277 iov[1].iov_base = (char *)buf;
2278 iov[1].iov_len = (num_unlock + num_lock) * sizeof(LOCKING_ANDX_RANGE);
2279
2280 cifs_stats_inc(&tcon->num_locks);
2281 rc = SendReceive2(xid, tcon->ses, iov, 2, &resp_buf_type, CIFS_NO_RESP);
2282 if (rc)
2283 cFYI(1, "Send error in cifs_lockv = %d", rc);
2284
2285 return rc;
2286}
d6e04ae6 2287
1da177e4 2288int
96daf2b0 2289CIFSSMBLock(const int xid, struct cifs_tcon *tcon,
03776f45 2290 const __u16 smb_file_id, const __u32 netpid, const __u64 len,
1da177e4 2291 const __u64 offset, const __u32 numUnlock,
12fed00d
PS
2292 const __u32 numLock, const __u8 lockType,
2293 const bool waitFlag, const __u8 oplock_level)
1da177e4
LT
2294{
2295 int rc = 0;
2296 LOCK_REQ *pSMB = NULL;
aaa9bbe0 2297/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
1da177e4 2298 int bytes_returned;
a891f0f8 2299 int flags = 0;
1da177e4
LT
2300 __u16 count;
2301
b6b38f70 2302 cFYI(1, "CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock);
46810cbf
SF
2303 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
2304
1da177e4
LT
2305 if (rc)
2306 return rc;
2307
790fe579 2308 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
a891f0f8
PS
2309 /* no response expected */
2310 flags = CIFS_ASYNC_OP | CIFS_OBREAK_OP;
1da177e4 2311 pSMB->Timeout = 0;
4b18f2a9 2312 } else if (waitFlag) {
a891f0f8 2313 flags = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
1da177e4
LT
2314 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
2315 } else {
2316 pSMB->Timeout = 0;
2317 }
2318
2319 pSMB->NumberOfLocks = cpu_to_le16(numLock);
2320 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
2321 pSMB->LockType = lockType;
12fed00d 2322 pSMB->OplockLevel = oplock_level;
1da177e4
LT
2323 pSMB->AndXCommand = 0xFF; /* none */
2324 pSMB->Fid = smb_file_id; /* netfid stays le */
2325
790fe579 2326 if ((numLock != 0) || (numUnlock != 0)) {
03776f45 2327 pSMB->Locks[0].Pid = cpu_to_le16(netpid);
1da177e4
LT
2328 /* BB where to store pid high? */
2329 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
2330 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
2331 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
2332 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
2333 count = sizeof(LOCKING_ANDX_RANGE);
2334 } else {
2335 /* oplock break */
2336 count = 0;
2337 }
be8e3b00 2338 inc_rfc1001_len(pSMB, count);
1da177e4
LT
2339 pSMB->ByteCount = cpu_to_le16(count);
2340
7ee1af76
JA
2341 if (waitFlag) {
2342 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
aaa9bbe0 2343 (struct smb_hdr *) pSMB, &bytes_returned);
133672ef 2344 cifs_small_buf_release(pSMB);
7ee1af76 2345 } else {
a891f0f8 2346 rc = SendReceiveNoRsp(xid, tcon->ses, (char *)pSMB, flags);
133672ef 2347 /* SMB buffer freed by function above */
7ee1af76 2348 }
a4544347 2349 cifs_stats_inc(&tcon->num_locks);
ad7a2926 2350 if (rc)
b6b38f70 2351 cFYI(1, "Send error in Lock = %d", rc);
1da177e4 2352
50c2f753 2353 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
2354 since file handle passed in no longer valid */
2355 return rc;
2356}
2357
08547b03 2358int
96daf2b0 2359CIFSSMBPosixLock(const int xid, struct cifs_tcon *tcon,
c5fd363d
JL
2360 const __u16 smb_file_id, const __u32 netpid,
2361 const loff_t start_offset, const __u64 len,
2362 struct file_lock *pLockData, const __u16 lock_type,
2363 const bool waitFlag)
08547b03
SF
2364{
2365 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2366 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
08547b03
SF
2367 struct cifs_posix_lock *parm_data;
2368 int rc = 0;
3a5ff61c 2369 int timeout = 0;
08547b03 2370 int bytes_returned = 0;
133672ef 2371 int resp_buf_type = 0;
08547b03 2372 __u16 params, param_offset, offset, byte_count, count;
133672ef 2373 struct kvec iov[1];
08547b03 2374
b6b38f70 2375 cFYI(1, "Posix Lock");
fc94cdb9 2376
08547b03
SF
2377 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
2378
2379 if (rc)
2380 return rc;
2381
2382 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
2383
50c2f753 2384 params = 6;
08547b03
SF
2385 pSMB->MaxSetupCount = 0;
2386 pSMB->Reserved = 0;
2387 pSMB->Flags = 0;
08547b03
SF
2388 pSMB->Reserved2 = 0;
2389 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2390 offset = param_offset + params;
2391
08547b03
SF
2392 count = sizeof(struct cifs_posix_lock);
2393 pSMB->MaxParameterCount = cpu_to_le16(2);
ad7a2926 2394 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
08547b03
SF
2395 pSMB->SetupCount = 1;
2396 pSMB->Reserved3 = 0;
c5fd363d 2397 if (pLockData)
08547b03
SF
2398 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2399 else
2400 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2401 byte_count = 3 /* pad */ + params + count;
2402 pSMB->DataCount = cpu_to_le16(count);
2403 pSMB->ParameterCount = cpu_to_le16(params);
2404 pSMB->TotalDataCount = pSMB->DataCount;
2405 pSMB->TotalParameterCount = pSMB->ParameterCount;
2406 pSMB->ParameterOffset = cpu_to_le16(param_offset);
50c2f753 2407 parm_data = (struct cifs_posix_lock *)
08547b03
SF
2408 (((char *) &pSMB->hdr.Protocol) + offset);
2409
2410 parm_data->lock_type = cpu_to_le16(lock_type);
790fe579 2411 if (waitFlag) {
133672ef 2412 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
cec6815a 2413 parm_data->lock_flags = cpu_to_le16(1);
3a5ff61c
SF
2414 pSMB->Timeout = cpu_to_le32(-1);
2415 } else
2416 pSMB->Timeout = 0;
2417
4f6bcec9 2418 parm_data->pid = cpu_to_le32(netpid);
c5fd363d 2419 parm_data->start = cpu_to_le64(start_offset);
cec6815a 2420 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
08547b03
SF
2421
2422 pSMB->DataOffset = cpu_to_le16(offset);
f26282c9 2423 pSMB->Fid = smb_file_id;
08547b03
SF
2424 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
2425 pSMB->Reserved4 = 0;
be8e3b00 2426 inc_rfc1001_len(pSMB, byte_count);
08547b03 2427 pSMB->ByteCount = cpu_to_le16(byte_count);
7ee1af76
JA
2428 if (waitFlag) {
2429 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
2430 (struct smb_hdr *) pSMBr, &bytes_returned);
2431 } else {
133672ef 2432 iov[0].iov_base = (char *)pSMB;
be8e3b00 2433 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
133672ef
SF
2434 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
2435 &resp_buf_type, timeout);
2436 pSMB = NULL; /* request buf already freed by SendReceive2. Do
2437 not try to free it twice below on exit */
2438 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
7ee1af76
JA
2439 }
2440
08547b03 2441 if (rc) {
b6b38f70 2442 cFYI(1, "Send error in Posix Lock = %d", rc);
c5fd363d 2443 } else if (pLockData) {
fc94cdb9
SF
2444 /* lock structure can be returned on get */
2445 __u16 data_offset;
2446 __u16 data_count;
2447 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2448
820a803f 2449 if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) {
fc94cdb9
SF
2450 rc = -EIO; /* bad smb */
2451 goto plk_err_exit;
2452 }
fc94cdb9
SF
2453 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2454 data_count = le16_to_cpu(pSMBr->t2.DataCount);
790fe579 2455 if (data_count < sizeof(struct cifs_posix_lock)) {
fc94cdb9
SF
2456 rc = -EIO;
2457 goto plk_err_exit;
2458 }
2459 parm_data = (struct cifs_posix_lock *)
2460 ((char *)&pSMBr->hdr.Protocol + data_offset);
f05337c6 2461 if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
fc94cdb9 2462 pLockData->fl_type = F_UNLCK;
f05337c6
PS
2463 else {
2464 if (parm_data->lock_type ==
2465 __constant_cpu_to_le16(CIFS_RDLCK))
2466 pLockData->fl_type = F_RDLCK;
2467 else if (parm_data->lock_type ==
2468 __constant_cpu_to_le16(CIFS_WRLCK))
2469 pLockData->fl_type = F_WRLCK;
2470
5443d130
SF
2471 pLockData->fl_start = le64_to_cpu(parm_data->start);
2472 pLockData->fl_end = pLockData->fl_start +
2473 le64_to_cpu(parm_data->length) - 1;
2474 pLockData->fl_pid = le32_to_cpu(parm_data->pid);
f05337c6 2475 }
08547b03 2476 }
50c2f753 2477
fc94cdb9 2478plk_err_exit:
08547b03
SF
2479 if (pSMB)
2480 cifs_small_buf_release(pSMB);
2481
133672ef
SF
2482 if (resp_buf_type == CIFS_SMALL_BUFFER)
2483 cifs_small_buf_release(iov[0].iov_base);
2484 else if (resp_buf_type == CIFS_LARGE_BUFFER)
2485 cifs_buf_release(iov[0].iov_base);
2486
08547b03
SF
2487 /* Note: On -EAGAIN error only caller can retry on handle based calls
2488 since file handle passed in no longer valid */
2489
2490 return rc;
2491}
2492
2493
1da177e4 2494int
96daf2b0 2495CIFSSMBClose(const int xid, struct cifs_tcon *tcon, int smb_file_id)
1da177e4
LT
2496{
2497 int rc = 0;
2498 CLOSE_REQ *pSMB = NULL;
b6b38f70 2499 cFYI(1, "In CIFSSMBClose");
1da177e4
LT
2500
2501/* do not retry on dead session on close */
2502 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
790fe579 2503 if (rc == -EAGAIN)
1da177e4
LT
2504 return 0;
2505 if (rc)
2506 return rc;
2507
1da177e4 2508 pSMB->FileID = (__u16) smb_file_id;
b815f1e5 2509 pSMB->LastWriteTime = 0xFFFFFFFF;
1da177e4 2510 pSMB->ByteCount = 0;
792af7b0 2511 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
a4544347 2512 cifs_stats_inc(&tcon->num_closes);
1da177e4 2513 if (rc) {
790fe579 2514 if (rc != -EINTR) {
1da177e4 2515 /* EINTR is expected when user ctl-c to kill app */
b6b38f70 2516 cERROR(1, "Send error in Close = %d", rc);
1da177e4
LT
2517 }
2518 }
2519
1da177e4 2520 /* Since session is dead, file will be closed on server already */
790fe579 2521 if (rc == -EAGAIN)
1da177e4
LT
2522 rc = 0;
2523
2524 return rc;
2525}
2526
b298f223 2527int
96daf2b0 2528CIFSSMBFlush(const int xid, struct cifs_tcon *tcon, int smb_file_id)
b298f223
SF
2529{
2530 int rc = 0;
2531 FLUSH_REQ *pSMB = NULL;
b6b38f70 2532 cFYI(1, "In CIFSSMBFlush");
b298f223
SF
2533
2534 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
2535 if (rc)
2536 return rc;
2537
2538 pSMB->FileID = (__u16) smb_file_id;
2539 pSMB->ByteCount = 0;
792af7b0 2540 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
b298f223
SF
2541 cifs_stats_inc(&tcon->num_flushes);
2542 if (rc)
b6b38f70 2543 cERROR(1, "Send error in Flush = %d", rc);
b298f223
SF
2544
2545 return rc;
2546}
2547
1da177e4 2548int
96daf2b0 2549CIFSSMBRename(const int xid, struct cifs_tcon *tcon,
1da177e4 2550 const char *fromName, const char *toName,
737b758c 2551 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2552{
2553 int rc = 0;
2554 RENAME_REQ *pSMB = NULL;
2555 RENAME_RSP *pSMBr = NULL;
2556 int bytes_returned;
2557 int name_len, name_len2;
2558 __u16 count;
2559
b6b38f70 2560 cFYI(1, "In CIFSSMBRename");
1da177e4
LT
2561renameRetry:
2562 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
2563 (void **) &pSMBr);
2564 if (rc)
2565 return rc;
2566
2567 pSMB->BufferFormat = 0x04;
2568 pSMB->SearchAttributes =
2569 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2570 ATTR_DIRECTORY);
2571
2572 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2573 name_len =
acbbb76a
SF
2574 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2575 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2576 name_len++; /* trailing null */
2577 name_len *= 2;
2578 pSMB->OldFileName[name_len] = 0x04; /* pad */
2579 /* protocol requires ASCII signature byte on Unicode string */
2580 pSMB->OldFileName[name_len + 1] = 0x00;
2581 name_len2 =
acbbb76a
SF
2582 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2583 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2584 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2585 name_len2 *= 2; /* convert to bytes */
50c2f753 2586 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2587 name_len = strnlen(fromName, PATH_MAX);
2588 name_len++; /* trailing null */
2589 strncpy(pSMB->OldFileName, fromName, name_len);
2590 name_len2 = strnlen(toName, PATH_MAX);
2591 name_len2++; /* trailing null */
2592 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2593 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2594 name_len2++; /* trailing null */
2595 name_len2++; /* signature byte */
2596 }
2597
2598 count = 1 /* 1st signature byte */ + name_len + name_len2;
be8e3b00 2599 inc_rfc1001_len(pSMB, count);
1da177e4
LT
2600 pSMB->ByteCount = cpu_to_le16(count);
2601
2602 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2603 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2604 cifs_stats_inc(&tcon->num_renames);
ad7a2926 2605 if (rc)
b6b38f70 2606 cFYI(1, "Send error in rename = %d", rc);
1da177e4 2607
1da177e4
LT
2608 cifs_buf_release(pSMB);
2609
2610 if (rc == -EAGAIN)
2611 goto renameRetry;
2612
2613 return rc;
2614}
2615
96daf2b0 2616int CIFSSMBRenameOpenFile(const int xid, struct cifs_tcon *pTcon,
391e5755 2617 int netfid, const char *target_name,
50c2f753 2618 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2619{
2620 struct smb_com_transaction2_sfi_req *pSMB = NULL;
2621 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
50c2f753 2622 struct set_file_rename *rename_info;
1da177e4
LT
2623 char *data_offset;
2624 char dummy_string[30];
2625 int rc = 0;
2626 int bytes_returned = 0;
2627 int len_of_str;
2628 __u16 params, param_offset, offset, count, byte_count;
2629
b6b38f70 2630 cFYI(1, "Rename to File by handle");
1da177e4
LT
2631 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2632 (void **) &pSMBr);
2633 if (rc)
2634 return rc;
2635
2636 params = 6;
2637 pSMB->MaxSetupCount = 0;
2638 pSMB->Reserved = 0;
2639 pSMB->Flags = 0;
2640 pSMB->Timeout = 0;
2641 pSMB->Reserved2 = 0;
2642 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2643 offset = param_offset + params;
2644
2645 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2646 rename_info = (struct set_file_rename *) data_offset;
2647 pSMB->MaxParameterCount = cpu_to_le16(2);
ad7a2926 2648 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
1da177e4
LT
2649 pSMB->SetupCount = 1;
2650 pSMB->Reserved3 = 0;
2651 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2652 byte_count = 3 /* pad */ + params;
2653 pSMB->ParameterCount = cpu_to_le16(params);
2654 pSMB->TotalParameterCount = pSMB->ParameterCount;
2655 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2656 pSMB->DataOffset = cpu_to_le16(offset);
2657 /* construct random name ".cifs_tmp<inodenum><mid>" */
2658 rename_info->overwrite = cpu_to_le32(1);
2659 rename_info->root_fid = 0;
2660 /* unicode only call */
790fe579 2661 if (target_name == NULL) {
50c2f753 2662 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
acbbb76a
SF
2663 len_of_str =
2664 cifsConvertToUTF16((__le16 *)rename_info->target_name,
737b758c 2665 dummy_string, 24, nls_codepage, remap);
1da177e4 2666 } else {
acbbb76a
SF
2667 len_of_str =
2668 cifsConvertToUTF16((__le16 *)rename_info->target_name,
50c2f753
SF
2669 target_name, PATH_MAX, nls_codepage,
2670 remap);
1da177e4
LT
2671 }
2672 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
391e5755 2673 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
1da177e4
LT
2674 byte_count += count;
2675 pSMB->DataCount = cpu_to_le16(count);
2676 pSMB->TotalDataCount = pSMB->DataCount;
2677 pSMB->Fid = netfid;
2678 pSMB->InformationLevel =
2679 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2680 pSMB->Reserved4 = 0;
be8e3b00 2681 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
2682 pSMB->ByteCount = cpu_to_le16(byte_count);
2683 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
50c2f753 2684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2685 cifs_stats_inc(&pTcon->num_t2renames);
ad7a2926 2686 if (rc)
b6b38f70 2687 cFYI(1, "Send error in Rename (by file handle) = %d", rc);
a5a2b489 2688
1da177e4
LT
2689 cifs_buf_release(pSMB);
2690
2691 /* Note: On -EAGAIN error only caller can retry on handle based calls
2692 since file handle passed in no longer valid */
2693
2694 return rc;
2695}
2696
2697int
96daf2b0 2698CIFSSMBCopy(const int xid, struct cifs_tcon *tcon, const char *fromName,
50c2f753
SF
2699 const __u16 target_tid, const char *toName, const int flags,
2700 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2701{
2702 int rc = 0;
2703 COPY_REQ *pSMB = NULL;
2704 COPY_RSP *pSMBr = NULL;
2705 int bytes_returned;
2706 int name_len, name_len2;
2707 __u16 count;
2708
b6b38f70 2709 cFYI(1, "In CIFSSMBCopy");
1da177e4
LT
2710copyRetry:
2711 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2712 (void **) &pSMBr);
2713 if (rc)
2714 return rc;
2715
2716 pSMB->BufferFormat = 0x04;
2717 pSMB->Tid2 = target_tid;
2718
2719 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2720
2721 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
acbbb76a
SF
2722 name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
2723 fromName, PATH_MAX, nls_codepage,
2724 remap);
1da177e4
LT
2725 name_len++; /* trailing null */
2726 name_len *= 2;
2727 pSMB->OldFileName[name_len] = 0x04; /* pad */
2728 /* protocol requires ASCII signature byte on Unicode string */
2729 pSMB->OldFileName[name_len + 1] = 0x00;
50c2f753 2730 name_len2 =
acbbb76a
SF
2731 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2732 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2733 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2734 name_len2 *= 2; /* convert to bytes */
50c2f753 2735 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2736 name_len = strnlen(fromName, PATH_MAX);
2737 name_len++; /* trailing null */
2738 strncpy(pSMB->OldFileName, fromName, name_len);
2739 name_len2 = strnlen(toName, PATH_MAX);
2740 name_len2++; /* trailing null */
2741 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2742 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2743 name_len2++; /* trailing null */
2744 name_len2++; /* signature byte */
2745 }
2746
2747 count = 1 /* 1st signature byte */ + name_len + name_len2;
be8e3b00 2748 inc_rfc1001_len(pSMB, count);
1da177e4
LT
2749 pSMB->ByteCount = cpu_to_le16(count);
2750
2751 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2752 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2753 if (rc) {
b6b38f70
JP
2754 cFYI(1, "Send error in copy = %d with %d files copied",
2755 rc, le16_to_cpu(pSMBr->CopyCount));
1da177e4 2756 }
0d817bc0 2757 cifs_buf_release(pSMB);
1da177e4
LT
2758
2759 if (rc == -EAGAIN)
2760 goto copyRetry;
2761
2762 return rc;
2763}
2764
2765int
96daf2b0 2766CIFSUnixCreateSymLink(const int xid, struct cifs_tcon *tcon,
1da177e4
LT
2767 const char *fromName, const char *toName,
2768 const struct nls_table *nls_codepage)
2769{
2770 TRANSACTION2_SPI_REQ *pSMB = NULL;
2771 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2772 char *data_offset;
2773 int name_len;
2774 int name_len_target;
2775 int rc = 0;
2776 int bytes_returned = 0;
2777 __u16 params, param_offset, offset, byte_count;
2778
b6b38f70 2779 cFYI(1, "In Symlink Unix style");
1da177e4
LT
2780createSymLinkRetry:
2781 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2782 (void **) &pSMBr);
2783 if (rc)
2784 return rc;
2785
2786 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2787 name_len =
acbbb76a
SF
2788 cifs_strtoUTF16((__le16 *) pSMB->FileName, fromName,
2789 /* find define for this maxpathcomponent */
2790 PATH_MAX, nls_codepage);
1da177e4
LT
2791 name_len++; /* trailing null */
2792 name_len *= 2;
2793
50c2f753 2794 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2795 name_len = strnlen(fromName, PATH_MAX);
2796 name_len++; /* trailing null */
2797 strncpy(pSMB->FileName, fromName, name_len);
2798 }
2799 params = 6 + name_len;
2800 pSMB->MaxSetupCount = 0;
2801 pSMB->Reserved = 0;
2802 pSMB->Flags = 0;
2803 pSMB->Timeout = 0;
2804 pSMB->Reserved2 = 0;
2805 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2806 InformationLevel) - 4;
1da177e4
LT
2807 offset = param_offset + params;
2808
2809 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2810 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2811 name_len_target =
acbbb76a
SF
2812 cifs_strtoUTF16((__le16 *) data_offset, toName, PATH_MAX
2813 /* find define for this maxpathcomponent */
2814 , nls_codepage);
1da177e4
LT
2815 name_len_target++; /* trailing null */
2816 name_len_target *= 2;
50c2f753 2817 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2818 name_len_target = strnlen(toName, PATH_MAX);
2819 name_len_target++; /* trailing null */
2820 strncpy(data_offset, toName, name_len_target);
2821 }
2822
2823 pSMB->MaxParameterCount = cpu_to_le16(2);
2824 /* BB find exact max on data count below from sess */
2825 pSMB->MaxDataCount = cpu_to_le16(1000);
2826 pSMB->SetupCount = 1;
2827 pSMB->Reserved3 = 0;
2828 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2829 byte_count = 3 /* pad */ + params + name_len_target;
2830 pSMB->DataCount = cpu_to_le16(name_len_target);
2831 pSMB->ParameterCount = cpu_to_le16(params);
2832 pSMB->TotalDataCount = pSMB->DataCount;
2833 pSMB->TotalParameterCount = pSMB->ParameterCount;
2834 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2835 pSMB->DataOffset = cpu_to_le16(offset);
2836 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2837 pSMB->Reserved4 = 0;
be8e3b00 2838 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
2839 pSMB->ByteCount = cpu_to_le16(byte_count);
2840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2842 cifs_stats_inc(&tcon->num_symlinks);
ad7a2926 2843 if (rc)
b6b38f70 2844 cFYI(1, "Send error in SetPathInfo create symlink = %d", rc);
1da177e4 2845
0d817bc0 2846 cifs_buf_release(pSMB);
1da177e4
LT
2847
2848 if (rc == -EAGAIN)
2849 goto createSymLinkRetry;
2850
2851 return rc;
2852}
2853
2854int
96daf2b0 2855CIFSUnixCreateHardLink(const int xid, struct cifs_tcon *tcon,
1da177e4 2856 const char *fromName, const char *toName,
737b758c 2857 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2858{
2859 TRANSACTION2_SPI_REQ *pSMB = NULL;
2860 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2861 char *data_offset;
2862 int name_len;
2863 int name_len_target;
2864 int rc = 0;
2865 int bytes_returned = 0;
2866 __u16 params, param_offset, offset, byte_count;
2867
b6b38f70 2868 cFYI(1, "In Create Hard link Unix style");
1da177e4
LT
2869createHardLinkRetry:
2870 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2871 (void **) &pSMBr);
2872 if (rc)
2873 return rc;
2874
2875 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
acbbb76a
SF
2876 name_len = cifsConvertToUTF16((__le16 *) pSMB->FileName, toName,
2877 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2878 name_len++; /* trailing null */
2879 name_len *= 2;
2880
50c2f753 2881 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2882 name_len = strnlen(toName, PATH_MAX);
2883 name_len++; /* trailing null */
2884 strncpy(pSMB->FileName, toName, name_len);
2885 }
2886 params = 6 + name_len;
2887 pSMB->MaxSetupCount = 0;
2888 pSMB->Reserved = 0;
2889 pSMB->Flags = 0;
2890 pSMB->Timeout = 0;
2891 pSMB->Reserved2 = 0;
2892 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 2893 InformationLevel) - 4;
1da177e4
LT
2894 offset = param_offset + params;
2895
2896 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2897 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2898 name_len_target =
acbbb76a
SF
2899 cifsConvertToUTF16((__le16 *) data_offset, fromName,
2900 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2901 name_len_target++; /* trailing null */
2902 name_len_target *= 2;
50c2f753 2903 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2904 name_len_target = strnlen(fromName, PATH_MAX);
2905 name_len_target++; /* trailing null */
2906 strncpy(data_offset, fromName, name_len_target);
2907 }
2908
2909 pSMB->MaxParameterCount = cpu_to_le16(2);
2910 /* BB find exact max on data count below from sess*/
2911 pSMB->MaxDataCount = cpu_to_le16(1000);
2912 pSMB->SetupCount = 1;
2913 pSMB->Reserved3 = 0;
2914 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2915 byte_count = 3 /* pad */ + params + name_len_target;
2916 pSMB->ParameterCount = cpu_to_le16(params);
2917 pSMB->TotalParameterCount = pSMB->ParameterCount;
2918 pSMB->DataCount = cpu_to_le16(name_len_target);
2919 pSMB->TotalDataCount = pSMB->DataCount;
2920 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2921 pSMB->DataOffset = cpu_to_le16(offset);
2922 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2923 pSMB->Reserved4 = 0;
be8e3b00 2924 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
2925 pSMB->ByteCount = cpu_to_le16(byte_count);
2926 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2927 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 2928 cifs_stats_inc(&tcon->num_hardlinks);
ad7a2926 2929 if (rc)
b6b38f70 2930 cFYI(1, "Send error in SetPathInfo (hard link) = %d", rc);
1da177e4
LT
2931
2932 cifs_buf_release(pSMB);
2933 if (rc == -EAGAIN)
2934 goto createHardLinkRetry;
2935
2936 return rc;
2937}
2938
2939int
96daf2b0 2940CIFSCreateHardLink(const int xid, struct cifs_tcon *tcon,
1da177e4 2941 const char *fromName, const char *toName,
737b758c 2942 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
2943{
2944 int rc = 0;
2945 NT_RENAME_REQ *pSMB = NULL;
2946 RENAME_RSP *pSMBr = NULL;
2947 int bytes_returned;
2948 int name_len, name_len2;
2949 __u16 count;
2950
b6b38f70 2951 cFYI(1, "In CIFSCreateHardLink");
1da177e4
LT
2952winCreateHardLinkRetry:
2953
2954 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2955 (void **) &pSMBr);
2956 if (rc)
2957 return rc;
2958
2959 pSMB->SearchAttributes =
2960 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2961 ATTR_DIRECTORY);
2962 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2963 pSMB->ClusterCount = 0;
2964
2965 pSMB->BufferFormat = 0x04;
2966
2967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2968 name_len =
acbbb76a
SF
2969 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2970 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2971 name_len++; /* trailing null */
2972 name_len *= 2;
fcc7c09d
JL
2973
2974 /* protocol specifies ASCII buffer format (0x04) for unicode */
2975 pSMB->OldFileName[name_len] = 0x04;
2976 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
1da177e4 2977 name_len2 =
acbbb76a
SF
2978 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2979 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2980 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2981 name_len2 *= 2; /* convert to bytes */
50c2f753 2982 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2983 name_len = strnlen(fromName, PATH_MAX);
2984 name_len++; /* trailing null */
2985 strncpy(pSMB->OldFileName, fromName, name_len);
2986 name_len2 = strnlen(toName, PATH_MAX);
2987 name_len2++; /* trailing null */
2988 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2989 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2990 name_len2++; /* trailing null */
2991 name_len2++; /* signature byte */
2992 }
2993
2994 count = 1 /* string type byte */ + name_len + name_len2;
be8e3b00 2995 inc_rfc1001_len(pSMB, count);
1da177e4
LT
2996 pSMB->ByteCount = cpu_to_le16(count);
2997
2998 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2999 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 3000 cifs_stats_inc(&tcon->num_hardlinks);
ad7a2926 3001 if (rc)
b6b38f70 3002 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
ad7a2926 3003
1da177e4
LT
3004 cifs_buf_release(pSMB);
3005 if (rc == -EAGAIN)
3006 goto winCreateHardLinkRetry;
3007
3008 return rc;
3009}
3010
3011int
96daf2b0 3012CIFSSMBUnixQuerySymLink(const int xid, struct cifs_tcon *tcon,
460b9696 3013 const unsigned char *searchName, char **symlinkinfo,
1da177e4
LT
3014 const struct nls_table *nls_codepage)
3015{
3016/* SMB_QUERY_FILE_UNIX_LINK */
3017 TRANSACTION2_QPI_REQ *pSMB = NULL;
3018 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3019 int rc = 0;
3020 int bytes_returned;
3021 int name_len;
3022 __u16 params, byte_count;
460b9696 3023 char *data_start;
1da177e4 3024
b6b38f70 3025 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
1da177e4
LT
3026
3027querySymLinkRetry:
3028 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3029 (void **) &pSMBr);
3030 if (rc)
3031 return rc;
3032
3033 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3034 name_len =
acbbb76a
SF
3035 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3036 PATH_MAX, nls_codepage);
1da177e4
LT
3037 name_len++; /* trailing null */
3038 name_len *= 2;
50c2f753 3039 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3040 name_len = strnlen(searchName, PATH_MAX);
3041 name_len++; /* trailing null */
3042 strncpy(pSMB->FileName, searchName, name_len);
3043 }
3044
3045 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3046 pSMB->TotalDataCount = 0;
3047 pSMB->MaxParameterCount = cpu_to_le16(2);
46a7574c 3048 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
1da177e4
LT
3049 pSMB->MaxSetupCount = 0;
3050 pSMB->Reserved = 0;
3051 pSMB->Flags = 0;
3052 pSMB->Timeout = 0;
3053 pSMB->Reserved2 = 0;
3054 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3055 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3056 pSMB->DataCount = 0;
3057 pSMB->DataOffset = 0;
3058 pSMB->SetupCount = 1;
3059 pSMB->Reserved3 = 0;
3060 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3061 byte_count = params + 1 /* pad */ ;
3062 pSMB->TotalParameterCount = cpu_to_le16(params);
3063 pSMB->ParameterCount = pSMB->TotalParameterCount;
3064 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3065 pSMB->Reserved4 = 0;
be8e3b00 3066 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
3067 pSMB->ByteCount = cpu_to_le16(byte_count);
3068
3069 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3070 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3071 if (rc) {
b6b38f70 3072 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
1da177e4
LT
3073 } else {
3074 /* decode response */
3075
3076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 3077 /* BB also check enough total bytes returned */
820a803f 3078 if (rc || get_bcc(&pSMBr->hdr) < 2)
460b9696 3079 rc = -EIO;
1da177e4 3080 else {
0e0d2cf3 3081 bool is_unicode;
460b9696
JL
3082 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3083
3084 data_start = ((char *) &pSMBr->hdr.Protocol) +
3085 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4 3086
0e0d2cf3
SF
3087 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3088 is_unicode = true;
3089 else
3090 is_unicode = false;
3091
737b758c 3092 /* BB FIXME investigate remapping reserved chars here */
acbbb76a
SF
3093 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3094 count, is_unicode, nls_codepage);
8b6427a2 3095 if (!*symlinkinfo)
460b9696 3096 rc = -ENOMEM;
1da177e4
LT
3097 }
3098 }
3099 cifs_buf_release(pSMB);
3100 if (rc == -EAGAIN)
3101 goto querySymLinkRetry;
3102 return rc;
3103}
3104
c52a9554
SF
3105#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3106/*
3107 * Recent Windows versions now create symlinks more frequently
3108 * and they use the "reparse point" mechanism below. We can of course
3109 * do symlinks nicely to Samba and other servers which support the
3110 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3111 * "MF" symlinks optionally, but for recent Windows we really need to
3112 * reenable the code below and fix the cifs_symlink callers to handle this.
3113 * In the interim this code has been moved to its own config option so
3114 * it is not compiled in by default until callers fixed up and more tested.
3115 */
1da177e4 3116int
96daf2b0 3117CIFSSMBQueryReparseLinkInfo(const int xid, struct cifs_tcon *tcon,
1da177e4 3118 const unsigned char *searchName,
50c2f753 3119 char *symlinkinfo, const int buflen, __u16 fid,
1da177e4
LT
3120 const struct nls_table *nls_codepage)
3121{
3122 int rc = 0;
3123 int bytes_returned;
50c2f753
SF
3124 struct smb_com_transaction_ioctl_req *pSMB;
3125 struct smb_com_transaction_ioctl_rsp *pSMBr;
1da177e4 3126
b6b38f70 3127 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
1da177e4
LT
3128 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3129 (void **) &pSMBr);
3130 if (rc)
3131 return rc;
3132
3133 pSMB->TotalParameterCount = 0 ;
3134 pSMB->TotalDataCount = 0;
3135 pSMB->MaxParameterCount = cpu_to_le32(2);
3136 /* BB find exact data count max from sess structure BB */
c974befa 3137 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
1da177e4
LT
3138 pSMB->MaxSetupCount = 4;
3139 pSMB->Reserved = 0;
3140 pSMB->ParameterOffset = 0;
3141 pSMB->DataCount = 0;
3142 pSMB->DataOffset = 0;
3143 pSMB->SetupCount = 4;
3144 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3145 pSMB->ParameterCount = pSMB->TotalParameterCount;
3146 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3147 pSMB->IsFsctl = 1; /* FSCTL */
3148 pSMB->IsRootFlag = 0;
3149 pSMB->Fid = fid; /* file handle always le */
3150 pSMB->ByteCount = 0;
3151
3152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3153 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3154 if (rc) {
b6b38f70 3155 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
1da177e4
LT
3156 } else { /* decode response */
3157 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3158 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
820a803f
JL
3159 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3160 /* BB also check enough total bytes returned */
1da177e4 3161 rc = -EIO; /* bad smb */
afe48c31
SF
3162 goto qreparse_out;
3163 }
3164 if (data_count && (data_count < 2048)) {
3165 char *end_of_smb = 2 /* sizeof byte count */ +
820a803f 3166 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
1da177e4 3167
afe48c31 3168 struct reparse_data *reparse_buf =
50c2f753
SF
3169 (struct reparse_data *)
3170 ((char *)&pSMBr->hdr.Protocol
3171 + data_offset);
afe48c31
SF
3172 if ((char *)reparse_buf >= end_of_smb) {
3173 rc = -EIO;
3174 goto qreparse_out;
3175 }
3176 if ((reparse_buf->LinkNamesBuf +
3177 reparse_buf->TargetNameOffset +
3178 reparse_buf->TargetNameLen) > end_of_smb) {
b6b38f70 3179 cFYI(1, "reparse buf beyond SMB");
afe48c31
SF
3180 rc = -EIO;
3181 goto qreparse_out;
3182 }
50c2f753 3183
afe48c31
SF
3184 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3185 cifs_from_ucs2(symlinkinfo, (__le16 *)
50c2f753
SF
3186 (reparse_buf->LinkNamesBuf +
3187 reparse_buf->TargetNameOffset),
afe48c31
SF
3188 buflen,
3189 reparse_buf->TargetNameLen,
3190 nls_codepage, 0);
3191 } else { /* ASCII names */
3192 strncpy(symlinkinfo,
3193 reparse_buf->LinkNamesBuf +
3194 reparse_buf->TargetNameOffset,
3195 min_t(const int, buflen,
3196 reparse_buf->TargetNameLen));
1da177e4 3197 }
afe48c31
SF
3198 } else {
3199 rc = -EIO;
b6b38f70
JP
3200 cFYI(1, "Invalid return data count on "
3201 "get reparse info ioctl");
1da177e4 3202 }
afe48c31
SF
3203 symlinkinfo[buflen] = 0; /* just in case so the caller
3204 does not go off the end of the buffer */
b6b38f70 3205 cFYI(1, "readlink result - %s", symlinkinfo);
1da177e4 3206 }
989c7e51 3207
1da177e4 3208qreparse_out:
4a6d87f1 3209 cifs_buf_release(pSMB);
1da177e4
LT
3210
3211 /* Note: On -EAGAIN error only caller can retry on handle based calls
3212 since file handle passed in no longer valid */
3213
3214 return rc;
3215}
c52a9554 3216#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
1da177e4
LT
3217
3218#ifdef CONFIG_CIFS_POSIX
3219
3220/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
50c2f753
SF
3221static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3222 struct cifs_posix_ace *cifs_ace)
1da177e4
LT
3223{
3224 /* u8 cifs fields do not need le conversion */
ff7feac9
SF
3225 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3226 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3227 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
b6b38f70 3228 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
1da177e4
LT
3229
3230 return;
3231}
3232
3233/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
50c2f753
SF
3234static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3235 const int acl_type, const int size_of_data_area)
1da177e4
LT
3236{
3237 int size = 0;
3238 int i;
3239 __u16 count;
50c2f753
SF
3240 struct cifs_posix_ace *pACE;
3241 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3242 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
1da177e4
LT
3243
3244 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3245 return -EOPNOTSUPP;
3246
790fe579 3247 if (acl_type & ACL_TYPE_ACCESS) {
1da177e4
LT
3248 count = le16_to_cpu(cifs_acl->access_entry_count);
3249 pACE = &cifs_acl->ace_array[0];
3250 size = sizeof(struct cifs_posix_acl);
3251 size += sizeof(struct cifs_posix_ace) * count;
3252 /* check if we would go beyond end of SMB */
790fe579 3253 if (size_of_data_area < size) {
b6b38f70
JP
3254 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3255 size_of_data_area, size);
1da177e4
LT
3256 return -EINVAL;
3257 }
790fe579 3258 } else if (acl_type & ACL_TYPE_DEFAULT) {
1da177e4
LT
3259 count = le16_to_cpu(cifs_acl->access_entry_count);
3260 size = sizeof(struct cifs_posix_acl);
3261 size += sizeof(struct cifs_posix_ace) * count;
3262/* skip past access ACEs to get to default ACEs */
3263 pACE = &cifs_acl->ace_array[count];
3264 count = le16_to_cpu(cifs_acl->default_entry_count);
3265 size += sizeof(struct cifs_posix_ace) * count;
3266 /* check if we would go beyond end of SMB */
790fe579 3267 if (size_of_data_area < size)
1da177e4
LT
3268 return -EINVAL;
3269 } else {
3270 /* illegal type */
3271 return -EINVAL;
3272 }
3273
3274 size = posix_acl_xattr_size(count);
790fe579 3275 if ((buflen == 0) || (local_acl == NULL)) {
50c2f753 3276 /* used to query ACL EA size */
790fe579 3277 } else if (size > buflen) {
1da177e4
LT
3278 return -ERANGE;
3279 } else /* buffer big enough */ {
ff7feac9 3280 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
50c2f753
SF
3281 for (i = 0; i < count ; i++) {
3282 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3283 pACE++;
1da177e4
LT
3284 }
3285 }
3286 return size;
3287}
3288
50c2f753
SF
3289static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3290 const posix_acl_xattr_entry *local_ace)
1da177e4
LT
3291{
3292 __u16 rc = 0; /* 0 = ACL converted ok */
3293
ff7feac9
SF
3294 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3295 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
1da177e4 3296 /* BB is there a better way to handle the large uid? */
790fe579 3297 if (local_ace->e_id == cpu_to_le32(-1)) {
1da177e4
LT
3298 /* Probably no need to le convert -1 on any arch but can not hurt */
3299 cifs_ace->cifs_uid = cpu_to_le64(-1);
50c2f753 3300 } else
ff7feac9 3301 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
b6b38f70 3302 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
1da177e4
LT
3303 return rc;
3304}
3305
3306/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
50c2f753
SF
3307static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3308 const int buflen, const int acl_type)
1da177e4
LT
3309{
3310 __u16 rc = 0;
50c2f753
SF
3311 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3312 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
1da177e4
LT
3313 int count;
3314 int i;
3315
790fe579 3316 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1da177e4
LT
3317 return 0;
3318
3319 count = posix_acl_xattr_count((size_t)buflen);
b6b38f70 3320 cFYI(1, "setting acl with %d entries from buf of length %d and "
63135e08 3321 "version of %d",
b6b38f70 3322 count, buflen, le32_to_cpu(local_acl->a_version));
790fe579 3323 if (le32_to_cpu(local_acl->a_version) != 2) {
b6b38f70
JP
3324 cFYI(1, "unknown POSIX ACL version %d",
3325 le32_to_cpu(local_acl->a_version));
1da177e4
LT
3326 return 0;
3327 }
3328 cifs_acl->version = cpu_to_le16(1);
790fe579 3329 if (acl_type == ACL_TYPE_ACCESS)
ff7feac9 3330 cifs_acl->access_entry_count = cpu_to_le16(count);
790fe579 3331 else if (acl_type == ACL_TYPE_DEFAULT)
ff7feac9 3332 cifs_acl->default_entry_count = cpu_to_le16(count);
1da177e4 3333 else {
b6b38f70 3334 cFYI(1, "unknown ACL type %d", acl_type);
1da177e4
LT
3335 return 0;
3336 }
50c2f753 3337 for (i = 0; i < count; i++) {
1da177e4
LT
3338 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3339 &local_acl->a_entries[i]);
790fe579 3340 if (rc != 0) {
1da177e4
LT
3341 /* ACE not converted */
3342 break;
3343 }
3344 }
790fe579 3345 if (rc == 0) {
1da177e4
LT
3346 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3347 rc += sizeof(struct cifs_posix_acl);
3348 /* BB add check to make sure ACL does not overflow SMB */
3349 }
3350 return rc;
3351}
3352
3353int
96daf2b0 3354CIFSSMBGetPosixACL(const int xid, struct cifs_tcon *tcon,
50c2f753
SF
3355 const unsigned char *searchName,
3356 char *acl_inf, const int buflen, const int acl_type,
3357 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3358{
3359/* SMB_QUERY_POSIX_ACL */
3360 TRANSACTION2_QPI_REQ *pSMB = NULL;
3361 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3362 int rc = 0;
3363 int bytes_returned;
3364 int name_len;
3365 __u16 params, byte_count;
50c2f753 3366
b6b38f70 3367 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
1da177e4
LT
3368
3369queryAclRetry:
3370 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3371 (void **) &pSMBr);
3372 if (rc)
3373 return rc;
50c2f753 3374
1da177e4
LT
3375 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3376 name_len =
acbbb76a
SF
3377 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3378 searchName, PATH_MAX, nls_codepage,
3379 remap);
1da177e4
LT
3380 name_len++; /* trailing null */
3381 name_len *= 2;
3382 pSMB->FileName[name_len] = 0;
3383 pSMB->FileName[name_len+1] = 0;
50c2f753 3384 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3385 name_len = strnlen(searchName, PATH_MAX);
3386 name_len++; /* trailing null */
3387 strncpy(pSMB->FileName, searchName, name_len);
3388 }
3389
3390 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3391 pSMB->TotalDataCount = 0;
3392 pSMB->MaxParameterCount = cpu_to_le16(2);
50c2f753 3393 /* BB find exact max data count below from sess structure BB */
1da177e4
LT
3394 pSMB->MaxDataCount = cpu_to_le16(4000);
3395 pSMB->MaxSetupCount = 0;
3396 pSMB->Reserved = 0;
3397 pSMB->Flags = 0;
3398 pSMB->Timeout = 0;
3399 pSMB->Reserved2 = 0;
3400 pSMB->ParameterOffset = cpu_to_le16(
50c2f753
SF
3401 offsetof(struct smb_com_transaction2_qpi_req,
3402 InformationLevel) - 4);
1da177e4
LT
3403 pSMB->DataCount = 0;
3404 pSMB->DataOffset = 0;
3405 pSMB->SetupCount = 1;
3406 pSMB->Reserved3 = 0;
3407 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3408 byte_count = params + 1 /* pad */ ;
3409 pSMB->TotalParameterCount = cpu_to_le16(params);
3410 pSMB->ParameterCount = pSMB->TotalParameterCount;
3411 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3412 pSMB->Reserved4 = 0;
be8e3b00 3413 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
3414 pSMB->ByteCount = cpu_to_le16(byte_count);
3415
3416 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3417 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
0a4b92c0 3418 cifs_stats_inc(&tcon->num_acl_get);
1da177e4 3419 if (rc) {
b6b38f70 3420 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
1da177e4
LT
3421 } else {
3422 /* decode response */
50c2f753 3423
1da177e4 3424 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 3425 /* BB also check enough total bytes returned */
820a803f 3426 if (rc || get_bcc(&pSMBr->hdr) < 2)
1da177e4
LT
3427 rc = -EIO; /* bad smb */
3428 else {
3429 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3430 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3431 rc = cifs_copy_posix_acl(acl_inf,
3432 (char *)&pSMBr->hdr.Protocol+data_offset,
50c2f753 3433 buflen, acl_type, count);
1da177e4
LT
3434 }
3435 }
3436 cifs_buf_release(pSMB);
3437 if (rc == -EAGAIN)
3438 goto queryAclRetry;
3439 return rc;
3440}
3441
3442int
96daf2b0 3443CIFSSMBSetPosixACL(const int xid, struct cifs_tcon *tcon,
50c2f753
SF
3444 const unsigned char *fileName,
3445 const char *local_acl, const int buflen,
3446 const int acl_type,
3447 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3448{
3449 struct smb_com_transaction2_spi_req *pSMB = NULL;
3450 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3451 char *parm_data;
3452 int name_len;
3453 int rc = 0;
3454 int bytes_returned = 0;
3455 __u16 params, byte_count, data_count, param_offset, offset;
3456
b6b38f70 3457 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
1da177e4
LT
3458setAclRetry:
3459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 3460 (void **) &pSMBr);
1da177e4
LT
3461 if (rc)
3462 return rc;
3463 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3464 name_len =
acbbb76a
SF
3465 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3466 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3467 name_len++; /* trailing null */
3468 name_len *= 2;
50c2f753 3469 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3470 name_len = strnlen(fileName, PATH_MAX);
3471 name_len++; /* trailing null */
3472 strncpy(pSMB->FileName, fileName, name_len);
3473 }
3474 params = 6 + name_len;
3475 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
3476 /* BB find max SMB size from sess */
3477 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
3478 pSMB->MaxSetupCount = 0;
3479 pSMB->Reserved = 0;
3480 pSMB->Flags = 0;
3481 pSMB->Timeout = 0;
3482 pSMB->Reserved2 = 0;
3483 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 3484 InformationLevel) - 4;
1da177e4
LT
3485 offset = param_offset + params;
3486 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3487 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3488
3489 /* convert to on the wire format for POSIX ACL */
50c2f753 3490 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
1da177e4 3491
790fe579 3492 if (data_count == 0) {
1da177e4
LT
3493 rc = -EOPNOTSUPP;
3494 goto setACLerrorExit;
3495 }
3496 pSMB->DataOffset = cpu_to_le16(offset);
3497 pSMB->SetupCount = 1;
3498 pSMB->Reserved3 = 0;
3499 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3500 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3501 byte_count = 3 /* pad */ + params + data_count;
3502 pSMB->DataCount = cpu_to_le16(data_count);
3503 pSMB->TotalDataCount = pSMB->DataCount;
3504 pSMB->ParameterCount = cpu_to_le16(params);
3505 pSMB->TotalParameterCount = pSMB->ParameterCount;
3506 pSMB->Reserved4 = 0;
be8e3b00 3507 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
3508 pSMB->ByteCount = cpu_to_le16(byte_count);
3509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 3510 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 3511 if (rc)
b6b38f70 3512 cFYI(1, "Set POSIX ACL returned %d", rc);
1da177e4
LT
3513
3514setACLerrorExit:
3515 cifs_buf_release(pSMB);
3516 if (rc == -EAGAIN)
3517 goto setAclRetry;
3518 return rc;
3519}
3520
f654bac2
SF
3521/* BB fix tabs in this function FIXME BB */
3522int
96daf2b0 3523CIFSGetExtAttr(const int xid, struct cifs_tcon *tcon,
ad7a2926 3524 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
f654bac2 3525{
50c2f753
SF
3526 int rc = 0;
3527 struct smb_t2_qfi_req *pSMB = NULL;
3528 struct smb_t2_qfi_rsp *pSMBr = NULL;
3529 int bytes_returned;
3530 __u16 params, byte_count;
f654bac2 3531
b6b38f70 3532 cFYI(1, "In GetExtAttr");
790fe579
SF
3533 if (tcon == NULL)
3534 return -ENODEV;
f654bac2
SF
3535
3536GetExtAttrRetry:
790fe579
SF
3537 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3538 (void **) &pSMBr);
3539 if (rc)
3540 return rc;
f654bac2 3541
ad7a2926 3542 params = 2 /* level */ + 2 /* fid */;
790fe579
SF
3543 pSMB->t2.TotalDataCount = 0;
3544 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3545 /* BB find exact max data count below from sess structure BB */
3546 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3547 pSMB->t2.MaxSetupCount = 0;
3548 pSMB->t2.Reserved = 0;
3549 pSMB->t2.Flags = 0;
3550 pSMB->t2.Timeout = 0;
3551 pSMB->t2.Reserved2 = 0;
3552 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3553 Fid) - 4);
3554 pSMB->t2.DataCount = 0;
3555 pSMB->t2.DataOffset = 0;
3556 pSMB->t2.SetupCount = 1;
3557 pSMB->t2.Reserved3 = 0;
3558 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3559 byte_count = params + 1 /* pad */ ;
3560 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3561 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3562 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3563 pSMB->Pad = 0;
f654bac2 3564 pSMB->Fid = netfid;
be8e3b00 3565 inc_rfc1001_len(pSMB, byte_count);
790fe579
SF
3566 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3567
3568 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3569 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3570 if (rc) {
b6b38f70 3571 cFYI(1, "error %d in GetExtAttr", rc);
790fe579
SF
3572 } else {
3573 /* decode response */
3574 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
790fe579 3575 /* BB also check enough total bytes returned */
820a803f 3576 if (rc || get_bcc(&pSMBr->hdr) < 2)
790fe579
SF
3577 /* If rc should we check for EOPNOSUPP and
3578 disable the srvino flag? or in caller? */
3579 rc = -EIO; /* bad smb */
3580 else {
3581 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3582 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3583 struct file_chattr_info *pfinfo;
3584 /* BB Do we need a cast or hash here ? */
3585 if (count != 16) {
b6b38f70 3586 cFYI(1, "Illegal size ret in GetExtAttr");
790fe579
SF
3587 rc = -EIO;
3588 goto GetExtAttrOut;
3589 }
3590 pfinfo = (struct file_chattr_info *)
3591 (data_offset + (char *) &pSMBr->hdr.Protocol);
3592 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
f654bac2 3593 *pMask = le64_to_cpu(pfinfo->mask);
790fe579
SF
3594 }
3595 }
f654bac2 3596GetExtAttrOut:
790fe579
SF
3597 cifs_buf_release(pSMB);
3598 if (rc == -EAGAIN)
3599 goto GetExtAttrRetry;
3600 return rc;
f654bac2
SF
3601}
3602
f654bac2 3603#endif /* CONFIG_POSIX */
1da177e4 3604
79df1bae
JL
3605#ifdef CONFIG_CIFS_ACL
3606/*
3607 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3608 * all NT TRANSACTS that we init here have total parm and data under about 400
3609 * bytes (to fit in small cifs buffer size), which is the case so far, it
3610 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3611 * returned setup area) and MaxParameterCount (returned parms size) must be set
3612 * by caller
3613 */
3614static int
3615smb_init_nttransact(const __u16 sub_command, const int setup_count,
96daf2b0 3616 const int parm_len, struct cifs_tcon *tcon,
79df1bae
JL
3617 void **ret_buf)
3618{
3619 int rc;
3620 __u32 temp_offset;
3621 struct smb_com_ntransact_req *pSMB;
3622
3623 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3624 (void **)&pSMB);
3625 if (rc)
3626 return rc;
3627 *ret_buf = (void *)pSMB;
3628 pSMB->Reserved = 0;
3629 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3630 pSMB->TotalDataCount = 0;
c974befa 3631 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
79df1bae
JL
3632 pSMB->ParameterCount = pSMB->TotalParameterCount;
3633 pSMB->DataCount = pSMB->TotalDataCount;
3634 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3635 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3636 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3637 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3638 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3639 pSMB->SubCommand = cpu_to_le16(sub_command);
3640 return 0;
3641}
3642
3643static int
3644validate_ntransact(char *buf, char **ppparm, char **ppdata,
3645 __u32 *pparmlen, __u32 *pdatalen)
3646{
3647 char *end_of_smb;
3648 __u32 data_count, data_offset, parm_count, parm_offset;
3649 struct smb_com_ntransact_rsp *pSMBr;
820a803f 3650 u16 bcc;
79df1bae
JL
3651
3652 *pdatalen = 0;
3653 *pparmlen = 0;
3654
3655 if (buf == NULL)
3656 return -EINVAL;
3657
3658 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3659
820a803f
JL
3660 bcc = get_bcc(&pSMBr->hdr);
3661 end_of_smb = 2 /* sizeof byte count */ + bcc +
79df1bae
JL
3662 (char *)&pSMBr->ByteCount;
3663
3664 data_offset = le32_to_cpu(pSMBr->DataOffset);
3665 data_count = le32_to_cpu(pSMBr->DataCount);
3666 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3667 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3668
3669 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3670 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3671
3672 /* should we also check that parm and data areas do not overlap? */
3673 if (*ppparm > end_of_smb) {
3674 cFYI(1, "parms start after end of smb");
3675 return -EINVAL;
3676 } else if (parm_count + *ppparm > end_of_smb) {
3677 cFYI(1, "parm end after end of smb");
3678 return -EINVAL;
3679 } else if (*ppdata > end_of_smb) {
3680 cFYI(1, "data starts after end of smb");
3681 return -EINVAL;
3682 } else if (data_count + *ppdata > end_of_smb) {
3683 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3684 *ppdata, data_count, (data_count + *ppdata),
3685 end_of_smb, pSMBr);
3686 return -EINVAL;
820a803f 3687 } else if (parm_count + data_count > bcc) {
79df1bae
JL
3688 cFYI(1, "parm count and data count larger than SMB");
3689 return -EINVAL;
3690 }
3691 *pdatalen = data_count;
3692 *pparmlen = parm_count;
3693 return 0;
3694}
3695
0a4b92c0
SF
3696/* Get Security Descriptor (by handle) from remote server for a file or dir */
3697int
96daf2b0 3698CIFSSMBGetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
630f3f0c 3699 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
0a4b92c0
SF
3700{
3701 int rc = 0;
3702 int buf_type = 0;
ad7a2926 3703 QUERY_SEC_DESC_REQ *pSMB;
0a4b92c0
SF
3704 struct kvec iov[1];
3705
b6b38f70 3706 cFYI(1, "GetCifsACL");
0a4b92c0 3707
630f3f0c
SF
3708 *pbuflen = 0;
3709 *acl_inf = NULL;
3710
b9c7a2bb 3711 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
0a4b92c0
SF
3712 8 /* parm len */, tcon, (void **) &pSMB);
3713 if (rc)
3714 return rc;
3715
3716 pSMB->MaxParameterCount = cpu_to_le32(4);
3717 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3718 pSMB->MaxSetupCount = 0;
3719 pSMB->Fid = fid; /* file handle always le */
3720 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3721 CIFS_ACL_DACL);
3722 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
be8e3b00 3723 inc_rfc1001_len(pSMB, 11);
0a4b92c0 3724 iov[0].iov_base = (char *)pSMB;
be8e3b00 3725 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
0a4b92c0 3726
a761ac57 3727 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
7749981e 3728 0);
0a4b92c0
SF
3729 cifs_stats_inc(&tcon->num_acl_get);
3730 if (rc) {
b6b38f70 3731 cFYI(1, "Send error in QuerySecDesc = %d", rc);
0a4b92c0 3732 } else { /* decode response */
ad7a2926 3733 __le32 *parm;
630f3f0c
SF
3734 __u32 parm_len;
3735 __u32 acl_len;
50c2f753 3736 struct smb_com_ntransact_rsp *pSMBr;
630f3f0c 3737 char *pdata;
0a4b92c0
SF
3738
3739/* validate_nttransact */
50c2f753 3740 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
630f3f0c 3741 &pdata, &parm_len, pbuflen);
790fe579 3742 if (rc)
0a4b92c0
SF
3743 goto qsec_out;
3744 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3745
b6b38f70 3746 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
0a4b92c0
SF
3747
3748 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3749 rc = -EIO; /* bad smb */
630f3f0c 3750 *pbuflen = 0;
0a4b92c0
SF
3751 goto qsec_out;
3752 }
3753
3754/* BB check that data area is minimum length and as big as acl_len */
3755
af6f4612 3756 acl_len = le32_to_cpu(*parm);
630f3f0c 3757 if (acl_len != *pbuflen) {
b6b38f70
JP
3758 cERROR(1, "acl length %d does not match %d",
3759 acl_len, *pbuflen);
630f3f0c
SF
3760 if (*pbuflen > acl_len)
3761 *pbuflen = acl_len;
3762 }
0a4b92c0 3763
630f3f0c
SF
3764 /* check if buffer is big enough for the acl
3765 header followed by the smallest SID */
3766 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3767 (*pbuflen >= 64 * 1024)) {
b6b38f70 3768 cERROR(1, "bad acl length %d", *pbuflen);
630f3f0c
SF
3769 rc = -EINVAL;
3770 *pbuflen = 0;
3771 } else {
3772 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3773 if (*acl_inf == NULL) {
3774 *pbuflen = 0;
3775 rc = -ENOMEM;
3776 }
3777 memcpy(*acl_inf, pdata, *pbuflen);
3778 }
0a4b92c0
SF
3779 }
3780qsec_out:
790fe579 3781 if (buf_type == CIFS_SMALL_BUFFER)
0a4b92c0 3782 cifs_small_buf_release(iov[0].iov_base);
790fe579 3783 else if (buf_type == CIFS_LARGE_BUFFER)
0a4b92c0 3784 cifs_buf_release(iov[0].iov_base);
4b8f930f 3785/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
0a4b92c0
SF
3786 return rc;
3787}
97837582
SF
3788
3789int
96daf2b0 3790CIFSSMBSetCIFSACL(const int xid, struct cifs_tcon *tcon, __u16 fid,
a5ff3769 3791 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
97837582
SF
3792{
3793 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3794 int rc = 0;
3795 int bytes_returned = 0;
3796 SET_SEC_DESC_REQ *pSMB = NULL;
b2a3ad9c 3797 void *pSMBr;
97837582
SF
3798
3799setCifsAclRetry:
b2a3ad9c 3800 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
97837582 3801 if (rc)
b2a3ad9c 3802 return rc;
97837582
SF
3803
3804 pSMB->MaxSetupCount = 0;
3805 pSMB->Reserved = 0;
3806
3807 param_count = 8;
3808 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3809 data_count = acllen;
3810 data_offset = param_offset + param_count;
3811 byte_count = 3 /* pad */ + param_count;
3812
3813 pSMB->DataCount = cpu_to_le32(data_count);
3814 pSMB->TotalDataCount = pSMB->DataCount;
3815 pSMB->MaxParameterCount = cpu_to_le32(4);
3816 pSMB->MaxDataCount = cpu_to_le32(16384);
3817 pSMB->ParameterCount = cpu_to_le32(param_count);
3818 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3819 pSMB->TotalParameterCount = pSMB->ParameterCount;
3820 pSMB->DataOffset = cpu_to_le32(data_offset);
3821 pSMB->SetupCount = 0;
3822 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3823 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3824
3825 pSMB->Fid = fid; /* file handle always le */
3826 pSMB->Reserved2 = 0;
a5ff3769 3827 pSMB->AclFlags = cpu_to_le32(aclflag);
97837582
SF
3828
3829 if (pntsd && acllen) {
b2a3ad9c
JL
3830 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3831 data_offset, pntsd, acllen);
be8e3b00 3832 inc_rfc1001_len(pSMB, byte_count + data_count);
97837582 3833 } else
be8e3b00 3834 inc_rfc1001_len(pSMB, byte_count);
97837582
SF
3835
3836 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3837 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3838
b6b38f70 3839 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
97837582 3840 if (rc)
b6b38f70 3841 cFYI(1, "Set CIFS ACL returned %d", rc);
97837582
SF
3842 cifs_buf_release(pSMB);
3843
3844 if (rc == -EAGAIN)
3845 goto setCifsAclRetry;
3846
3847 return (rc);
3848}
3849
79df1bae 3850#endif /* CONFIG_CIFS_ACL */
0a4b92c0 3851
6b8edfe0
SF
3852/* Legacy Query Path Information call for lookup to old servers such
3853 as Win9x/WinME */
96daf2b0 3854int SMBQueryInformation(const int xid, struct cifs_tcon *tcon,
50c2f753
SF
3855 const unsigned char *searchName,
3856 FILE_ALL_INFO *pFinfo,
3857 const struct nls_table *nls_codepage, int remap)
6b8edfe0 3858{
ad7a2926
SF
3859 QUERY_INFORMATION_REQ *pSMB;
3860 QUERY_INFORMATION_RSP *pSMBr;
6b8edfe0
SF
3861 int rc = 0;
3862 int bytes_returned;
3863 int name_len;
3864
b6b38f70 3865 cFYI(1, "In SMBQPath path %s", searchName);
6b8edfe0
SF
3866QInfRetry:
3867 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
50c2f753 3868 (void **) &pSMBr);
6b8edfe0
SF
3869 if (rc)
3870 return rc;
3871
3872 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3873 name_len =
acbbb76a
SF
3874 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3875 searchName, PATH_MAX, nls_codepage,
3876 remap);
6b8edfe0
SF
3877 name_len++; /* trailing null */
3878 name_len *= 2;
50c2f753 3879 } else {
6b8edfe0
SF
3880 name_len = strnlen(searchName, PATH_MAX);
3881 name_len++; /* trailing null */
3882 strncpy(pSMB->FileName, searchName, name_len);
3883 }
3884 pSMB->BufferFormat = 0x04;
50c2f753 3885 name_len++; /* account for buffer type byte */
be8e3b00 3886 inc_rfc1001_len(pSMB, (__u16)name_len);
6b8edfe0
SF
3887 pSMB->ByteCount = cpu_to_le16(name_len);
3888
3889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 3890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6b8edfe0 3891 if (rc) {
b6b38f70 3892 cFYI(1, "Send error in QueryInfo = %d", rc);
ad7a2926 3893 } else if (pFinfo) {
1bd5bbcb
SF
3894 struct timespec ts;
3895 __u32 time = le32_to_cpu(pSMBr->last_write_time);
ad7a2926
SF
3896
3897 /* decode response */
1bd5bbcb 3898 /* BB FIXME - add time zone adjustment BB */
6b8edfe0 3899 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
1bd5bbcb
SF
3900 ts.tv_nsec = 0;
3901 ts.tv_sec = time;
3902 /* decode time fields */
733f99ac 3903 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
1bd5bbcb
SF
3904 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3905 pFinfo->LastAccessTime = 0;
70ca734a
SF
3906 pFinfo->AllocationSize =
3907 cpu_to_le64(le32_to_cpu(pSMBr->size));
3908 pFinfo->EndOfFile = pFinfo->AllocationSize;
3909 pFinfo->Attributes =
3910 cpu_to_le32(le16_to_cpu(pSMBr->attr));
6b8edfe0
SF
3911 } else
3912 rc = -EIO; /* bad buffer passed in */
3913
3914 cifs_buf_release(pSMB);
3915
3916 if (rc == -EAGAIN)
3917 goto QInfRetry;
3918
3919 return rc;
3920}
3921
bcd5357f 3922int
96daf2b0 3923CIFSSMBQFileInfo(const int xid, struct cifs_tcon *tcon,
bcd5357f
JL
3924 u16 netfid, FILE_ALL_INFO *pFindData)
3925{
3926 struct smb_t2_qfi_req *pSMB = NULL;
3927 struct smb_t2_qfi_rsp *pSMBr = NULL;
3928 int rc = 0;
3929 int bytes_returned;
3930 __u16 params, byte_count;
3931
3932QFileInfoRetry:
3933 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3934 (void **) &pSMBr);
3935 if (rc)
3936 return rc;
3937
3938 params = 2 /* level */ + 2 /* fid */;
3939 pSMB->t2.TotalDataCount = 0;
3940 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3941 /* BB find exact max data count below from sess structure BB */
3942 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3943 pSMB->t2.MaxSetupCount = 0;
3944 pSMB->t2.Reserved = 0;
3945 pSMB->t2.Flags = 0;
3946 pSMB->t2.Timeout = 0;
3947 pSMB->t2.Reserved2 = 0;
3948 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3949 Fid) - 4);
3950 pSMB->t2.DataCount = 0;
3951 pSMB->t2.DataOffset = 0;
3952 pSMB->t2.SetupCount = 1;
3953 pSMB->t2.Reserved3 = 0;
3954 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3955 byte_count = params + 1 /* pad */ ;
3956 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3957 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3958 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3959 pSMB->Pad = 0;
3960 pSMB->Fid = netfid;
be8e3b00 3961 inc_rfc1001_len(pSMB, byte_count);
6b8edfe0 3962
bcd5357f
JL
3963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3965 if (rc) {
f19159dc 3966 cFYI(1, "Send error in QPathInfo = %d", rc);
bcd5357f
JL
3967 } else { /* decode response */
3968 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6b8edfe0 3969
bcd5357f
JL
3970 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3971 rc = -EIO;
820a803f 3972 else if (get_bcc(&pSMBr->hdr) < 40)
bcd5357f
JL
3973 rc = -EIO; /* bad smb */
3974 else if (pFindData) {
3975 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3976 memcpy((char *) pFindData,
3977 (char *) &pSMBr->hdr.Protocol +
3978 data_offset, sizeof(FILE_ALL_INFO));
3979 } else
3980 rc = -ENOMEM;
3981 }
3982 cifs_buf_release(pSMB);
3983 if (rc == -EAGAIN)
3984 goto QFileInfoRetry;
6b8edfe0 3985
bcd5357f
JL
3986 return rc;
3987}
6b8edfe0 3988
1da177e4 3989int
96daf2b0 3990CIFSSMBQPathInfo(const int xid, struct cifs_tcon *tcon,
1da177e4 3991 const unsigned char *searchName,
ad7a2926 3992 FILE_ALL_INFO *pFindData,
acf1a1b1 3993 int legacy /* old style infolevel */,
737b758c 3994 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3995{
3996/* level 263 SMB_QUERY_FILE_ALL_INFO */
3997 TRANSACTION2_QPI_REQ *pSMB = NULL;
3998 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3999 int rc = 0;
4000 int bytes_returned;
4001 int name_len;
4002 __u16 params, byte_count;
4003
b6b38f70 4004/* cFYI(1, "In QPathInfo path %s", searchName); */
1da177e4
LT
4005QPathInfoRetry:
4006 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4007 (void **) &pSMBr);
4008 if (rc)
4009 return rc;
4010
4011 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4012 name_len =
acbbb76a
SF
4013 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4014 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4015 name_len++; /* trailing null */
4016 name_len *= 2;
50c2f753 4017 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4018 name_len = strnlen(searchName, PATH_MAX);
4019 name_len++; /* trailing null */
4020 strncpy(pSMB->FileName, searchName, name_len);
4021 }
4022
50c2f753 4023 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
4024 pSMB->TotalDataCount = 0;
4025 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4026 /* BB find exact max SMB PDU from sess structure BB */
4027 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4028 pSMB->MaxSetupCount = 0;
4029 pSMB->Reserved = 0;
4030 pSMB->Flags = 0;
4031 pSMB->Timeout = 0;
4032 pSMB->Reserved2 = 0;
4033 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4034 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
4035 pSMB->DataCount = 0;
4036 pSMB->DataOffset = 0;
4037 pSMB->SetupCount = 1;
4038 pSMB->Reserved3 = 0;
4039 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4040 byte_count = params + 1 /* pad */ ;
4041 pSMB->TotalParameterCount = cpu_to_le16(params);
4042 pSMB->ParameterCount = pSMB->TotalParameterCount;
790fe579 4043 if (legacy)
acf1a1b1
SF
4044 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4045 else
4046 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
1da177e4 4047 pSMB->Reserved4 = 0;
be8e3b00 4048 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4049 pSMB->ByteCount = cpu_to_le16(byte_count);
4050
4051 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4052 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4053 if (rc) {
b6b38f70 4054 cFYI(1, "Send error in QPathInfo = %d", rc);
1da177e4
LT
4055 } else { /* decode response */
4056 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4057
acf1a1b1
SF
4058 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4059 rc = -EIO;
820a803f 4060 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
1da177e4 4061 rc = -EIO; /* bad smb */
820a803f 4062 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
50c2f753
SF
4063 rc = -EIO; /* 24 or 26 expected but we do not read
4064 last field */
4065 else if (pFindData) {
acf1a1b1 4066 int size;
1da177e4 4067 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
ad7a2926
SF
4068
4069 /* On legacy responses we do not read the last field,
4070 EAsize, fortunately since it varies by subdialect and
4071 also note it differs on Set vs. Get, ie two bytes or 4
4072 bytes depending but we don't care here */
4073 if (legacy)
acf1a1b1
SF
4074 size = sizeof(FILE_INFO_STANDARD);
4075 else
4076 size = sizeof(FILE_ALL_INFO);
1da177e4
LT
4077 memcpy((char *) pFindData,
4078 (char *) &pSMBr->hdr.Protocol +
acf1a1b1 4079 data_offset, size);
1da177e4
LT
4080 } else
4081 rc = -ENOMEM;
4082 }
4083 cifs_buf_release(pSMB);
4084 if (rc == -EAGAIN)
4085 goto QPathInfoRetry;
4086
4087 return rc;
4088}
4089
c8634fd3 4090int
96daf2b0 4091CIFSSMBUnixQFileInfo(const int xid, struct cifs_tcon *tcon,
c8634fd3
JL
4092 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4093{
4094 struct smb_t2_qfi_req *pSMB = NULL;
4095 struct smb_t2_qfi_rsp *pSMBr = NULL;
4096 int rc = 0;
4097 int bytes_returned;
4098 __u16 params, byte_count;
4099
4100UnixQFileInfoRetry:
4101 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4102 (void **) &pSMBr);
4103 if (rc)
4104 return rc;
4105
4106 params = 2 /* level */ + 2 /* fid */;
4107 pSMB->t2.TotalDataCount = 0;
4108 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4109 /* BB find exact max data count below from sess structure BB */
4110 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4111 pSMB->t2.MaxSetupCount = 0;
4112 pSMB->t2.Reserved = 0;
4113 pSMB->t2.Flags = 0;
4114 pSMB->t2.Timeout = 0;
4115 pSMB->t2.Reserved2 = 0;
4116 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4117 Fid) - 4);
4118 pSMB->t2.DataCount = 0;
4119 pSMB->t2.DataOffset = 0;
4120 pSMB->t2.SetupCount = 1;
4121 pSMB->t2.Reserved3 = 0;
4122 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4123 byte_count = params + 1 /* pad */ ;
4124 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4125 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4126 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4127 pSMB->Pad = 0;
4128 pSMB->Fid = netfid;
be8e3b00 4129 inc_rfc1001_len(pSMB, byte_count);
c8634fd3
JL
4130
4131 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4132 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4133 if (rc) {
f19159dc 4134 cFYI(1, "Send error in QPathInfo = %d", rc);
c8634fd3
JL
4135 } else { /* decode response */
4136 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4137
820a803f 4138 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
ac3aa2f8 4139 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
c8634fd3 4140 "Unix Extensions can be disabled on mount "
f19159dc 4141 "by specifying the nosfu mount option.");
c8634fd3
JL
4142 rc = -EIO; /* bad smb */
4143 } else {
4144 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4145 memcpy((char *) pFindData,
4146 (char *) &pSMBr->hdr.Protocol +
4147 data_offset,
4148 sizeof(FILE_UNIX_BASIC_INFO));
4149 }
4150 }
4151
4152 cifs_buf_release(pSMB);
4153 if (rc == -EAGAIN)
4154 goto UnixQFileInfoRetry;
4155
4156 return rc;
4157}
4158
1da177e4 4159int
96daf2b0 4160CIFSSMBUnixQPathInfo(const int xid, struct cifs_tcon *tcon,
1da177e4 4161 const unsigned char *searchName,
582d21e5 4162 FILE_UNIX_BASIC_INFO *pFindData,
737b758c 4163 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4164{
4165/* SMB_QUERY_FILE_UNIX_BASIC */
4166 TRANSACTION2_QPI_REQ *pSMB = NULL;
4167 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4168 int rc = 0;
4169 int bytes_returned = 0;
4170 int name_len;
4171 __u16 params, byte_count;
4172
b6b38f70 4173 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
1da177e4
LT
4174UnixQPathInfoRetry:
4175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4176 (void **) &pSMBr);
4177 if (rc)
4178 return rc;
4179
4180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4181 name_len =
acbbb76a
SF
4182 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4183 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4184 name_len++; /* trailing null */
4185 name_len *= 2;
50c2f753 4186 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4187 name_len = strnlen(searchName, PATH_MAX);
4188 name_len++; /* trailing null */
4189 strncpy(pSMB->FileName, searchName, name_len);
4190 }
4191
50c2f753 4192 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
4193 pSMB->TotalDataCount = 0;
4194 pSMB->MaxParameterCount = cpu_to_le16(2);
4195 /* BB find exact max SMB PDU from sess structure BB */
50c2f753 4196 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4197 pSMB->MaxSetupCount = 0;
4198 pSMB->Reserved = 0;
4199 pSMB->Flags = 0;
4200 pSMB->Timeout = 0;
4201 pSMB->Reserved2 = 0;
4202 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4203 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
4204 pSMB->DataCount = 0;
4205 pSMB->DataOffset = 0;
4206 pSMB->SetupCount = 1;
4207 pSMB->Reserved3 = 0;
4208 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4209 byte_count = params + 1 /* pad */ ;
4210 pSMB->TotalParameterCount = cpu_to_le16(params);
4211 pSMB->ParameterCount = pSMB->TotalParameterCount;
4212 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4213 pSMB->Reserved4 = 0;
be8e3b00 4214 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4215 pSMB->ByteCount = cpu_to_le16(byte_count);
4216
4217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4219 if (rc) {
b6b38f70 4220 cFYI(1, "Send error in QPathInfo = %d", rc);
1da177e4
LT
4221 } else { /* decode response */
4222 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4223
820a803f 4224 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
ac3aa2f8 4225 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
1e71f25d 4226 "Unix Extensions can be disabled on mount "
b6b38f70 4227 "by specifying the nosfu mount option.");
1da177e4
LT
4228 rc = -EIO; /* bad smb */
4229 } else {
4230 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4231 memcpy((char *) pFindData,
4232 (char *) &pSMBr->hdr.Protocol +
4233 data_offset,
630f3f0c 4234 sizeof(FILE_UNIX_BASIC_INFO));
1da177e4
LT
4235 }
4236 }
4237 cifs_buf_release(pSMB);
4238 if (rc == -EAGAIN)
4239 goto UnixQPathInfoRetry;
4240
4241 return rc;
4242}
4243
1da177e4
LT
4244/* xid, tcon, searchName and codepage are input parms, rest are returned */
4245int
96daf2b0 4246CIFSFindFirst(const int xid, struct cifs_tcon *tcon,
50c2f753 4247 const char *searchName,
1da177e4 4248 const struct nls_table *nls_codepage,
2608bee7 4249 __u16 *pnetfid, __u16 search_flags,
50c2f753 4250 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
1da177e4
LT
4251{
4252/* level 257 SMB_ */
4253 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4254 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
ad7a2926 4255 T2_FFIRST_RSP_PARMS *parms;
1da177e4
LT
4256 int rc = 0;
4257 int bytes_returned = 0;
4258 int name_len;
4259 __u16 params, byte_count;
4260
b6b38f70 4261 cFYI(1, "In FindFirst for %s", searchName);
1da177e4
LT
4262
4263findFirstRetry:
4264 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4265 (void **) &pSMBr);
4266 if (rc)
4267 return rc;
4268
4269 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4270 name_len =
acbbb76a
SF
4271 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4272 PATH_MAX, nls_codepage, remap);
737b758c
SF
4273 /* We can not add the asterik earlier in case
4274 it got remapped to 0xF03A as if it were part of the
4275 directory name instead of a wildcard */
1da177e4 4276 name_len *= 2;
ac67055e 4277 pSMB->FileName[name_len] = dirsep;
737b758c
SF
4278 pSMB->FileName[name_len+1] = 0;
4279 pSMB->FileName[name_len+2] = '*';
4280 pSMB->FileName[name_len+3] = 0;
4281 name_len += 4; /* now the trailing null */
1da177e4
LT
4282 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4283 pSMB->FileName[name_len+1] = 0;
737b758c 4284 name_len += 2;
1da177e4
LT
4285 } else { /* BB add check for overrun of SMB buf BB */
4286 name_len = strnlen(searchName, PATH_MAX);
1da177e4 4287/* BB fix here and in unicode clause above ie
790fe579 4288 if (name_len > buffersize-header)
1da177e4
LT
4289 free buffer exit; BB */
4290 strncpy(pSMB->FileName, searchName, name_len);
ac67055e 4291 pSMB->FileName[name_len] = dirsep;
68575476
SF
4292 pSMB->FileName[name_len+1] = '*';
4293 pSMB->FileName[name_len+2] = 0;
4294 name_len += 3;
1da177e4
LT
4295 }
4296
4297 params = 12 + name_len /* includes null */ ;
4298 pSMB->TotalDataCount = 0; /* no EAs */
4299 pSMB->MaxParameterCount = cpu_to_le16(10);
c974befa 4300 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
1da177e4
LT
4301 pSMB->MaxSetupCount = 0;
4302 pSMB->Reserved = 0;
4303 pSMB->Flags = 0;
4304 pSMB->Timeout = 0;
4305 pSMB->Reserved2 = 0;
4306 byte_count = params + 1 /* pad */ ;
4307 pSMB->TotalParameterCount = cpu_to_le16(params);
4308 pSMB->ParameterCount = pSMB->TotalParameterCount;
4309 pSMB->ParameterOffset = cpu_to_le16(
88274815
SF
4310 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4311 - 4);
1da177e4
LT
4312 pSMB->DataCount = 0;
4313 pSMB->DataOffset = 0;
4314 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4315 pSMB->Reserved3 = 0;
4316 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4317 pSMB->SearchAttributes =
4318 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4319 ATTR_DIRECTORY);
50c2f753 4320 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2608bee7 4321 pSMB->SearchFlags = cpu_to_le16(search_flags);
1da177e4
LT
4322 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4323
4324 /* BB what should we set StorageType to? Does it matter? BB */
4325 pSMB->SearchStorageType = 0;
be8e3b00 4326 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4327 pSMB->ByteCount = cpu_to_le16(byte_count);
4328
4329 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4330 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 4331 cifs_stats_inc(&tcon->num_ffirst);
1da177e4 4332
88274815
SF
4333 if (rc) {/* BB add logic to retry regular search if Unix search
4334 rejected unexpectedly by server */
1da177e4 4335 /* BB Add code to handle unsupported level rc */
b6b38f70 4336 cFYI(1, "Error in FindFirst = %d", rc);
1982c344 4337
88274815 4338 cifs_buf_release(pSMB);
1da177e4
LT
4339
4340 /* BB eventually could optimize out free and realloc of buf */
4341 /* for this case */
4342 if (rc == -EAGAIN)
4343 goto findFirstRetry;
4344 } else { /* decode response */
4345 /* BB remember to free buffer if error BB */
4346 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
790fe579 4347 if (rc == 0) {
b77d753c
SF
4348 unsigned int lnoff;
4349
1da177e4 4350 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 4351 psrch_inf->unicode = true;
1da177e4 4352 else
4b18f2a9 4353 psrch_inf->unicode = false;
1da177e4
LT
4354
4355 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
d47d7c1a 4356 psrch_inf->smallBuf = 0;
50c2f753
SF
4357 psrch_inf->srch_entries_start =
4358 (char *) &pSMBr->hdr.Protocol +
1da177e4 4359 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
4360 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4361 le16_to_cpu(pSMBr->t2.ParameterOffset));
4362
790fe579 4363 if (parms->EndofSearch)
4b18f2a9 4364 psrch_inf->endOfSearch = true;
1da177e4 4365 else
4b18f2a9 4366 psrch_inf->endOfSearch = false;
1da177e4 4367
50c2f753
SF
4368 psrch_inf->entries_in_buffer =
4369 le16_to_cpu(parms->SearchCount);
60808233 4370 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
1da177e4 4371 psrch_inf->entries_in_buffer;
b77d753c 4372 lnoff = le16_to_cpu(parms->LastNameOffset);
c974befa 4373 if (CIFSMaxBufSize < lnoff) {
b6b38f70 4374 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
4375 psrch_inf->last_entry = NULL;
4376 return rc;
4377 }
4378
0752f152 4379 psrch_inf->last_entry = psrch_inf->srch_entries_start +
b77d753c
SF
4380 lnoff;
4381
1da177e4
LT
4382 *pnetfid = parms->SearchHandle;
4383 } else {
4384 cifs_buf_release(pSMB);
4385 }
4386 }
4387
4388 return rc;
4389}
4390
2608bee7
SP
4391int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
4392 __u16 search_flags, struct cifs_search_info *psrch_inf)
1da177e4
LT
4393{
4394 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4395 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
ad7a2926 4396 T2_FNEXT_RSP_PARMS *parms;
1da177e4
LT
4397 char *response_data;
4398 int rc = 0;
9438fabb
JL
4399 int bytes_returned;
4400 unsigned int name_len;
1da177e4
LT
4401 __u16 params, byte_count;
4402
b6b38f70 4403 cFYI(1, "In FindNext");
1da177e4 4404
4b18f2a9 4405 if (psrch_inf->endOfSearch)
1da177e4
LT
4406 return -ENOENT;
4407
4408 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4409 (void **) &pSMBr);
4410 if (rc)
4411 return rc;
4412
50c2f753 4413 params = 14; /* includes 2 bytes of null string, converted to LE below*/
1da177e4
LT
4414 byte_count = 0;
4415 pSMB->TotalDataCount = 0; /* no EAs */
4416 pSMB->MaxParameterCount = cpu_to_le16(8);
c974befa 4417 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
1da177e4
LT
4418 pSMB->MaxSetupCount = 0;
4419 pSMB->Reserved = 0;
4420 pSMB->Flags = 0;
4421 pSMB->Timeout = 0;
4422 pSMB->Reserved2 = 0;
4423 pSMB->ParameterOffset = cpu_to_le16(
4424 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4425 pSMB->DataCount = 0;
4426 pSMB->DataOffset = 0;
4427 pSMB->SetupCount = 1;
4428 pSMB->Reserved3 = 0;
4429 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4430 pSMB->SearchHandle = searchHandle; /* always kept as le */
4431 pSMB->SearchCount =
630f3f0c 4432 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
1da177e4
LT
4433 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4434 pSMB->ResumeKey = psrch_inf->resume_key;
2608bee7 4435 pSMB->SearchFlags = cpu_to_le16(search_flags);
1da177e4
LT
4436
4437 name_len = psrch_inf->resume_name_len;
4438 params += name_len;
790fe579 4439 if (name_len < PATH_MAX) {
1da177e4
LT
4440 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4441 byte_count += name_len;
ef6724e3
SF
4442 /* 14 byte parm len above enough for 2 byte null terminator */
4443 pSMB->ResumeFileName[name_len] = 0;
4444 pSMB->ResumeFileName[name_len+1] = 0;
1da177e4
LT
4445 } else {
4446 rc = -EINVAL;
4447 goto FNext2_err_exit;
4448 }
4449 byte_count = params + 1 /* pad */ ;
4450 pSMB->TotalParameterCount = cpu_to_le16(params);
4451 pSMB->ParameterCount = pSMB->TotalParameterCount;
be8e3b00 4452 inc_rfc1001_len(pSMB, byte_count);
1da177e4 4453 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 4454
1da177e4
LT
4455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 4457 cifs_stats_inc(&tcon->num_fnext);
1da177e4
LT
4458 if (rc) {
4459 if (rc == -EBADF) {
4b18f2a9 4460 psrch_inf->endOfSearch = true;
6353450a 4461 cifs_buf_release(pSMB);
50c2f753 4462 rc = 0; /* search probably was closed at end of search*/
1da177e4 4463 } else
b6b38f70 4464 cFYI(1, "FindNext returned = %d", rc);
1da177e4
LT
4465 } else { /* decode response */
4466 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50c2f753 4467
790fe579 4468 if (rc == 0) {
b77d753c
SF
4469 unsigned int lnoff;
4470
1da177e4
LT
4471 /* BB fixme add lock for file (srch_info) struct here */
4472 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 4473 psrch_inf->unicode = true;
1da177e4 4474 else
4b18f2a9 4475 psrch_inf->unicode = false;
1da177e4
LT
4476 response_data = (char *) &pSMBr->hdr.Protocol +
4477 le16_to_cpu(pSMBr->t2.ParameterOffset);
4478 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4479 response_data = (char *)&pSMBr->hdr.Protocol +
4480 le16_to_cpu(pSMBr->t2.DataOffset);
790fe579 4481 if (psrch_inf->smallBuf)
d47d7c1a
SF
4482 cifs_small_buf_release(
4483 psrch_inf->ntwrk_buf_start);
4484 else
4485 cifs_buf_release(psrch_inf->ntwrk_buf_start);
1da177e4
LT
4486 psrch_inf->srch_entries_start = response_data;
4487 psrch_inf->ntwrk_buf_start = (char *)pSMB;
d47d7c1a 4488 psrch_inf->smallBuf = 0;
790fe579 4489 if (parms->EndofSearch)
4b18f2a9 4490 psrch_inf->endOfSearch = true;
1da177e4 4491 else
4b18f2a9 4492 psrch_inf->endOfSearch = false;
50c2f753
SF
4493 psrch_inf->entries_in_buffer =
4494 le16_to_cpu(parms->SearchCount);
1da177e4
LT
4495 psrch_inf->index_of_last_entry +=
4496 psrch_inf->entries_in_buffer;
b77d753c 4497 lnoff = le16_to_cpu(parms->LastNameOffset);
c974befa 4498 if (CIFSMaxBufSize < lnoff) {
b6b38f70 4499 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
4500 psrch_inf->last_entry = NULL;
4501 return rc;
4502 } else
4503 psrch_inf->last_entry =
4504 psrch_inf->srch_entries_start + lnoff;
4505
b6b38f70
JP
4506/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4507 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
1da177e4
LT
4508
4509 /* BB fixme add unlock here */
4510 }
4511
4512 }
4513
4514 /* BB On error, should we leave previous search buf (and count and
4515 last entry fields) intact or free the previous one? */
4516
4517 /* Note: On -EAGAIN error only caller can retry on handle based calls
4518 since file handle passed in no longer valid */
4519FNext2_err_exit:
4520 if (rc != 0)
4521 cifs_buf_release(pSMB);
1da177e4
LT
4522 return rc;
4523}
4524
4525int
96daf2b0 4526CIFSFindClose(const int xid, struct cifs_tcon *tcon,
50c2f753 4527 const __u16 searchHandle)
1da177e4
LT
4528{
4529 int rc = 0;
4530 FINDCLOSE_REQ *pSMB = NULL;
1da177e4 4531
b6b38f70 4532 cFYI(1, "In CIFSSMBFindClose");
1da177e4
LT
4533 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4534
4535 /* no sense returning error if session restarted
4536 as file handle has been closed */
790fe579 4537 if (rc == -EAGAIN)
1da177e4
LT
4538 return 0;
4539 if (rc)
4540 return rc;
4541
1da177e4
LT
4542 pSMB->FileID = searchHandle;
4543 pSMB->ByteCount = 0;
792af7b0 4544 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
ad7a2926 4545 if (rc)
b6b38f70 4546 cERROR(1, "Send error in FindClose = %d", rc);
ad7a2926 4547
a4544347 4548 cifs_stats_inc(&tcon->num_fclose);
1da177e4
LT
4549
4550 /* Since session is dead, search handle closed on server already */
4551 if (rc == -EAGAIN)
4552 rc = 0;
4553
4554 return rc;
4555}
4556
1da177e4 4557int
96daf2b0 4558CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
50c2f753 4559 const unsigned char *searchName,
ad7a2926 4560 __u64 *inode_number,
50c2f753 4561 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4562{
4563 int rc = 0;
4564 TRANSACTION2_QPI_REQ *pSMB = NULL;
4565 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4566 int name_len, bytes_returned;
4567 __u16 params, byte_count;
4568
b6b38f70 4569 cFYI(1, "In GetSrvInodeNum for %s", searchName);
790fe579 4570 if (tcon == NULL)
50c2f753 4571 return -ENODEV;
1da177e4
LT
4572
4573GetInodeNumberRetry:
4574 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 4575 (void **) &pSMBr);
1da177e4
LT
4576 if (rc)
4577 return rc;
4578
1da177e4
LT
4579 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4580 name_len =
acbbb76a
SF
4581 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4582 searchName, PATH_MAX, nls_codepage,
4583 remap);
1da177e4
LT
4584 name_len++; /* trailing null */
4585 name_len *= 2;
50c2f753 4586 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4587 name_len = strnlen(searchName, PATH_MAX);
4588 name_len++; /* trailing null */
4589 strncpy(pSMB->FileName, searchName, name_len);
4590 }
4591
4592 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4593 pSMB->TotalDataCount = 0;
4594 pSMB->MaxParameterCount = cpu_to_le16(2);
4595 /* BB find exact max data count below from sess structure BB */
4596 pSMB->MaxDataCount = cpu_to_le16(4000);
4597 pSMB->MaxSetupCount = 0;
4598 pSMB->Reserved = 0;
4599 pSMB->Flags = 0;
4600 pSMB->Timeout = 0;
4601 pSMB->Reserved2 = 0;
4602 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4603 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
4604 pSMB->DataCount = 0;
4605 pSMB->DataOffset = 0;
4606 pSMB->SetupCount = 1;
4607 pSMB->Reserved3 = 0;
4608 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4609 byte_count = params + 1 /* pad */ ;
4610 pSMB->TotalParameterCount = cpu_to_le16(params);
4611 pSMB->ParameterCount = pSMB->TotalParameterCount;
4612 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4613 pSMB->Reserved4 = 0;
be8e3b00 4614 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4615 pSMB->ByteCount = cpu_to_le16(byte_count);
4616
4617 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4618 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4619 if (rc) {
b6b38f70 4620 cFYI(1, "error %d in QueryInternalInfo", rc);
1da177e4
LT
4621 } else {
4622 /* decode response */
4623 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4624 /* BB also check enough total bytes returned */
820a803f 4625 if (rc || get_bcc(&pSMBr->hdr) < 2)
1da177e4
LT
4626 /* If rc should we check for EOPNOSUPP and
4627 disable the srvino flag? or in caller? */
4628 rc = -EIO; /* bad smb */
50c2f753 4629 else {
1da177e4
LT
4630 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4631 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
50c2f753 4632 struct file_internal_info *pfinfo;
1da177e4 4633 /* BB Do we need a cast or hash here ? */
790fe579 4634 if (count < 8) {
b6b38f70 4635 cFYI(1, "Illegal size ret in QryIntrnlInf");
1da177e4
LT
4636 rc = -EIO;
4637 goto GetInodeNumOut;
4638 }
4639 pfinfo = (struct file_internal_info *)
4640 (data_offset + (char *) &pSMBr->hdr.Protocol);
85a6dac5 4641 *inode_number = le64_to_cpu(pfinfo->UniqueId);
1da177e4
LT
4642 }
4643 }
4644GetInodeNumOut:
4645 cifs_buf_release(pSMB);
4646 if (rc == -EAGAIN)
4647 goto GetInodeNumberRetry;
4648 return rc;
4649}
1da177e4 4650
fec4585f
IM
4651/* parses DFS refferal V3 structure
4652 * caller is responsible for freeing target_nodes
4653 * returns:
4654 * on success - 0
4655 * on failure - errno
4656 */
4657static int
a1fe78f1 4658parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
fec4585f
IM
4659 unsigned int *num_of_nodes,
4660 struct dfs_info3_param **target_nodes,
2c55608f
IM
4661 const struct nls_table *nls_codepage, int remap,
4662 const char *searchName)
fec4585f
IM
4663{
4664 int i, rc = 0;
4665 char *data_end;
4666 bool is_unicode;
4667 struct dfs_referral_level_3 *ref;
4668
5ca33c6a
HH
4669 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4670 is_unicode = true;
4671 else
4672 is_unicode = false;
fec4585f
IM
4673 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4674
4675 if (*num_of_nodes < 1) {
b6b38f70 4676 cERROR(1, "num_referrals: must be at least > 0,"
ac3aa2f8 4677 "but we get num_referrals = %d", *num_of_nodes);
fec4585f 4678 rc = -EINVAL;
a1fe78f1 4679 goto parse_DFS_referrals_exit;
fec4585f
IM
4680 }
4681
4682 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
1d92cfd5 4683 if (ref->VersionNumber != cpu_to_le16(3)) {
b6b38f70
JP
4684 cERROR(1, "Referrals of V%d version are not supported,"
4685 "should be V3", le16_to_cpu(ref->VersionNumber));
fec4585f 4686 rc = -EINVAL;
a1fe78f1 4687 goto parse_DFS_referrals_exit;
fec4585f
IM
4688 }
4689
4690 /* get the upper boundary of the resp buffer */
4691 data_end = (char *)(&(pSMBr->PathConsumed)) +
4692 le16_to_cpu(pSMBr->t2.DataCount);
4693
ac3aa2f8 4694 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
fec4585f 4695 *num_of_nodes,
b6b38f70 4696 le32_to_cpu(pSMBr->DFSFlags));
fec4585f
IM
4697
4698 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4699 *num_of_nodes, GFP_KERNEL);
4700 if (*target_nodes == NULL) {
ac3aa2f8 4701 cERROR(1, "Failed to allocate buffer for target_nodes");
fec4585f 4702 rc = -ENOMEM;
a1fe78f1 4703 goto parse_DFS_referrals_exit;
fec4585f
IM
4704 }
4705
3ad2f3fb 4706 /* collect necessary data from referrals */
fec4585f
IM
4707 for (i = 0; i < *num_of_nodes; i++) {
4708 char *temp;
4709 int max_len;
4710 struct dfs_info3_param *node = (*target_nodes)+i;
4711
0e0d2cf3 4712 node->flags = le32_to_cpu(pSMBr->DFSFlags);
2c55608f 4713 if (is_unicode) {
331c3135
JL
4714 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4715 GFP_KERNEL);
2920ee2b
SF
4716 if (tmp == NULL) {
4717 rc = -ENOMEM;
4718 goto parse_DFS_referrals_exit;
4719 }
acbbb76a
SF
4720 cifsConvertToUTF16((__le16 *) tmp, searchName,
4721 PATH_MAX, nls_codepage, remap);
4722 node->path_consumed = cifs_utf16_bytes(tmp,
69f801fc 4723 le16_to_cpu(pSMBr->PathConsumed),
2c55608f
IM
4724 nls_codepage);
4725 kfree(tmp);
4726 } else
4727 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4728
fec4585f
IM
4729 node->server_type = le16_to_cpu(ref->ServerType);
4730 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4731
4732 /* copy DfsPath */
4733 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4734 max_len = data_end - temp;
acbbb76a
SF
4735 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4736 is_unicode, nls_codepage);
d8e2f53a
JL
4737 if (!node->path_name) {
4738 rc = -ENOMEM;
a1fe78f1 4739 goto parse_DFS_referrals_exit;
066ce689 4740 }
fec4585f
IM
4741
4742 /* copy link target UNC */
4743 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4744 max_len = data_end - temp;
acbbb76a
SF
4745 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4746 is_unicode, nls_codepage);
d8f2799b 4747 if (!node->node_name) {
d8e2f53a 4748 rc = -ENOMEM;
d8f2799b
SM
4749 goto parse_DFS_referrals_exit;
4750 }
4751
4752 ref++;
fec4585f
IM
4753 }
4754
a1fe78f1 4755parse_DFS_referrals_exit:
fec4585f
IM
4756 if (rc) {
4757 free_dfs_info_array(*target_nodes, *num_of_nodes);
4758 *target_nodes = NULL;
4759 *num_of_nodes = 0;
4760 }
4761 return rc;
4762}
4763
1da177e4 4764int
96daf2b0 4765CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
1da177e4 4766 const unsigned char *searchName,
c2cf07d5
SF
4767 struct dfs_info3_param **target_nodes,
4768 unsigned int *num_of_nodes,
737b758c 4769 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4770{
4771/* TRANS2_GET_DFS_REFERRAL */
4772 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4773 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
1da177e4
LT
4774 int rc = 0;
4775 int bytes_returned;
4776 int name_len;
1da177e4 4777 __u16 params, byte_count;
c2cf07d5
SF
4778 *num_of_nodes = 0;
4779 *target_nodes = NULL;
1da177e4 4780
b6b38f70 4781 cFYI(1, "In GetDFSRefer the path %s", searchName);
1da177e4
LT
4782 if (ses == NULL)
4783 return -ENODEV;
4784getDFSRetry:
4785 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4786 (void **) &pSMBr);
4787 if (rc)
4788 return rc;
50c2f753
SF
4789
4790 /* server pointer checked in called function,
1982c344 4791 but should never be null here anyway */
88257360 4792 pSMB->hdr.Mid = get_next_mid(ses->server);
1da177e4
LT
4793 pSMB->hdr.Tid = ses->ipc_tid;
4794 pSMB->hdr.Uid = ses->Suid;
26f57364 4795 if (ses->capabilities & CAP_STATUS32)
1da177e4 4796 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
26f57364 4797 if (ses->capabilities & CAP_DFS)
1da177e4 4798 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
1da177e4
LT
4799
4800 if (ses->capabilities & CAP_UNICODE) {
4801 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4802 name_len =
acbbb76a
SF
4803 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4804 searchName, PATH_MAX, nls_codepage,
4805 remap);
1da177e4
LT
4806 name_len++; /* trailing null */
4807 name_len *= 2;
50c2f753 4808 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4809 name_len = strnlen(searchName, PATH_MAX);
4810 name_len++; /* trailing null */
4811 strncpy(pSMB->RequestFileName, searchName, name_len);
4812 }
4813
790fe579 4814 if (ses->server) {
96daf2b0 4815 if (ses->server->sec_mode &
1a4e15a0
SF
4816 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4817 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4818 }
4819
50c2f753 4820 pSMB->hdr.Uid = ses->Suid;
1a4e15a0 4821
1da177e4
LT
4822 params = 2 /* level */ + name_len /*includes null */ ;
4823 pSMB->TotalDataCount = 0;
4824 pSMB->DataCount = 0;
4825 pSMB->DataOffset = 0;
4826 pSMB->MaxParameterCount = 0;
582d21e5
SF
4827 /* BB find exact max SMB PDU from sess structure BB */
4828 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4829 pSMB->MaxSetupCount = 0;
4830 pSMB->Reserved = 0;
4831 pSMB->Flags = 0;
4832 pSMB->Timeout = 0;
4833 pSMB->Reserved2 = 0;
4834 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4835 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
1da177e4
LT
4836 pSMB->SetupCount = 1;
4837 pSMB->Reserved3 = 0;
4838 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4839 byte_count = params + 3 /* pad */ ;
4840 pSMB->ParameterCount = cpu_to_le16(params);
4841 pSMB->TotalParameterCount = pSMB->ParameterCount;
4842 pSMB->MaxReferralLevel = cpu_to_le16(3);
be8e3b00 4843 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4844 pSMB->ByteCount = cpu_to_le16(byte_count);
4845
4846 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4847 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4848 if (rc) {
b6b38f70 4849 cFYI(1, "Send error in GetDFSRefer = %d", rc);
c2cf07d5
SF
4850 goto GetDFSRefExit;
4851 }
4852 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4853
c2cf07d5 4854 /* BB Also check if enough total bytes returned? */
820a803f 4855 if (rc || get_bcc(&pSMBr->hdr) < 17) {
c2cf07d5 4856 rc = -EIO; /* bad smb */
fec4585f
IM
4857 goto GetDFSRefExit;
4858 }
c2cf07d5 4859
b6b38f70 4860 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
820a803f 4861 get_bcc(&pSMBr->hdr),
b6b38f70 4862 le16_to_cpu(pSMBr->t2.DataOffset));
1da177e4 4863
fec4585f 4864 /* parse returned result into more usable form */
a1fe78f1 4865 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
2c55608f
IM
4866 target_nodes, nls_codepage, remap,
4867 searchName);
c2cf07d5 4868
1da177e4 4869GetDFSRefExit:
0d817bc0 4870 cifs_buf_release(pSMB);
1da177e4
LT
4871
4872 if (rc == -EAGAIN)
4873 goto getDFSRetry;
4874
4875 return rc;
4876}
4877
20962438
SF
4878/* Query File System Info such as free space to old servers such as Win 9x */
4879int
96daf2b0 4880SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
20962438
SF
4881{
4882/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4883 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4884 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4885 FILE_SYSTEM_ALLOC_INFO *response_data;
4886 int rc = 0;
4887 int bytes_returned = 0;
4888 __u16 params, byte_count;
4889
b6b38f70 4890 cFYI(1, "OldQFSInfo");
20962438
SF
4891oldQFSInfoRetry:
4892 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4893 (void **) &pSMBr);
4894 if (rc)
4895 return rc;
20962438
SF
4896
4897 params = 2; /* level */
4898 pSMB->TotalDataCount = 0;
4899 pSMB->MaxParameterCount = cpu_to_le16(2);
4900 pSMB->MaxDataCount = cpu_to_le16(1000);
4901 pSMB->MaxSetupCount = 0;
4902 pSMB->Reserved = 0;
4903 pSMB->Flags = 0;
4904 pSMB->Timeout = 0;
4905 pSMB->Reserved2 = 0;
4906 byte_count = params + 1 /* pad */ ;
4907 pSMB->TotalParameterCount = cpu_to_le16(params);
4908 pSMB->ParameterCount = pSMB->TotalParameterCount;
4909 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4910 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4911 pSMB->DataCount = 0;
4912 pSMB->DataOffset = 0;
4913 pSMB->SetupCount = 1;
4914 pSMB->Reserved3 = 0;
4915 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4916 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
be8e3b00 4917 inc_rfc1001_len(pSMB, byte_count);
20962438
SF
4918 pSMB->ByteCount = cpu_to_le16(byte_count);
4919
4920 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4921 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4922 if (rc) {
b6b38f70 4923 cFYI(1, "Send error in QFSInfo = %d", rc);
20962438
SF
4924 } else { /* decode response */
4925 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4926
820a803f 4927 if (rc || get_bcc(&pSMBr->hdr) < 18)
20962438
SF
4928 rc = -EIO; /* bad smb */
4929 else {
4930 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
b6b38f70 4931 cFYI(1, "qfsinf resp BCC: %d Offset %d",
820a803f 4932 get_bcc(&pSMBr->hdr), data_offset);
20962438 4933
50c2f753 4934 response_data = (FILE_SYSTEM_ALLOC_INFO *)
20962438
SF
4935 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4936 FSData->f_bsize =
4937 le16_to_cpu(response_data->BytesPerSector) *
4938 le32_to_cpu(response_data->
4939 SectorsPerAllocationUnit);
4940 FSData->f_blocks =
50c2f753 4941 le32_to_cpu(response_data->TotalAllocationUnits);
20962438
SF
4942 FSData->f_bfree = FSData->f_bavail =
4943 le32_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
4944 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4945 (unsigned long long)FSData->f_blocks,
4946 (unsigned long long)FSData->f_bfree,
4947 FSData->f_bsize);
20962438
SF
4948 }
4949 }
4950 cifs_buf_release(pSMB);
4951
4952 if (rc == -EAGAIN)
4953 goto oldQFSInfoRetry;
4954
4955 return rc;
4956}
4957
1da177e4 4958int
96daf2b0 4959CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
1da177e4
LT
4960{
4961/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4962 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4963 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4964 FILE_SYSTEM_INFO *response_data;
4965 int rc = 0;
4966 int bytes_returned = 0;
4967 __u16 params, byte_count;
4968
b6b38f70 4969 cFYI(1, "In QFSInfo");
1da177e4
LT
4970QFSInfoRetry:
4971 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4972 (void **) &pSMBr);
4973 if (rc)
4974 return rc;
4975
4976 params = 2; /* level */
4977 pSMB->TotalDataCount = 0;
4978 pSMB->MaxParameterCount = cpu_to_le16(2);
20962438 4979 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4980 pSMB->MaxSetupCount = 0;
4981 pSMB->Reserved = 0;
4982 pSMB->Flags = 0;
4983 pSMB->Timeout = 0;
4984 pSMB->Reserved2 = 0;
4985 byte_count = params + 1 /* pad */ ;
4986 pSMB->TotalParameterCount = cpu_to_le16(params);
4987 pSMB->ParameterCount = pSMB->TotalParameterCount;
4988 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4989 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4990 pSMB->DataCount = 0;
4991 pSMB->DataOffset = 0;
4992 pSMB->SetupCount = 1;
4993 pSMB->Reserved3 = 0;
4994 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4995 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
be8e3b00 4996 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4997 pSMB->ByteCount = cpu_to_le16(byte_count);
4998
4999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5001 if (rc) {
b6b38f70 5002 cFYI(1, "Send error in QFSInfo = %d", rc);
1da177e4 5003 } else { /* decode response */
50c2f753 5004 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 5005
820a803f 5006 if (rc || get_bcc(&pSMBr->hdr) < 24)
1da177e4
LT
5007 rc = -EIO; /* bad smb */
5008 else {
5009 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
5010
5011 response_data =
5012 (FILE_SYSTEM_INFO
5013 *) (((char *) &pSMBr->hdr.Protocol) +
5014 data_offset);
5015 FSData->f_bsize =
5016 le32_to_cpu(response_data->BytesPerSector) *
5017 le32_to_cpu(response_data->
5018 SectorsPerAllocationUnit);
5019 FSData->f_blocks =
5020 le64_to_cpu(response_data->TotalAllocationUnits);
5021 FSData->f_bfree = FSData->f_bavail =
5022 le64_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
5023 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5024 (unsigned long long)FSData->f_blocks,
5025 (unsigned long long)FSData->f_bfree,
5026 FSData->f_bsize);
1da177e4
LT
5027 }
5028 }
5029 cifs_buf_release(pSMB);
5030
5031 if (rc == -EAGAIN)
5032 goto QFSInfoRetry;
5033
5034 return rc;
5035}
5036
5037int
96daf2b0 5038CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
1da177e4
LT
5039{
5040/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5041 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5042 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5043 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5044 int rc = 0;
5045 int bytes_returned = 0;
5046 __u16 params, byte_count;
5047
b6b38f70 5048 cFYI(1, "In QFSAttributeInfo");
1da177e4
LT
5049QFSAttributeRetry:
5050 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5051 (void **) &pSMBr);
5052 if (rc)
5053 return rc;
5054
5055 params = 2; /* level */
5056 pSMB->TotalDataCount = 0;
5057 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5058 /* BB find exact max SMB PDU from sess structure BB */
5059 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5060 pSMB->MaxSetupCount = 0;
5061 pSMB->Reserved = 0;
5062 pSMB->Flags = 0;
5063 pSMB->Timeout = 0;
5064 pSMB->Reserved2 = 0;
5065 byte_count = params + 1 /* pad */ ;
5066 pSMB->TotalParameterCount = cpu_to_le16(params);
5067 pSMB->ParameterCount = pSMB->TotalParameterCount;
5068 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5069 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5070 pSMB->DataCount = 0;
5071 pSMB->DataOffset = 0;
5072 pSMB->SetupCount = 1;
5073 pSMB->Reserved3 = 0;
5074 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5075 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
be8e3b00 5076 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5077 pSMB->ByteCount = cpu_to_le16(byte_count);
5078
5079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5081 if (rc) {
b6b38f70 5082 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
1da177e4
LT
5083 } else { /* decode response */
5084 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5085
820a803f 5086 if (rc || get_bcc(&pSMBr->hdr) < 13) {
50c2f753 5087 /* BB also check if enough bytes returned */
1da177e4
LT
5088 rc = -EIO; /* bad smb */
5089 } else {
5090 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5091 response_data =
5092 (FILE_SYSTEM_ATTRIBUTE_INFO
5093 *) (((char *) &pSMBr->hdr.Protocol) +
5094 data_offset);
5095 memcpy(&tcon->fsAttrInfo, response_data,
26f57364 5096 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
1da177e4
LT
5097 }
5098 }
5099 cifs_buf_release(pSMB);
5100
5101 if (rc == -EAGAIN)
5102 goto QFSAttributeRetry;
5103
5104 return rc;
5105}
5106
5107int
96daf2b0 5108CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
1da177e4
LT
5109{
5110/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5111 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5112 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5113 FILE_SYSTEM_DEVICE_INFO *response_data;
5114 int rc = 0;
5115 int bytes_returned = 0;
5116 __u16 params, byte_count;
5117
b6b38f70 5118 cFYI(1, "In QFSDeviceInfo");
1da177e4
LT
5119QFSDeviceRetry:
5120 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5121 (void **) &pSMBr);
5122 if (rc)
5123 return rc;
5124
5125 params = 2; /* level */
5126 pSMB->TotalDataCount = 0;
5127 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5128 /* BB find exact max SMB PDU from sess structure BB */
5129 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5130 pSMB->MaxSetupCount = 0;
5131 pSMB->Reserved = 0;
5132 pSMB->Flags = 0;
5133 pSMB->Timeout = 0;
5134 pSMB->Reserved2 = 0;
5135 byte_count = params + 1 /* pad */ ;
5136 pSMB->TotalParameterCount = cpu_to_le16(params);
5137 pSMB->ParameterCount = pSMB->TotalParameterCount;
5138 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5139 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5140
5141 pSMB->DataCount = 0;
5142 pSMB->DataOffset = 0;
5143 pSMB->SetupCount = 1;
5144 pSMB->Reserved3 = 0;
5145 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5146 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
be8e3b00 5147 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5148 pSMB->ByteCount = cpu_to_le16(byte_count);
5149
5150 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5151 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5152 if (rc) {
b6b38f70 5153 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
1da177e4
LT
5154 } else { /* decode response */
5155 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5156
820a803f
JL
5157 if (rc || get_bcc(&pSMBr->hdr) <
5158 sizeof(FILE_SYSTEM_DEVICE_INFO))
1da177e4
LT
5159 rc = -EIO; /* bad smb */
5160 else {
5161 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5162 response_data =
737b758c
SF
5163 (FILE_SYSTEM_DEVICE_INFO *)
5164 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
5165 data_offset);
5166 memcpy(&tcon->fsDevInfo, response_data,
26f57364 5167 sizeof(FILE_SYSTEM_DEVICE_INFO));
1da177e4
LT
5168 }
5169 }
5170 cifs_buf_release(pSMB);
5171
5172 if (rc == -EAGAIN)
5173 goto QFSDeviceRetry;
5174
5175 return rc;
5176}
5177
5178int
96daf2b0 5179CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
1da177e4
LT
5180{
5181/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5182 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5183 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5184 FILE_SYSTEM_UNIX_INFO *response_data;
5185 int rc = 0;
5186 int bytes_returned = 0;
5187 __u16 params, byte_count;
5188
b6b38f70 5189 cFYI(1, "In QFSUnixInfo");
1da177e4 5190QFSUnixRetry:
f569599a
JL
5191 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5192 (void **) &pSMB, (void **) &pSMBr);
1da177e4
LT
5193 if (rc)
5194 return rc;
5195
5196 params = 2; /* level */
5197 pSMB->TotalDataCount = 0;
5198 pSMB->DataCount = 0;
5199 pSMB->DataOffset = 0;
5200 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5201 /* BB find exact max SMB PDU from sess structure BB */
5202 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
5203 pSMB->MaxSetupCount = 0;
5204 pSMB->Reserved = 0;
5205 pSMB->Flags = 0;
5206 pSMB->Timeout = 0;
5207 pSMB->Reserved2 = 0;
5208 byte_count = params + 1 /* pad */ ;
5209 pSMB->ParameterCount = cpu_to_le16(params);
5210 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
5211 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5212 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5213 pSMB->SetupCount = 1;
5214 pSMB->Reserved3 = 0;
5215 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5216 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
be8e3b00 5217 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5218 pSMB->ByteCount = cpu_to_le16(byte_count);
5219
5220 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5221 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5222 if (rc) {
b6b38f70 5223 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
5224 } else { /* decode response */
5225 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5226
820a803f 5227 if (rc || get_bcc(&pSMBr->hdr) < 13) {
1da177e4
LT
5228 rc = -EIO; /* bad smb */
5229 } else {
5230 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5231 response_data =
5232 (FILE_SYSTEM_UNIX_INFO
5233 *) (((char *) &pSMBr->hdr.Protocol) +
5234 data_offset);
5235 memcpy(&tcon->fsUnixInfo, response_data,
26f57364 5236 sizeof(FILE_SYSTEM_UNIX_INFO));
1da177e4
LT
5237 }
5238 }
5239 cifs_buf_release(pSMB);
5240
5241 if (rc == -EAGAIN)
5242 goto QFSUnixRetry;
5243
5244
5245 return rc;
5246}
5247
ac67055e 5248int
96daf2b0 5249CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
ac67055e
JA
5250{
5251/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5252 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5253 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5254 int rc = 0;
5255 int bytes_returned = 0;
5256 __u16 params, param_offset, offset, byte_count;
5257
b6b38f70 5258 cFYI(1, "In SETFSUnixInfo");
ac67055e 5259SETFSUnixRetry:
f26282c9 5260 /* BB switch to small buf init to save memory */
f569599a
JL
5261 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5262 (void **) &pSMB, (void **) &pSMBr);
ac67055e
JA
5263 if (rc)
5264 return rc;
5265
5266 params = 4; /* 2 bytes zero followed by info level. */
5267 pSMB->MaxSetupCount = 0;
5268 pSMB->Reserved = 0;
5269 pSMB->Flags = 0;
5270 pSMB->Timeout = 0;
5271 pSMB->Reserved2 = 0;
50c2f753
SF
5272 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5273 - 4;
ac67055e
JA
5274 offset = param_offset + params;
5275
5276 pSMB->MaxParameterCount = cpu_to_le16(4);
582d21e5
SF
5277 /* BB find exact max SMB PDU from sess structure BB */
5278 pSMB->MaxDataCount = cpu_to_le16(100);
ac67055e
JA
5279 pSMB->SetupCount = 1;
5280 pSMB->Reserved3 = 0;
5281 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5282 byte_count = 1 /* pad */ + params + 12;
5283
5284 pSMB->DataCount = cpu_to_le16(12);
5285 pSMB->ParameterCount = cpu_to_le16(params);
5286 pSMB->TotalDataCount = pSMB->DataCount;
5287 pSMB->TotalParameterCount = pSMB->ParameterCount;
5288 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5289 pSMB->DataOffset = cpu_to_le16(offset);
5290
5291 /* Params. */
5292 pSMB->FileNum = 0;
5293 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5294
5295 /* Data. */
5296 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5297 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5298 pSMB->ClientUnixCap = cpu_to_le64(cap);
5299
be8e3b00 5300 inc_rfc1001_len(pSMB, byte_count);
ac67055e
JA
5301 pSMB->ByteCount = cpu_to_le16(byte_count);
5302
5303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5305 if (rc) {
b6b38f70 5306 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
ac67055e
JA
5307 } else { /* decode response */
5308 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
ad7a2926 5309 if (rc)
ac67055e 5310 rc = -EIO; /* bad smb */
ac67055e
JA
5311 }
5312 cifs_buf_release(pSMB);
5313
5314 if (rc == -EAGAIN)
5315 goto SETFSUnixRetry;
5316
5317 return rc;
5318}
5319
5320
1da177e4
LT
5321
5322int
96daf2b0 5323CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
737b758c 5324 struct kstatfs *FSData)
1da177e4
LT
5325{
5326/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5327 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5328 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5329 FILE_SYSTEM_POSIX_INFO *response_data;
5330 int rc = 0;
5331 int bytes_returned = 0;
5332 __u16 params, byte_count;
5333
b6b38f70 5334 cFYI(1, "In QFSPosixInfo");
1da177e4
LT
5335QFSPosixRetry:
5336 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5337 (void **) &pSMBr);
5338 if (rc)
5339 return rc;
5340
5341 params = 2; /* level */
5342 pSMB->TotalDataCount = 0;
5343 pSMB->DataCount = 0;
5344 pSMB->DataOffset = 0;
5345 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5346 /* BB find exact max SMB PDU from sess structure BB */
5347 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
5348 pSMB->MaxSetupCount = 0;
5349 pSMB->Reserved = 0;
5350 pSMB->Flags = 0;
5351 pSMB->Timeout = 0;
5352 pSMB->Reserved2 = 0;
5353 byte_count = params + 1 /* pad */ ;
5354 pSMB->ParameterCount = cpu_to_le16(params);
5355 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
5356 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5357 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5358 pSMB->SetupCount = 1;
5359 pSMB->Reserved3 = 0;
5360 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5361 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
be8e3b00 5362 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5363 pSMB->ByteCount = cpu_to_le16(byte_count);
5364
5365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5366 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5367 if (rc) {
b6b38f70 5368 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
5369 } else { /* decode response */
5370 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5371
820a803f 5372 if (rc || get_bcc(&pSMBr->hdr) < 13) {
1da177e4
LT
5373 rc = -EIO; /* bad smb */
5374 } else {
5375 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5376 response_data =
5377 (FILE_SYSTEM_POSIX_INFO
5378 *) (((char *) &pSMBr->hdr.Protocol) +
5379 data_offset);
5380 FSData->f_bsize =
5381 le32_to_cpu(response_data->BlockSize);
5382 FSData->f_blocks =
5383 le64_to_cpu(response_data->TotalBlocks);
5384 FSData->f_bfree =
5385 le64_to_cpu(response_data->BlocksAvail);
790fe579 5386 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
1da177e4
LT
5387 FSData->f_bavail = FSData->f_bfree;
5388 } else {
5389 FSData->f_bavail =
50c2f753 5390 le64_to_cpu(response_data->UserBlocksAvail);
1da177e4 5391 }
790fe579 5392 if (response_data->TotalFileNodes != cpu_to_le64(-1))
1da177e4 5393 FSData->f_files =
50c2f753 5394 le64_to_cpu(response_data->TotalFileNodes);
790fe579 5395 if (response_data->FreeFileNodes != cpu_to_le64(-1))
1da177e4 5396 FSData->f_ffree =
50c2f753 5397 le64_to_cpu(response_data->FreeFileNodes);
1da177e4
LT
5398 }
5399 }
5400 cifs_buf_release(pSMB);
5401
5402 if (rc == -EAGAIN)
5403 goto QFSPosixRetry;
5404
5405 return rc;
5406}
5407
5408
50c2f753
SF
5409/* We can not use write of zero bytes trick to
5410 set file size due to need for large file support. Also note that
5411 this SetPathInfo is preferred to SetFileInfo based method in next
1da177e4
LT
5412 routine which is only needed to work around a sharing violation bug
5413 in Samba which this routine can run into */
5414
5415int
96daf2b0 5416CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
4b18f2a9 5417 __u64 size, bool SetAllocation,
737b758c 5418 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5419{
5420 struct smb_com_transaction2_spi_req *pSMB = NULL;
5421 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5422 struct file_end_of_file_info *parm_data;
5423 int name_len;
5424 int rc = 0;
5425 int bytes_returned = 0;
5426 __u16 params, byte_count, data_count, param_offset, offset;
5427
b6b38f70 5428 cFYI(1, "In SetEOF");
1da177e4
LT
5429SetEOFRetry:
5430 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5431 (void **) &pSMBr);
5432 if (rc)
5433 return rc;
5434
5435 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5436 name_len =
acbbb76a
SF
5437 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5438 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5439 name_len++; /* trailing null */
5440 name_len *= 2;
3e87d803 5441 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5442 name_len = strnlen(fileName, PATH_MAX);
5443 name_len++; /* trailing null */
5444 strncpy(pSMB->FileName, fileName, name_len);
5445 }
5446 params = 6 + name_len;
26f57364 5447 data_count = sizeof(struct file_end_of_file_info);
1da177e4 5448 pSMB->MaxParameterCount = cpu_to_le16(2);
3e87d803 5449 pSMB->MaxDataCount = cpu_to_le16(4100);
1da177e4
LT
5450 pSMB->MaxSetupCount = 0;
5451 pSMB->Reserved = 0;
5452 pSMB->Flags = 0;
5453 pSMB->Timeout = 0;
5454 pSMB->Reserved2 = 0;
5455 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5456 InformationLevel) - 4;
1da177e4 5457 offset = param_offset + params;
790fe579 5458 if (SetAllocation) {
50c2f753
SF
5459 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5460 pSMB->InformationLevel =
5461 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5462 else
5463 pSMB->InformationLevel =
5464 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5465 } else /* Set File Size */ {
1da177e4
LT
5466 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5467 pSMB->InformationLevel =
50c2f753 5468 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
5469 else
5470 pSMB->InformationLevel =
50c2f753 5471 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
5472 }
5473
5474 parm_data =
5475 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5476 offset);
5477 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5478 pSMB->DataOffset = cpu_to_le16(offset);
5479 pSMB->SetupCount = 1;
5480 pSMB->Reserved3 = 0;
5481 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5482 byte_count = 3 /* pad */ + params + data_count;
5483 pSMB->DataCount = cpu_to_le16(data_count);
5484 pSMB->TotalDataCount = pSMB->DataCount;
5485 pSMB->ParameterCount = cpu_to_le16(params);
5486 pSMB->TotalParameterCount = pSMB->ParameterCount;
5487 pSMB->Reserved4 = 0;
be8e3b00 5488 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5489 parm_data->FileSize = cpu_to_le64(size);
5490 pSMB->ByteCount = cpu_to_le16(byte_count);
5491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5493 if (rc)
b6b38f70 5494 cFYI(1, "SetPathInfo (file size) returned %d", rc);
1da177e4
LT
5495
5496 cifs_buf_release(pSMB);
5497
5498 if (rc == -EAGAIN)
5499 goto SetEOFRetry;
5500
5501 return rc;
5502}
5503
5504int
96daf2b0 5505CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
4b18f2a9 5506 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
1da177e4
LT
5507{
5508 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
5509 struct file_end_of_file_info *parm_data;
5510 int rc = 0;
1da177e4
LT
5511 __u16 params, param_offset, offset, byte_count, count;
5512
b6b38f70
JP
5513 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5514 (long long)size);
cd63499c
SF
5515 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5516
1da177e4
LT
5517 if (rc)
5518 return rc;
5519
5520 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5521 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 5522
1da177e4
LT
5523 params = 6;
5524 pSMB->MaxSetupCount = 0;
5525 pSMB->Reserved = 0;
5526 pSMB->Flags = 0;
5527 pSMB->Timeout = 0;
5528 pSMB->Reserved2 = 0;
5529 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5530 offset = param_offset + params;
5531
1da177e4
LT
5532 count = sizeof(struct file_end_of_file_info);
5533 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5534 /* BB find exact max SMB PDU from sess structure BB */
5535 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5536 pSMB->SetupCount = 1;
5537 pSMB->Reserved3 = 0;
5538 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5539 byte_count = 3 /* pad */ + params + count;
5540 pSMB->DataCount = cpu_to_le16(count);
5541 pSMB->ParameterCount = cpu_to_le16(params);
5542 pSMB->TotalDataCount = pSMB->DataCount;
5543 pSMB->TotalParameterCount = pSMB->ParameterCount;
5544 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5545 parm_data =
50c2f753
SF
5546 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5547 + offset);
1da177e4
LT
5548 pSMB->DataOffset = cpu_to_le16(offset);
5549 parm_data->FileSize = cpu_to_le64(size);
5550 pSMB->Fid = fid;
790fe579 5551 if (SetAllocation) {
1da177e4
LT
5552 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5553 pSMB->InformationLevel =
5554 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5555 else
5556 pSMB->InformationLevel =
5557 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
50c2f753 5558 } else /* Set File Size */ {
1da177e4
LT
5559 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5560 pSMB->InformationLevel =
50c2f753 5561 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
5562 else
5563 pSMB->InformationLevel =
50c2f753 5564 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
5565 }
5566 pSMB->Reserved4 = 0;
be8e3b00 5567 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5568 pSMB->ByteCount = cpu_to_le16(byte_count);
792af7b0 5569 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
1da177e4 5570 if (rc) {
b6b38f70 5571 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
1da177e4
LT
5572 }
5573
50c2f753 5574 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
5575 since file handle passed in no longer valid */
5576
5577 return rc;
5578}
5579
50c2f753 5580/* Some legacy servers such as NT4 require that the file times be set on
1da177e4
LT
5581 an open handle, rather than by pathname - this is awkward due to
5582 potential access conflicts on the open, but it is unavoidable for these
5583 old servers since the only other choice is to go from 100 nanosecond DCE
5584 time and resort to the original setpathinfo level which takes the ancient
5585 DOS time format with 2 second granularity */
5586int
96daf2b0 5587CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
2dd2dfa0 5588 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
1da177e4
LT
5589{
5590 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
5591 char *data_offset;
5592 int rc = 0;
1da177e4
LT
5593 __u16 params, param_offset, offset, byte_count, count;
5594
b6b38f70 5595 cFYI(1, "Set Times (via SetFileInfo)");
cd63499c
SF
5596 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5597
1da177e4
LT
5598 if (rc)
5599 return rc;
5600
2dd2dfa0
JL
5601 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5602 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 5603
1da177e4
LT
5604 params = 6;
5605 pSMB->MaxSetupCount = 0;
5606 pSMB->Reserved = 0;
5607 pSMB->Flags = 0;
5608 pSMB->Timeout = 0;
5609 pSMB->Reserved2 = 0;
5610 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5611 offset = param_offset + params;
5612
b2a3ad9c
JL
5613 data_offset = (char *)pSMB +
5614 offsetof(struct smb_hdr, Protocol) + offset;
1da177e4 5615
26f57364 5616 count = sizeof(FILE_BASIC_INFO);
1da177e4 5617 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5618 /* BB find max SMB PDU from sess */
5619 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5620 pSMB->SetupCount = 1;
5621 pSMB->Reserved3 = 0;
5622 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5623 byte_count = 3 /* pad */ + params + count;
5624 pSMB->DataCount = cpu_to_le16(count);
5625 pSMB->ParameterCount = cpu_to_le16(params);
5626 pSMB->TotalDataCount = pSMB->DataCount;
5627 pSMB->TotalParameterCount = pSMB->ParameterCount;
5628 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5629 pSMB->DataOffset = cpu_to_le16(offset);
5630 pSMB->Fid = fid;
5631 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5632 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5633 else
5634 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5635 pSMB->Reserved4 = 0;
be8e3b00 5636 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5637 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 5638 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
792af7b0 5639 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
ad7a2926 5640 if (rc)
b6b38f70 5641 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
1da177e4 5642
50c2f753 5643 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
5644 since file handle passed in no longer valid */
5645
5646 return rc;
5647}
5648
6d22f098 5649int
96daf2b0 5650CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
6d22f098
JL
5651 bool delete_file, __u16 fid, __u32 pid_of_opener)
5652{
5653 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5654 char *data_offset;
5655 int rc = 0;
5656 __u16 params, param_offset, offset, byte_count, count;
5657
b6b38f70 5658 cFYI(1, "Set File Disposition (via SetFileInfo)");
6d22f098
JL
5659 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5660
5661 if (rc)
5662 return rc;
5663
5664 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5665 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5666
5667 params = 6;
5668 pSMB->MaxSetupCount = 0;
5669 pSMB->Reserved = 0;
5670 pSMB->Flags = 0;
5671 pSMB->Timeout = 0;
5672 pSMB->Reserved2 = 0;
5673 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5674 offset = param_offset + params;
5675
5676 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5677
5678 count = 1;
5679 pSMB->MaxParameterCount = cpu_to_le16(2);
5680 /* BB find max SMB PDU from sess */
5681 pSMB->MaxDataCount = cpu_to_le16(1000);
5682 pSMB->SetupCount = 1;
5683 pSMB->Reserved3 = 0;
5684 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5685 byte_count = 3 /* pad */ + params + count;
5686 pSMB->DataCount = cpu_to_le16(count);
5687 pSMB->ParameterCount = cpu_to_le16(params);
5688 pSMB->TotalDataCount = pSMB->DataCount;
5689 pSMB->TotalParameterCount = pSMB->ParameterCount;
5690 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5691 pSMB->DataOffset = cpu_to_le16(offset);
5692 pSMB->Fid = fid;
5693 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5694 pSMB->Reserved4 = 0;
be8e3b00 5695 inc_rfc1001_len(pSMB, byte_count);
6d22f098
JL
5696 pSMB->ByteCount = cpu_to_le16(byte_count);
5697 *data_offset = delete_file ? 1 : 0;
792af7b0 5698 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
6d22f098 5699 if (rc)
b6b38f70 5700 cFYI(1, "Send error in SetFileDisposition = %d", rc);
6d22f098
JL
5701
5702 return rc;
5703}
1da177e4
LT
5704
5705int
96daf2b0 5706CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
6fc000e5
JL
5707 const char *fileName, const FILE_BASIC_INFO *data,
5708 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5709{
5710 TRANSACTION2_SPI_REQ *pSMB = NULL;
5711 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5712 int name_len;
5713 int rc = 0;
5714 int bytes_returned = 0;
5715 char *data_offset;
5716 __u16 params, param_offset, offset, byte_count, count;
5717
b6b38f70 5718 cFYI(1, "In SetTimes");
1da177e4
LT
5719
5720SetTimesRetry:
5721 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5722 (void **) &pSMBr);
5723 if (rc)
5724 return rc;
5725
5726 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5727 name_len =
acbbb76a
SF
5728 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5729 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5730 name_len++; /* trailing null */
5731 name_len *= 2;
50c2f753 5732 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5733 name_len = strnlen(fileName, PATH_MAX);
5734 name_len++; /* trailing null */
5735 strncpy(pSMB->FileName, fileName, name_len);
5736 }
5737
5738 params = 6 + name_len;
26f57364 5739 count = sizeof(FILE_BASIC_INFO);
1da177e4 5740 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5741 /* BB find max SMB PDU from sess structure BB */
5742 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5743 pSMB->MaxSetupCount = 0;
5744 pSMB->Reserved = 0;
5745 pSMB->Flags = 0;
5746 pSMB->Timeout = 0;
5747 pSMB->Reserved2 = 0;
5748 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5749 InformationLevel) - 4;
1da177e4
LT
5750 offset = param_offset + params;
5751 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5752 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5753 pSMB->DataOffset = cpu_to_le16(offset);
5754 pSMB->SetupCount = 1;
5755 pSMB->Reserved3 = 0;
5756 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5757 byte_count = 3 /* pad */ + params + count;
5758
5759 pSMB->DataCount = cpu_to_le16(count);
5760 pSMB->ParameterCount = cpu_to_le16(params);
5761 pSMB->TotalDataCount = pSMB->DataCount;
5762 pSMB->TotalParameterCount = pSMB->ParameterCount;
5763 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5764 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5765 else
5766 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5767 pSMB->Reserved4 = 0;
be8e3b00 5768 inc_rfc1001_len(pSMB, byte_count);
26f57364 5769 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
1da177e4
LT
5770 pSMB->ByteCount = cpu_to_le16(byte_count);
5771 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5772 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5773 if (rc)
b6b38f70 5774 cFYI(1, "SetPathInfo (times) returned %d", rc);
1da177e4
LT
5775
5776 cifs_buf_release(pSMB);
5777
5778 if (rc == -EAGAIN)
5779 goto SetTimesRetry;
5780
5781 return rc;
5782}
5783
5784/* Can not be used to set time stamps yet (due to old DOS time format) */
5785/* Can be used to set attributes */
5786#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5787 handling it anyway and NT4 was what we thought it would be needed for
5788 Do not delete it until we prove whether needed for Win9x though */
5789int
96daf2b0 5790CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
1da177e4
LT
5791 __u16 dos_attrs, const struct nls_table *nls_codepage)
5792{
5793 SETATTR_REQ *pSMB = NULL;
5794 SETATTR_RSP *pSMBr = NULL;
5795 int rc = 0;
5796 int bytes_returned;
5797 int name_len;
5798
b6b38f70 5799 cFYI(1, "In SetAttrLegacy");
1da177e4
LT
5800
5801SetAttrLgcyRetry:
5802 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5803 (void **) &pSMBr);
5804 if (rc)
5805 return rc;
5806
5807 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5808 name_len =
acbbb76a
SF
5809 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5810 PATH_MAX, nls_codepage);
1da177e4
LT
5811 name_len++; /* trailing null */
5812 name_len *= 2;
50c2f753 5813 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5814 name_len = strnlen(fileName, PATH_MAX);
5815 name_len++; /* trailing null */
5816 strncpy(pSMB->fileName, fileName, name_len);
5817 }
5818 pSMB->attr = cpu_to_le16(dos_attrs);
5819 pSMB->BufferFormat = 0x04;
be8e3b00 5820 inc_rfc1001_len(pSMB, name_len + 1);
1da177e4
LT
5821 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5822 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5823 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5824 if (rc)
b6b38f70 5825 cFYI(1, "Error in LegacySetAttr = %d", rc);
1da177e4
LT
5826
5827 cifs_buf_release(pSMB);
5828
5829 if (rc == -EAGAIN)
5830 goto SetAttrLgcyRetry;
5831
5832 return rc;
5833}
5834#endif /* temporarily unneeded SetAttr legacy function */
5835
654cf14a
JL
5836static void
5837cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5838 const struct cifs_unix_set_info_args *args)
5839{
5840 u64 mode = args->mode;
5841
5842 /*
5843 * Samba server ignores set of file size to zero due to bugs in some
5844 * older clients, but we should be precise - we use SetFileSize to
5845 * set file size and do not want to truncate file size to zero
25985edc 5846 * accidentally as happened on one Samba server beta by putting
654cf14a
JL
5847 * zero instead of -1 here
5848 */
5849 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5850 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5851 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5852 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5853 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5854 data_offset->Uid = cpu_to_le64(args->uid);
5855 data_offset->Gid = cpu_to_le64(args->gid);
5856 /* better to leave device as zero when it is */
5857 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5858 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5859 data_offset->Permissions = cpu_to_le64(mode);
5860
5861 if (S_ISREG(mode))
5862 data_offset->Type = cpu_to_le32(UNIX_FILE);
5863 else if (S_ISDIR(mode))
5864 data_offset->Type = cpu_to_le32(UNIX_DIR);
5865 else if (S_ISLNK(mode))
5866 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5867 else if (S_ISCHR(mode))
5868 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5869 else if (S_ISBLK(mode))
5870 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5871 else if (S_ISFIFO(mode))
5872 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5873 else if (S_ISSOCK(mode))
5874 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5875}
5876
3bbeeb3c 5877int
96daf2b0 5878CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
3bbeeb3c
JL
5879 const struct cifs_unix_set_info_args *args,
5880 u16 fid, u32 pid_of_opener)
5881{
5882 struct smb_com_transaction2_sfi_req *pSMB = NULL;
b2a3ad9c 5883 char *data_offset;
3bbeeb3c
JL
5884 int rc = 0;
5885 u16 params, param_offset, offset, byte_count, count;
5886
b6b38f70 5887 cFYI(1, "Set Unix Info (via SetFileInfo)");
3bbeeb3c
JL
5888 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5889
5890 if (rc)
5891 return rc;
5892
5893 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5894 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5895
5896 params = 6;
5897 pSMB->MaxSetupCount = 0;
5898 pSMB->Reserved = 0;
5899 pSMB->Flags = 0;
5900 pSMB->Timeout = 0;
5901 pSMB->Reserved2 = 0;
5902 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5903 offset = param_offset + params;
5904
b2a3ad9c
JL
5905 data_offset = (char *)pSMB +
5906 offsetof(struct smb_hdr, Protocol) + offset;
5907
3bbeeb3c
JL
5908 count = sizeof(FILE_UNIX_BASIC_INFO);
5909
5910 pSMB->MaxParameterCount = cpu_to_le16(2);
5911 /* BB find max SMB PDU from sess */
5912 pSMB->MaxDataCount = cpu_to_le16(1000);
5913 pSMB->SetupCount = 1;
5914 pSMB->Reserved3 = 0;
5915 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5916 byte_count = 3 /* pad */ + params + count;
5917 pSMB->DataCount = cpu_to_le16(count);
5918 pSMB->ParameterCount = cpu_to_le16(params);
5919 pSMB->TotalDataCount = pSMB->DataCount;
5920 pSMB->TotalParameterCount = pSMB->ParameterCount;
5921 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5922 pSMB->DataOffset = cpu_to_le16(offset);
5923 pSMB->Fid = fid;
5924 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5925 pSMB->Reserved4 = 0;
be8e3b00 5926 inc_rfc1001_len(pSMB, byte_count);
3bbeeb3c
JL
5927 pSMB->ByteCount = cpu_to_le16(byte_count);
5928
b2a3ad9c 5929 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
3bbeeb3c 5930
792af7b0 5931 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
3bbeeb3c 5932 if (rc)
b6b38f70 5933 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
3bbeeb3c
JL
5934
5935 /* Note: On -EAGAIN error only caller can retry on handle based calls
5936 since file handle passed in no longer valid */
5937
5938 return rc;
5939}
5940
1da177e4 5941int
96daf2b0 5942CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
01ea95e3
JL
5943 const struct cifs_unix_set_info_args *args,
5944 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5945{
5946 TRANSACTION2_SPI_REQ *pSMB = NULL;
5947 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5948 int name_len;
5949 int rc = 0;
5950 int bytes_returned = 0;
5951 FILE_UNIX_BASIC_INFO *data_offset;
5952 __u16 params, param_offset, offset, count, byte_count;
5953
b6b38f70 5954 cFYI(1, "In SetUID/GID/Mode");
1da177e4
LT
5955setPermsRetry:
5956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5957 (void **) &pSMBr);
5958 if (rc)
5959 return rc;
5960
5961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5962 name_len =
acbbb76a
SF
5963 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5964 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5965 name_len++; /* trailing null */
5966 name_len *= 2;
3e87d803 5967 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5968 name_len = strnlen(fileName, PATH_MAX);
5969 name_len++; /* trailing null */
5970 strncpy(pSMB->FileName, fileName, name_len);
5971 }
5972
5973 params = 6 + name_len;
26f57364 5974 count = sizeof(FILE_UNIX_BASIC_INFO);
1da177e4 5975 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5976 /* BB find max SMB PDU from sess structure BB */
5977 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5978 pSMB->MaxSetupCount = 0;
5979 pSMB->Reserved = 0;
5980 pSMB->Flags = 0;
5981 pSMB->Timeout = 0;
5982 pSMB->Reserved2 = 0;
5983 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5984 InformationLevel) - 4;
1da177e4
LT
5985 offset = param_offset + params;
5986 data_offset =
5987 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5988 offset);
5989 memset(data_offset, 0, count);
5990 pSMB->DataOffset = cpu_to_le16(offset);
5991 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5992 pSMB->SetupCount = 1;
5993 pSMB->Reserved3 = 0;
5994 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5995 byte_count = 3 /* pad */ + params + count;
5996 pSMB->ParameterCount = cpu_to_le16(params);
5997 pSMB->DataCount = cpu_to_le16(count);
5998 pSMB->TotalParameterCount = pSMB->ParameterCount;
5999 pSMB->TotalDataCount = pSMB->DataCount;
6000 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
6001 pSMB->Reserved4 = 0;
be8e3b00 6002 inc_rfc1001_len(pSMB, byte_count);
1da177e4 6003
654cf14a 6004 cifs_fill_unix_set_info(data_offset, args);
1da177e4
LT
6005
6006 pSMB->ByteCount = cpu_to_le16(byte_count);
6007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 6009 if (rc)
b6b38f70 6010 cFYI(1, "SetPathInfo (perms) returned %d", rc);
1da177e4 6011
0d817bc0 6012 cifs_buf_release(pSMB);
1da177e4
LT
6013 if (rc == -EAGAIN)
6014 goto setPermsRetry;
6015 return rc;
6016}
6017
1da177e4 6018#ifdef CONFIG_CIFS_XATTR
31c0519f
JL
6019/*
6020 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6021 * function used by listxattr and getxattr type calls. When ea_name is set,
6022 * it looks for that attribute name and stuffs that value into the EAData
6023 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6024 * buffer. In both cases, the return value is either the length of the
6025 * resulting data or a negative error code. If EAData is a NULL pointer then
6026 * the data isn't copied to it, but the length is returned.
6027 */
1da177e4 6028ssize_t
96daf2b0 6029CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
31c0519f
JL
6030 const unsigned char *searchName, const unsigned char *ea_name,
6031 char *EAData, size_t buf_size,
6032 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
6033{
6034 /* BB assumes one setup word */
6035 TRANSACTION2_QPI_REQ *pSMB = NULL;
6036 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6037 int rc = 0;
6038 int bytes_returned;
6e462b9f 6039 int list_len;
f0d3868b 6040 struct fealist *ea_response_data;
50c2f753
SF
6041 struct fea *temp_fea;
6042 char *temp_ptr;
0cd126b5 6043 char *end_of_smb;
f0d3868b 6044 __u16 params, byte_count, data_offset;
5980fc96 6045 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
1da177e4 6046
b6b38f70 6047 cFYI(1, "In Query All EAs path %s", searchName);
1da177e4
LT
6048QAllEAsRetry:
6049 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6050 (void **) &pSMBr);
6051 if (rc)
6052 return rc;
6053
6054 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6e462b9f 6055 list_len =
acbbb76a
SF
6056 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6057 PATH_MAX, nls_codepage, remap);
6e462b9f
JL
6058 list_len++; /* trailing null */
6059 list_len *= 2;
1da177e4 6060 } else { /* BB improve the check for buffer overruns BB */
6e462b9f
JL
6061 list_len = strnlen(searchName, PATH_MAX);
6062 list_len++; /* trailing null */
6063 strncpy(pSMB->FileName, searchName, list_len);
1da177e4
LT
6064 }
6065
6e462b9f 6066 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
1da177e4
LT
6067 pSMB->TotalDataCount = 0;
6068 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5 6069 /* BB find exact max SMB PDU from sess structure BB */
e529614a 6070 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
1da177e4
LT
6071 pSMB->MaxSetupCount = 0;
6072 pSMB->Reserved = 0;
6073 pSMB->Flags = 0;
6074 pSMB->Timeout = 0;
6075 pSMB->Reserved2 = 0;
6076 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 6077 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
6078 pSMB->DataCount = 0;
6079 pSMB->DataOffset = 0;
6080 pSMB->SetupCount = 1;
6081 pSMB->Reserved3 = 0;
6082 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6083 byte_count = params + 1 /* pad */ ;
6084 pSMB->TotalParameterCount = cpu_to_le16(params);
6085 pSMB->ParameterCount = pSMB->TotalParameterCount;
6086 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6087 pSMB->Reserved4 = 0;
be8e3b00 6088 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
6089 pSMB->ByteCount = cpu_to_le16(byte_count);
6090
6091 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6092 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6093 if (rc) {
b6b38f70 6094 cFYI(1, "Send error in QueryAllEAs = %d", rc);
f0d3868b
JL
6095 goto QAllEAsOut;
6096 }
1da177e4 6097
f0d3868b
JL
6098
6099 /* BB also check enough total bytes returned */
6100 /* BB we need to improve the validity checking
6101 of these trans2 responses */
6102
6103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
820a803f 6104 if (rc || get_bcc(&pSMBr->hdr) < 4) {
f0d3868b
JL
6105 rc = -EIO; /* bad smb */
6106 goto QAllEAsOut;
6107 }
6108
6109 /* check that length of list is not more than bcc */
6110 /* check that each entry does not go beyond length
6111 of list */
6112 /* check that each element of each entry does not
6113 go beyond end of list */
6114 /* validate_trans2_offsets() */
6115 /* BB check if start of smb + data_offset > &bcc+ bcc */
6116
6117 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6118 ea_response_data = (struct fealist *)
6119 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6120
6e462b9f 6121 list_len = le32_to_cpu(ea_response_data->list_len);
b6b38f70 6122 cFYI(1, "ea length %d", list_len);
6e462b9f 6123 if (list_len <= 8) {
b6b38f70 6124 cFYI(1, "empty EA list returned from server");
f0d3868b
JL
6125 goto QAllEAsOut;
6126 }
6127
0cd126b5 6128 /* make sure list_len doesn't go past end of SMB */
690c522f 6129 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
0cd126b5 6130 if ((char *)ea_response_data + list_len > end_of_smb) {
b6b38f70 6131 cFYI(1, "EA list appears to go beyond SMB");
0cd126b5
JL
6132 rc = -EIO;
6133 goto QAllEAsOut;
6134 }
6135
f0d3868b 6136 /* account for ea list len */
6e462b9f 6137 list_len -= 4;
f0d3868b
JL
6138 temp_fea = ea_response_data->list;
6139 temp_ptr = (char *)temp_fea;
6e462b9f 6140 while (list_len > 0) {
122ca007 6141 unsigned int name_len;
f0d3868b 6142 __u16 value_len;
0cd126b5 6143
6e462b9f 6144 list_len -= 4;
f0d3868b 6145 temp_ptr += 4;
0cd126b5
JL
6146 /* make sure we can read name_len and value_len */
6147 if (list_len < 0) {
b6b38f70 6148 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
6149 rc = -EIO;
6150 goto QAllEAsOut;
6151 }
6152
6153 name_len = temp_fea->name_len;
6154 value_len = le16_to_cpu(temp_fea->value_len);
6155 list_len -= name_len + 1 + value_len;
6156 if (list_len < 0) {
b6b38f70 6157 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
6158 rc = -EIO;
6159 goto QAllEAsOut;
6160 }
6161
31c0519f 6162 if (ea_name) {
91d065c4 6163 if (ea_name_len == name_len &&
ac423446 6164 memcmp(ea_name, temp_ptr, name_len) == 0) {
31c0519f
JL
6165 temp_ptr += name_len + 1;
6166 rc = value_len;
6167 if (buf_size == 0)
6168 goto QAllEAsOut;
6169 if ((size_t)value_len > buf_size) {
6170 rc = -ERANGE;
6171 goto QAllEAsOut;
6172 }
6173 memcpy(EAData, temp_ptr, value_len);
6174 goto QAllEAsOut;
6175 }
f0d3868b 6176 } else {
31c0519f
JL
6177 /* account for prefix user. and trailing null */
6178 rc += (5 + 1 + name_len);
6179 if (rc < (int) buf_size) {
6180 memcpy(EAData, "user.", 5);
6181 EAData += 5;
6182 memcpy(EAData, temp_ptr, name_len);
6183 EAData += name_len;
6184 /* null terminate name */
6185 *EAData = 0;
6186 ++EAData;
6187 } else if (buf_size == 0) {
6188 /* skip copy - calc size only */
6189 } else {
6190 /* stop before overrun buffer */
6191 rc = -ERANGE;
6192 break;
6193 }
1da177e4 6194 }
0cd126b5 6195 temp_ptr += name_len + 1 + value_len;
f0d3868b 6196 temp_fea = (struct fea *)temp_ptr;
1da177e4 6197 }
f0d3868b 6198
31c0519f
JL
6199 /* didn't find the named attribute */
6200 if (ea_name)
6201 rc = -ENODATA;
6202
f0d3868b 6203QAllEAsOut:
0d817bc0 6204 cifs_buf_release(pSMB);
1da177e4
LT
6205 if (rc == -EAGAIN)
6206 goto QAllEAsRetry;
6207
6208 return (ssize_t)rc;
6209}
6210
1da177e4 6211int
96daf2b0 6212CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
50c2f753
SF
6213 const char *ea_name, const void *ea_value,
6214 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6215 int remap)
1da177e4
LT
6216{
6217 struct smb_com_transaction2_spi_req *pSMB = NULL;
6218 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6219 struct fealist *parm_data;
6220 int name_len;
6221 int rc = 0;
6222 int bytes_returned = 0;
6223 __u16 params, param_offset, byte_count, offset, count;
6224
b6b38f70 6225 cFYI(1, "In SetEA");
1da177e4
LT
6226SetEARetry:
6227 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6228 (void **) &pSMBr);
6229 if (rc)
6230 return rc;
6231
6232 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6233 name_len =
acbbb76a
SF
6234 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6235 PATH_MAX, nls_codepage, remap);
1da177e4
LT
6236 name_len++; /* trailing null */
6237 name_len *= 2;
50c2f753 6238 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
6239 name_len = strnlen(fileName, PATH_MAX);
6240 name_len++; /* trailing null */
6241 strncpy(pSMB->FileName, fileName, name_len);
6242 }
6243
6244 params = 6 + name_len;
6245
6246 /* done calculating parms using name_len of file name,
6247 now use name_len to calculate length of ea name
6248 we are going to create in the inode xattrs */
790fe579 6249 if (ea_name == NULL)
1da177e4
LT
6250 name_len = 0;
6251 else
50c2f753 6252 name_len = strnlen(ea_name, 255);
1da177e4 6253
dae5dbdb 6254 count = sizeof(*parm_data) + ea_value_len + name_len;
1da177e4 6255 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
6256 /* BB find max SMB PDU from sess */
6257 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
6258 pSMB->MaxSetupCount = 0;
6259 pSMB->Reserved = 0;
6260 pSMB->Flags = 0;
6261 pSMB->Timeout = 0;
6262 pSMB->Reserved2 = 0;
6263 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 6264 InformationLevel) - 4;
1da177e4
LT
6265 offset = param_offset + params;
6266 pSMB->InformationLevel =
6267 cpu_to_le16(SMB_SET_FILE_EA);
6268
6269 parm_data =
6270 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6271 offset);
6272 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6273 pSMB->DataOffset = cpu_to_le16(offset);
6274 pSMB->SetupCount = 1;
6275 pSMB->Reserved3 = 0;
6276 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6277 byte_count = 3 /* pad */ + params + count;
6278 pSMB->DataCount = cpu_to_le16(count);
6279 parm_data->list_len = cpu_to_le32(count);
6280 parm_data->list[0].EA_flags = 0;
6281 /* we checked above that name len is less than 255 */
53b3531b 6282 parm_data->list[0].name_len = (__u8)name_len;
1da177e4 6283 /* EA names are always ASCII */
790fe579 6284 if (ea_name)
50c2f753 6285 strncpy(parm_data->list[0].name, ea_name, name_len);
1da177e4
LT
6286 parm_data->list[0].name[name_len] = 0;
6287 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6288 /* caller ensures that ea_value_len is less than 64K but
6289 we need to ensure that it fits within the smb */
6290
50c2f753
SF
6291 /*BB add length check to see if it would fit in
6292 negotiated SMB buffer size BB */
790fe579
SF
6293 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6294 if (ea_value_len)
50c2f753
SF
6295 memcpy(parm_data->list[0].name+name_len+1,
6296 ea_value, ea_value_len);
1da177e4
LT
6297
6298 pSMB->TotalDataCount = pSMB->DataCount;
6299 pSMB->ParameterCount = cpu_to_le16(params);
6300 pSMB->TotalParameterCount = pSMB->ParameterCount;
6301 pSMB->Reserved4 = 0;
be8e3b00 6302 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
6303 pSMB->ByteCount = cpu_to_le16(byte_count);
6304 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6305 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 6306 if (rc)
b6b38f70 6307 cFYI(1, "SetPathInfo (EA) returned %d", rc);
1da177e4
LT
6308
6309 cifs_buf_release(pSMB);
6310
6311 if (rc == -EAGAIN)
6312 goto SetEARetry;
6313
6314 return rc;
6315}
1da177e4 6316#endif
0eff0e26
SF
6317
6318#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6319/*
6320 * Years ago the kernel added a "dnotify" function for Samba server,
6321 * to allow network clients (such as Windows) to display updated
6322 * lists of files in directory listings automatically when
6323 * files are added by one user when another user has the
6324 * same directory open on their desktop. The Linux cifs kernel
6325 * client hooked into the kernel side of this interface for
6326 * the same reason, but ironically when the VFS moved from
6327 * "dnotify" to "inotify" it became harder to plug in Linux
6328 * network file system clients (the most obvious use case
6329 * for notify interfaces is when multiple users can update
6330 * the contents of the same directory - exactly what network
6331 * file systems can do) although the server (Samba) could
6332 * still use it. For the short term we leave the worker
6333 * function ifdeffed out (below) until inotify is fixed
6334 * in the VFS to make it easier to plug in network file
6335 * system clients. If inotify turns out to be permanently
6336 * incompatible for network fs clients, we could instead simply
6337 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6338 */
96daf2b0 6339int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
0eff0e26
SF
6340 const int notify_subdirs, const __u16 netfid,
6341 __u32 filter, struct file *pfile, int multishot,
6342 const struct nls_table *nls_codepage)
6343{
6344 int rc = 0;
6345 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6346 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6347 struct dir_notify_req *dnotify_req;
6348 int bytes_returned;
6349
6350 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6351 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6352 (void **) &pSMBr);
6353 if (rc)
6354 return rc;
6355
6356 pSMB->TotalParameterCount = 0 ;
6357 pSMB->TotalDataCount = 0;
6358 pSMB->MaxParameterCount = cpu_to_le32(2);
c974befa 6359 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
0eff0e26
SF
6360 pSMB->MaxSetupCount = 4;
6361 pSMB->Reserved = 0;
6362 pSMB->ParameterOffset = 0;
6363 pSMB->DataCount = 0;
6364 pSMB->DataOffset = 0;
6365 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6366 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6367 pSMB->ParameterCount = pSMB->TotalParameterCount;
6368 if (notify_subdirs)
6369 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6370 pSMB->Reserved2 = 0;
6371 pSMB->CompletionFilter = cpu_to_le32(filter);
6372 pSMB->Fid = netfid; /* file handle always le */
6373 pSMB->ByteCount = 0;
6374
6375 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6376 (struct smb_hdr *)pSMBr, &bytes_returned,
6377 CIFS_ASYNC_OP);
6378 if (rc) {
6379 cFYI(1, "Error in Notify = %d", rc);
6380 } else {
6381 /* Add file to outstanding requests */
6382 /* BB change to kmem cache alloc */
6383 dnotify_req = kmalloc(
6384 sizeof(struct dir_notify_req),
6385 GFP_KERNEL);
6386 if (dnotify_req) {
6387 dnotify_req->Pid = pSMB->hdr.Pid;
6388 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6389 dnotify_req->Mid = pSMB->hdr.Mid;
6390 dnotify_req->Tid = pSMB->hdr.Tid;
6391 dnotify_req->Uid = pSMB->hdr.Uid;
6392 dnotify_req->netfid = netfid;
6393 dnotify_req->pfile = pfile;
6394 dnotify_req->filter = filter;
6395 dnotify_req->multishot = multishot;
6396 spin_lock(&GlobalMid_Lock);
6397 list_add_tail(&dnotify_req->lhead,
6398 &GlobalDnotifyReqList);
6399 spin_unlock(&GlobalMid_Lock);
6400 } else
6401 rc = -ENOMEM;
6402 }
6403 cifs_buf_release(pSMB);
6404 return rc;
6405}
6406#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */