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