CIFS: Move protocol specific part from SendReceive2 to ops struct
[deliverable/linux.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,
2608bee7 4241 __u16 *pnetfid, __u16 search_flags,
50c2f753 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 4312 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2608bee7 4313 pSMB->SearchFlags = cpu_to_le16(search_flags);
1da177e4
LT
4314 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4315
4316 /* BB what should we set StorageType to? Does it matter? BB */
4317 pSMB->SearchStorageType = 0;
be8e3b00 4318 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4319 pSMB->ByteCount = cpu_to_le16(byte_count);
4320
4321 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4322 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 4323 cifs_stats_inc(&tcon->num_ffirst);
1da177e4 4324
88274815
SF
4325 if (rc) {/* BB add logic to retry regular search if Unix search
4326 rejected unexpectedly by server */
1da177e4 4327 /* BB Add code to handle unsupported level rc */
b6b38f70 4328 cFYI(1, "Error in FindFirst = %d", rc);
1982c344 4329
88274815 4330 cifs_buf_release(pSMB);
1da177e4
LT
4331
4332 /* BB eventually could optimize out free and realloc of buf */
4333 /* for this case */
4334 if (rc == -EAGAIN)
4335 goto findFirstRetry;
4336 } else { /* decode response */
4337 /* BB remember to free buffer if error BB */
4338 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
790fe579 4339 if (rc == 0) {
b77d753c
SF
4340 unsigned int lnoff;
4341
1da177e4 4342 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 4343 psrch_inf->unicode = true;
1da177e4 4344 else
4b18f2a9 4345 psrch_inf->unicode = false;
1da177e4
LT
4346
4347 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
d47d7c1a 4348 psrch_inf->smallBuf = 0;
50c2f753
SF
4349 psrch_inf->srch_entries_start =
4350 (char *) &pSMBr->hdr.Protocol +
1da177e4 4351 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
4352 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4353 le16_to_cpu(pSMBr->t2.ParameterOffset));
4354
790fe579 4355 if (parms->EndofSearch)
4b18f2a9 4356 psrch_inf->endOfSearch = true;
1da177e4 4357 else
4b18f2a9 4358 psrch_inf->endOfSearch = false;
1da177e4 4359
50c2f753
SF
4360 psrch_inf->entries_in_buffer =
4361 le16_to_cpu(parms->SearchCount);
60808233 4362 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
1da177e4 4363 psrch_inf->entries_in_buffer;
b77d753c 4364 lnoff = le16_to_cpu(parms->LastNameOffset);
c974befa 4365 if (CIFSMaxBufSize < lnoff) {
b6b38f70 4366 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
4367 psrch_inf->last_entry = NULL;
4368 return rc;
4369 }
4370
0752f152 4371 psrch_inf->last_entry = psrch_inf->srch_entries_start +
b77d753c
SF
4372 lnoff;
4373
1da177e4
LT
4374 *pnetfid = parms->SearchHandle;
4375 } else {
4376 cifs_buf_release(pSMB);
4377 }
4378 }
4379
4380 return rc;
4381}
4382
2608bee7
SP
4383int CIFSFindNext(const int xid, struct cifs_tcon *tcon, __u16 searchHandle,
4384 __u16 search_flags, struct cifs_search_info *psrch_inf)
1da177e4
LT
4385{
4386 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4387 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
ad7a2926 4388 T2_FNEXT_RSP_PARMS *parms;
1da177e4
LT
4389 char *response_data;
4390 int rc = 0;
9438fabb
JL
4391 int bytes_returned;
4392 unsigned int name_len;
1da177e4
LT
4393 __u16 params, byte_count;
4394
b6b38f70 4395 cFYI(1, "In FindNext");
1da177e4 4396
4b18f2a9 4397 if (psrch_inf->endOfSearch)
1da177e4
LT
4398 return -ENOENT;
4399
4400 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4401 (void **) &pSMBr);
4402 if (rc)
4403 return rc;
4404
50c2f753 4405 params = 14; /* includes 2 bytes of null string, converted to LE below*/
1da177e4
LT
4406 byte_count = 0;
4407 pSMB->TotalDataCount = 0; /* no EAs */
4408 pSMB->MaxParameterCount = cpu_to_le16(8);
c974befa 4409 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
1da177e4
LT
4410 pSMB->MaxSetupCount = 0;
4411 pSMB->Reserved = 0;
4412 pSMB->Flags = 0;
4413 pSMB->Timeout = 0;
4414 pSMB->Reserved2 = 0;
4415 pSMB->ParameterOffset = cpu_to_le16(
4416 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4417 pSMB->DataCount = 0;
4418 pSMB->DataOffset = 0;
4419 pSMB->SetupCount = 1;
4420 pSMB->Reserved3 = 0;
4421 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4422 pSMB->SearchHandle = searchHandle; /* always kept as le */
4423 pSMB->SearchCount =
630f3f0c 4424 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
1da177e4
LT
4425 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4426 pSMB->ResumeKey = psrch_inf->resume_key;
2608bee7 4427 pSMB->SearchFlags = cpu_to_le16(search_flags);
1da177e4
LT
4428
4429 name_len = psrch_inf->resume_name_len;
4430 params += name_len;
790fe579 4431 if (name_len < PATH_MAX) {
1da177e4
LT
4432 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4433 byte_count += name_len;
ef6724e3
SF
4434 /* 14 byte parm len above enough for 2 byte null terminator */
4435 pSMB->ResumeFileName[name_len] = 0;
4436 pSMB->ResumeFileName[name_len+1] = 0;
1da177e4
LT
4437 } else {
4438 rc = -EINVAL;
4439 goto FNext2_err_exit;
4440 }
4441 byte_count = params + 1 /* pad */ ;
4442 pSMB->TotalParameterCount = cpu_to_le16(params);
4443 pSMB->ParameterCount = pSMB->TotalParameterCount;
be8e3b00 4444 inc_rfc1001_len(pSMB, byte_count);
1da177e4 4445 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 4446
1da177e4
LT
4447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
a4544347 4449 cifs_stats_inc(&tcon->num_fnext);
1da177e4
LT
4450 if (rc) {
4451 if (rc == -EBADF) {
4b18f2a9 4452 psrch_inf->endOfSearch = true;
6353450a 4453 cifs_buf_release(pSMB);
50c2f753 4454 rc = 0; /* search probably was closed at end of search*/
1da177e4 4455 } else
b6b38f70 4456 cFYI(1, "FindNext returned = %d", rc);
1da177e4
LT
4457 } else { /* decode response */
4458 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50c2f753 4459
790fe579 4460 if (rc == 0) {
b77d753c
SF
4461 unsigned int lnoff;
4462
1da177e4
LT
4463 /* BB fixme add lock for file (srch_info) struct here */
4464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 4465 psrch_inf->unicode = true;
1da177e4 4466 else
4b18f2a9 4467 psrch_inf->unicode = false;
1da177e4
LT
4468 response_data = (char *) &pSMBr->hdr.Protocol +
4469 le16_to_cpu(pSMBr->t2.ParameterOffset);
4470 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4471 response_data = (char *)&pSMBr->hdr.Protocol +
4472 le16_to_cpu(pSMBr->t2.DataOffset);
790fe579 4473 if (psrch_inf->smallBuf)
d47d7c1a
SF
4474 cifs_small_buf_release(
4475 psrch_inf->ntwrk_buf_start);
4476 else
4477 cifs_buf_release(psrch_inf->ntwrk_buf_start);
1da177e4
LT
4478 psrch_inf->srch_entries_start = response_data;
4479 psrch_inf->ntwrk_buf_start = (char *)pSMB;
d47d7c1a 4480 psrch_inf->smallBuf = 0;
790fe579 4481 if (parms->EndofSearch)
4b18f2a9 4482 psrch_inf->endOfSearch = true;
1da177e4 4483 else
4b18f2a9 4484 psrch_inf->endOfSearch = false;
50c2f753
SF
4485 psrch_inf->entries_in_buffer =
4486 le16_to_cpu(parms->SearchCount);
1da177e4
LT
4487 psrch_inf->index_of_last_entry +=
4488 psrch_inf->entries_in_buffer;
b77d753c 4489 lnoff = le16_to_cpu(parms->LastNameOffset);
c974befa 4490 if (CIFSMaxBufSize < lnoff) {
b6b38f70 4491 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
4492 psrch_inf->last_entry = NULL;
4493 return rc;
4494 } else
4495 psrch_inf->last_entry =
4496 psrch_inf->srch_entries_start + lnoff;
4497
b6b38f70
JP
4498/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4499 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
1da177e4
LT
4500
4501 /* BB fixme add unlock here */
4502 }
4503
4504 }
4505
4506 /* BB On error, should we leave previous search buf (and count and
4507 last entry fields) intact or free the previous one? */
4508
4509 /* Note: On -EAGAIN error only caller can retry on handle based calls
4510 since file handle passed in no longer valid */
4511FNext2_err_exit:
4512 if (rc != 0)
4513 cifs_buf_release(pSMB);
1da177e4
LT
4514 return rc;
4515}
4516
4517int
96daf2b0 4518CIFSFindClose(const int xid, struct cifs_tcon *tcon,
50c2f753 4519 const __u16 searchHandle)
1da177e4
LT
4520{
4521 int rc = 0;
4522 FINDCLOSE_REQ *pSMB = NULL;
1da177e4 4523
b6b38f70 4524 cFYI(1, "In CIFSSMBFindClose");
1da177e4
LT
4525 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4526
4527 /* no sense returning error if session restarted
4528 as file handle has been closed */
790fe579 4529 if (rc == -EAGAIN)
1da177e4
LT
4530 return 0;
4531 if (rc)
4532 return rc;
4533
1da177e4
LT
4534 pSMB->FileID = searchHandle;
4535 pSMB->ByteCount = 0;
792af7b0 4536 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
ad7a2926 4537 if (rc)
b6b38f70 4538 cERROR(1, "Send error in FindClose = %d", rc);
ad7a2926 4539
a4544347 4540 cifs_stats_inc(&tcon->num_fclose);
1da177e4
LT
4541
4542 /* Since session is dead, search handle closed on server already */
4543 if (rc == -EAGAIN)
4544 rc = 0;
4545
4546 return rc;
4547}
4548
1da177e4 4549int
96daf2b0 4550CIFSGetSrvInodeNumber(const int xid, struct cifs_tcon *tcon,
50c2f753 4551 const unsigned char *searchName,
ad7a2926 4552 __u64 *inode_number,
50c2f753 4553 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4554{
4555 int rc = 0;
4556 TRANSACTION2_QPI_REQ *pSMB = NULL;
4557 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4558 int name_len, bytes_returned;
4559 __u16 params, byte_count;
4560
b6b38f70 4561 cFYI(1, "In GetSrvInodeNum for %s", searchName);
790fe579 4562 if (tcon == NULL)
50c2f753 4563 return -ENODEV;
1da177e4
LT
4564
4565GetInodeNumberRetry:
4566 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 4567 (void **) &pSMBr);
1da177e4
LT
4568 if (rc)
4569 return rc;
4570
1da177e4
LT
4571 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4572 name_len =
acbbb76a
SF
4573 cifsConvertToUTF16((__le16 *) pSMB->FileName,
4574 searchName, PATH_MAX, nls_codepage,
4575 remap);
1da177e4
LT
4576 name_len++; /* trailing null */
4577 name_len *= 2;
50c2f753 4578 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4579 name_len = strnlen(searchName, PATH_MAX);
4580 name_len++; /* trailing null */
4581 strncpy(pSMB->FileName, searchName, name_len);
4582 }
4583
4584 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4585 pSMB->TotalDataCount = 0;
4586 pSMB->MaxParameterCount = cpu_to_le16(2);
4587 /* BB find exact max data count below from sess structure BB */
4588 pSMB->MaxDataCount = cpu_to_le16(4000);
4589 pSMB->MaxSetupCount = 0;
4590 pSMB->Reserved = 0;
4591 pSMB->Flags = 0;
4592 pSMB->Timeout = 0;
4593 pSMB->Reserved2 = 0;
4594 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4595 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
4596 pSMB->DataCount = 0;
4597 pSMB->DataOffset = 0;
4598 pSMB->SetupCount = 1;
4599 pSMB->Reserved3 = 0;
4600 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4601 byte_count = params + 1 /* pad */ ;
4602 pSMB->TotalParameterCount = cpu_to_le16(params);
4603 pSMB->ParameterCount = pSMB->TotalParameterCount;
4604 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4605 pSMB->Reserved4 = 0;
be8e3b00 4606 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4607 pSMB->ByteCount = cpu_to_le16(byte_count);
4608
4609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4610 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4611 if (rc) {
b6b38f70 4612 cFYI(1, "error %d in QueryInternalInfo", rc);
1da177e4
LT
4613 } else {
4614 /* decode response */
4615 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4616 /* BB also check enough total bytes returned */
820a803f 4617 if (rc || get_bcc(&pSMBr->hdr) < 2)
1da177e4
LT
4618 /* If rc should we check for EOPNOSUPP and
4619 disable the srvino flag? or in caller? */
4620 rc = -EIO; /* bad smb */
50c2f753 4621 else {
1da177e4
LT
4622 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4623 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
50c2f753 4624 struct file_internal_info *pfinfo;
1da177e4 4625 /* BB Do we need a cast or hash here ? */
790fe579 4626 if (count < 8) {
b6b38f70 4627 cFYI(1, "Illegal size ret in QryIntrnlInf");
1da177e4
LT
4628 rc = -EIO;
4629 goto GetInodeNumOut;
4630 }
4631 pfinfo = (struct file_internal_info *)
4632 (data_offset + (char *) &pSMBr->hdr.Protocol);
85a6dac5 4633 *inode_number = le64_to_cpu(pfinfo->UniqueId);
1da177e4
LT
4634 }
4635 }
4636GetInodeNumOut:
4637 cifs_buf_release(pSMB);
4638 if (rc == -EAGAIN)
4639 goto GetInodeNumberRetry;
4640 return rc;
4641}
1da177e4 4642
fec4585f
IM
4643/* parses DFS refferal V3 structure
4644 * caller is responsible for freeing target_nodes
4645 * returns:
4646 * on success - 0
4647 * on failure - errno
4648 */
4649static int
a1fe78f1 4650parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
fec4585f
IM
4651 unsigned int *num_of_nodes,
4652 struct dfs_info3_param **target_nodes,
2c55608f
IM
4653 const struct nls_table *nls_codepage, int remap,
4654 const char *searchName)
fec4585f
IM
4655{
4656 int i, rc = 0;
4657 char *data_end;
4658 bool is_unicode;
4659 struct dfs_referral_level_3 *ref;
4660
5ca33c6a
HH
4661 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4662 is_unicode = true;
4663 else
4664 is_unicode = false;
fec4585f
IM
4665 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4666
4667 if (*num_of_nodes < 1) {
b6b38f70
JP
4668 cERROR(1, "num_referrals: must be at least > 0,"
4669 "but we get num_referrals = %d\n", *num_of_nodes);
fec4585f 4670 rc = -EINVAL;
a1fe78f1 4671 goto parse_DFS_referrals_exit;
fec4585f
IM
4672 }
4673
4674 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
1d92cfd5 4675 if (ref->VersionNumber != cpu_to_le16(3)) {
b6b38f70
JP
4676 cERROR(1, "Referrals of V%d version are not supported,"
4677 "should be V3", le16_to_cpu(ref->VersionNumber));
fec4585f 4678 rc = -EINVAL;
a1fe78f1 4679 goto parse_DFS_referrals_exit;
fec4585f
IM
4680 }
4681
4682 /* get the upper boundary of the resp buffer */
4683 data_end = (char *)(&(pSMBr->PathConsumed)) +
4684 le16_to_cpu(pSMBr->t2.DataCount);
4685
f19159dc 4686 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...\n",
fec4585f 4687 *num_of_nodes,
b6b38f70 4688 le32_to_cpu(pSMBr->DFSFlags));
fec4585f
IM
4689
4690 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4691 *num_of_nodes, GFP_KERNEL);
4692 if (*target_nodes == NULL) {
b6b38f70 4693 cERROR(1, "Failed to allocate buffer for target_nodes\n");
fec4585f 4694 rc = -ENOMEM;
a1fe78f1 4695 goto parse_DFS_referrals_exit;
fec4585f
IM
4696 }
4697
3ad2f3fb 4698 /* collect necessary data from referrals */
fec4585f
IM
4699 for (i = 0; i < *num_of_nodes; i++) {
4700 char *temp;
4701 int max_len;
4702 struct dfs_info3_param *node = (*target_nodes)+i;
4703
0e0d2cf3 4704 node->flags = le32_to_cpu(pSMBr->DFSFlags);
2c55608f 4705 if (is_unicode) {
331c3135
JL
4706 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4707 GFP_KERNEL);
2920ee2b
SF
4708 if (tmp == NULL) {
4709 rc = -ENOMEM;
4710 goto parse_DFS_referrals_exit;
4711 }
acbbb76a
SF
4712 cifsConvertToUTF16((__le16 *) tmp, searchName,
4713 PATH_MAX, nls_codepage, remap);
4714 node->path_consumed = cifs_utf16_bytes(tmp,
69f801fc 4715 le16_to_cpu(pSMBr->PathConsumed),
2c55608f
IM
4716 nls_codepage);
4717 kfree(tmp);
4718 } else
4719 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4720
fec4585f
IM
4721 node->server_type = le16_to_cpu(ref->ServerType);
4722 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4723
4724 /* copy DfsPath */
4725 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4726 max_len = data_end - temp;
acbbb76a
SF
4727 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4728 is_unicode, nls_codepage);
d8e2f53a
JL
4729 if (!node->path_name) {
4730 rc = -ENOMEM;
a1fe78f1 4731 goto parse_DFS_referrals_exit;
066ce689 4732 }
fec4585f
IM
4733
4734 /* copy link target UNC */
4735 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4736 max_len = data_end - temp;
acbbb76a
SF
4737 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4738 is_unicode, nls_codepage);
d8f2799b 4739 if (!node->node_name) {
d8e2f53a 4740 rc = -ENOMEM;
d8f2799b
SM
4741 goto parse_DFS_referrals_exit;
4742 }
4743
4744 ref++;
fec4585f
IM
4745 }
4746
a1fe78f1 4747parse_DFS_referrals_exit:
fec4585f
IM
4748 if (rc) {
4749 free_dfs_info_array(*target_nodes, *num_of_nodes);
4750 *target_nodes = NULL;
4751 *num_of_nodes = 0;
4752 }
4753 return rc;
4754}
4755
1da177e4 4756int
96daf2b0 4757CIFSGetDFSRefer(const int xid, struct cifs_ses *ses,
1da177e4 4758 const unsigned char *searchName,
c2cf07d5
SF
4759 struct dfs_info3_param **target_nodes,
4760 unsigned int *num_of_nodes,
737b758c 4761 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4762{
4763/* TRANS2_GET_DFS_REFERRAL */
4764 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4765 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
1da177e4
LT
4766 int rc = 0;
4767 int bytes_returned;
4768 int name_len;
1da177e4 4769 __u16 params, byte_count;
c2cf07d5
SF
4770 *num_of_nodes = 0;
4771 *target_nodes = NULL;
1da177e4 4772
b6b38f70 4773 cFYI(1, "In GetDFSRefer the path %s", searchName);
1da177e4
LT
4774 if (ses == NULL)
4775 return -ENODEV;
4776getDFSRetry:
4777 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4778 (void **) &pSMBr);
4779 if (rc)
4780 return rc;
50c2f753
SF
4781
4782 /* server pointer checked in called function,
1982c344
SF
4783 but should never be null here anyway */
4784 pSMB->hdr.Mid = GetNextMid(ses->server);
1da177e4
LT
4785 pSMB->hdr.Tid = ses->ipc_tid;
4786 pSMB->hdr.Uid = ses->Suid;
26f57364 4787 if (ses->capabilities & CAP_STATUS32)
1da177e4 4788 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
26f57364 4789 if (ses->capabilities & CAP_DFS)
1da177e4 4790 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
1da177e4
LT
4791
4792 if (ses->capabilities & CAP_UNICODE) {
4793 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4794 name_len =
acbbb76a
SF
4795 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
4796 searchName, PATH_MAX, nls_codepage,
4797 remap);
1da177e4
LT
4798 name_len++; /* trailing null */
4799 name_len *= 2;
50c2f753 4800 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4801 name_len = strnlen(searchName, PATH_MAX);
4802 name_len++; /* trailing null */
4803 strncpy(pSMB->RequestFileName, searchName, name_len);
4804 }
4805
790fe579 4806 if (ses->server) {
96daf2b0 4807 if (ses->server->sec_mode &
1a4e15a0
SF
4808 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4809 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4810 }
4811
50c2f753 4812 pSMB->hdr.Uid = ses->Suid;
1a4e15a0 4813
1da177e4
LT
4814 params = 2 /* level */ + name_len /*includes null */ ;
4815 pSMB->TotalDataCount = 0;
4816 pSMB->DataCount = 0;
4817 pSMB->DataOffset = 0;
4818 pSMB->MaxParameterCount = 0;
582d21e5
SF
4819 /* BB find exact max SMB PDU from sess structure BB */
4820 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4821 pSMB->MaxSetupCount = 0;
4822 pSMB->Reserved = 0;
4823 pSMB->Flags = 0;
4824 pSMB->Timeout = 0;
4825 pSMB->Reserved2 = 0;
4826 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4827 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
1da177e4
LT
4828 pSMB->SetupCount = 1;
4829 pSMB->Reserved3 = 0;
4830 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4831 byte_count = params + 3 /* pad */ ;
4832 pSMB->ParameterCount = cpu_to_le16(params);
4833 pSMB->TotalParameterCount = pSMB->ParameterCount;
4834 pSMB->MaxReferralLevel = cpu_to_le16(3);
be8e3b00 4835 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4836 pSMB->ByteCount = cpu_to_le16(byte_count);
4837
4838 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4839 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4840 if (rc) {
b6b38f70 4841 cFYI(1, "Send error in GetDFSRefer = %d", rc);
c2cf07d5
SF
4842 goto GetDFSRefExit;
4843 }
4844 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4845
c2cf07d5 4846 /* BB Also check if enough total bytes returned? */
820a803f 4847 if (rc || get_bcc(&pSMBr->hdr) < 17) {
c2cf07d5 4848 rc = -EIO; /* bad smb */
fec4585f
IM
4849 goto GetDFSRefExit;
4850 }
c2cf07d5 4851
b6b38f70 4852 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
820a803f 4853 get_bcc(&pSMBr->hdr),
b6b38f70 4854 le16_to_cpu(pSMBr->t2.DataOffset));
1da177e4 4855
fec4585f 4856 /* parse returned result into more usable form */
a1fe78f1 4857 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
2c55608f
IM
4858 target_nodes, nls_codepage, remap,
4859 searchName);
c2cf07d5 4860
1da177e4 4861GetDFSRefExit:
0d817bc0 4862 cifs_buf_release(pSMB);
1da177e4
LT
4863
4864 if (rc == -EAGAIN)
4865 goto getDFSRetry;
4866
4867 return rc;
4868}
4869
20962438
SF
4870/* Query File System Info such as free space to old servers such as Win 9x */
4871int
96daf2b0 4872SMBOldQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
20962438
SF
4873{
4874/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4875 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4876 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4877 FILE_SYSTEM_ALLOC_INFO *response_data;
4878 int rc = 0;
4879 int bytes_returned = 0;
4880 __u16 params, byte_count;
4881
b6b38f70 4882 cFYI(1, "OldQFSInfo");
20962438
SF
4883oldQFSInfoRetry:
4884 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4885 (void **) &pSMBr);
4886 if (rc)
4887 return rc;
20962438
SF
4888
4889 params = 2; /* level */
4890 pSMB->TotalDataCount = 0;
4891 pSMB->MaxParameterCount = cpu_to_le16(2);
4892 pSMB->MaxDataCount = cpu_to_le16(1000);
4893 pSMB->MaxSetupCount = 0;
4894 pSMB->Reserved = 0;
4895 pSMB->Flags = 0;
4896 pSMB->Timeout = 0;
4897 pSMB->Reserved2 = 0;
4898 byte_count = params + 1 /* pad */ ;
4899 pSMB->TotalParameterCount = cpu_to_le16(params);
4900 pSMB->ParameterCount = pSMB->TotalParameterCount;
4901 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4902 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4903 pSMB->DataCount = 0;
4904 pSMB->DataOffset = 0;
4905 pSMB->SetupCount = 1;
4906 pSMB->Reserved3 = 0;
4907 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4908 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
be8e3b00 4909 inc_rfc1001_len(pSMB, byte_count);
20962438
SF
4910 pSMB->ByteCount = cpu_to_le16(byte_count);
4911
4912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4914 if (rc) {
b6b38f70 4915 cFYI(1, "Send error in QFSInfo = %d", rc);
20962438
SF
4916 } else { /* decode response */
4917 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4918
820a803f 4919 if (rc || get_bcc(&pSMBr->hdr) < 18)
20962438
SF
4920 rc = -EIO; /* bad smb */
4921 else {
4922 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
b6b38f70 4923 cFYI(1, "qfsinf resp BCC: %d Offset %d",
820a803f 4924 get_bcc(&pSMBr->hdr), data_offset);
20962438 4925
50c2f753 4926 response_data = (FILE_SYSTEM_ALLOC_INFO *)
20962438
SF
4927 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4928 FSData->f_bsize =
4929 le16_to_cpu(response_data->BytesPerSector) *
4930 le32_to_cpu(response_data->
4931 SectorsPerAllocationUnit);
4932 FSData->f_blocks =
50c2f753 4933 le32_to_cpu(response_data->TotalAllocationUnits);
20962438
SF
4934 FSData->f_bfree = FSData->f_bavail =
4935 le32_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
4936 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4937 (unsigned long long)FSData->f_blocks,
4938 (unsigned long long)FSData->f_bfree,
4939 FSData->f_bsize);
20962438
SF
4940 }
4941 }
4942 cifs_buf_release(pSMB);
4943
4944 if (rc == -EAGAIN)
4945 goto oldQFSInfoRetry;
4946
4947 return rc;
4948}
4949
1da177e4 4950int
96daf2b0 4951CIFSSMBQFSInfo(const int xid, struct cifs_tcon *tcon, struct kstatfs *FSData)
1da177e4
LT
4952{
4953/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4954 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4955 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4956 FILE_SYSTEM_INFO *response_data;
4957 int rc = 0;
4958 int bytes_returned = 0;
4959 __u16 params, byte_count;
4960
b6b38f70 4961 cFYI(1, "In QFSInfo");
1da177e4
LT
4962QFSInfoRetry:
4963 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4964 (void **) &pSMBr);
4965 if (rc)
4966 return rc;
4967
4968 params = 2; /* level */
4969 pSMB->TotalDataCount = 0;
4970 pSMB->MaxParameterCount = cpu_to_le16(2);
20962438 4971 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4972 pSMB->MaxSetupCount = 0;
4973 pSMB->Reserved = 0;
4974 pSMB->Flags = 0;
4975 pSMB->Timeout = 0;
4976 pSMB->Reserved2 = 0;
4977 byte_count = params + 1 /* pad */ ;
4978 pSMB->TotalParameterCount = cpu_to_le16(params);
4979 pSMB->ParameterCount = pSMB->TotalParameterCount;
4980 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4981 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4982 pSMB->DataCount = 0;
4983 pSMB->DataOffset = 0;
4984 pSMB->SetupCount = 1;
4985 pSMB->Reserved3 = 0;
4986 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4987 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
be8e3b00 4988 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4989 pSMB->ByteCount = cpu_to_le16(byte_count);
4990
4991 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4992 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4993 if (rc) {
b6b38f70 4994 cFYI(1, "Send error in QFSInfo = %d", rc);
1da177e4 4995 } else { /* decode response */
50c2f753 4996 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4997
820a803f 4998 if (rc || get_bcc(&pSMBr->hdr) < 24)
1da177e4
LT
4999 rc = -EIO; /* bad smb */
5000 else {
5001 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
5002
5003 response_data =
5004 (FILE_SYSTEM_INFO
5005 *) (((char *) &pSMBr->hdr.Protocol) +
5006 data_offset);
5007 FSData->f_bsize =
5008 le32_to_cpu(response_data->BytesPerSector) *
5009 le32_to_cpu(response_data->
5010 SectorsPerAllocationUnit);
5011 FSData->f_blocks =
5012 le64_to_cpu(response_data->TotalAllocationUnits);
5013 FSData->f_bfree = FSData->f_bavail =
5014 le64_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
5015 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5016 (unsigned long long)FSData->f_blocks,
5017 (unsigned long long)FSData->f_bfree,
5018 FSData->f_bsize);
1da177e4
LT
5019 }
5020 }
5021 cifs_buf_release(pSMB);
5022
5023 if (rc == -EAGAIN)
5024 goto QFSInfoRetry;
5025
5026 return rc;
5027}
5028
5029int
96daf2b0 5030CIFSSMBQFSAttributeInfo(const int xid, struct cifs_tcon *tcon)
1da177e4
LT
5031{
5032/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5033 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5034 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5035 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5036 int rc = 0;
5037 int bytes_returned = 0;
5038 __u16 params, byte_count;
5039
b6b38f70 5040 cFYI(1, "In QFSAttributeInfo");
1da177e4
LT
5041QFSAttributeRetry:
5042 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5043 (void **) &pSMBr);
5044 if (rc)
5045 return rc;
5046
5047 params = 2; /* level */
5048 pSMB->TotalDataCount = 0;
5049 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5050 /* BB find exact max SMB PDU from sess structure BB */
5051 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5052 pSMB->MaxSetupCount = 0;
5053 pSMB->Reserved = 0;
5054 pSMB->Flags = 0;
5055 pSMB->Timeout = 0;
5056 pSMB->Reserved2 = 0;
5057 byte_count = params + 1 /* pad */ ;
5058 pSMB->TotalParameterCount = cpu_to_le16(params);
5059 pSMB->ParameterCount = pSMB->TotalParameterCount;
5060 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5061 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5062 pSMB->DataCount = 0;
5063 pSMB->DataOffset = 0;
5064 pSMB->SetupCount = 1;
5065 pSMB->Reserved3 = 0;
5066 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5067 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
be8e3b00 5068 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5069 pSMB->ByteCount = cpu_to_le16(byte_count);
5070
5071 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5072 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5073 if (rc) {
b6b38f70 5074 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
1da177e4
LT
5075 } else { /* decode response */
5076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5077
820a803f 5078 if (rc || get_bcc(&pSMBr->hdr) < 13) {
50c2f753 5079 /* BB also check if enough bytes returned */
1da177e4
LT
5080 rc = -EIO; /* bad smb */
5081 } else {
5082 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5083 response_data =
5084 (FILE_SYSTEM_ATTRIBUTE_INFO
5085 *) (((char *) &pSMBr->hdr.Protocol) +
5086 data_offset);
5087 memcpy(&tcon->fsAttrInfo, response_data,
26f57364 5088 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
1da177e4
LT
5089 }
5090 }
5091 cifs_buf_release(pSMB);
5092
5093 if (rc == -EAGAIN)
5094 goto QFSAttributeRetry;
5095
5096 return rc;
5097}
5098
5099int
96daf2b0 5100CIFSSMBQFSDeviceInfo(const int xid, struct cifs_tcon *tcon)
1da177e4
LT
5101{
5102/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5103 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5104 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5105 FILE_SYSTEM_DEVICE_INFO *response_data;
5106 int rc = 0;
5107 int bytes_returned = 0;
5108 __u16 params, byte_count;
5109
b6b38f70 5110 cFYI(1, "In QFSDeviceInfo");
1da177e4
LT
5111QFSDeviceRetry:
5112 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5113 (void **) &pSMBr);
5114 if (rc)
5115 return rc;
5116
5117 params = 2; /* level */
5118 pSMB->TotalDataCount = 0;
5119 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5120 /* BB find exact max SMB PDU from sess structure BB */
5121 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5122 pSMB->MaxSetupCount = 0;
5123 pSMB->Reserved = 0;
5124 pSMB->Flags = 0;
5125 pSMB->Timeout = 0;
5126 pSMB->Reserved2 = 0;
5127 byte_count = params + 1 /* pad */ ;
5128 pSMB->TotalParameterCount = cpu_to_le16(params);
5129 pSMB->ParameterCount = pSMB->TotalParameterCount;
5130 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5131 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5132
5133 pSMB->DataCount = 0;
5134 pSMB->DataOffset = 0;
5135 pSMB->SetupCount = 1;
5136 pSMB->Reserved3 = 0;
5137 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5138 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
be8e3b00 5139 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5140 pSMB->ByteCount = cpu_to_le16(byte_count);
5141
5142 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5143 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5144 if (rc) {
b6b38f70 5145 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
1da177e4
LT
5146 } else { /* decode response */
5147 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5148
820a803f
JL
5149 if (rc || get_bcc(&pSMBr->hdr) <
5150 sizeof(FILE_SYSTEM_DEVICE_INFO))
1da177e4
LT
5151 rc = -EIO; /* bad smb */
5152 else {
5153 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5154 response_data =
737b758c
SF
5155 (FILE_SYSTEM_DEVICE_INFO *)
5156 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
5157 data_offset);
5158 memcpy(&tcon->fsDevInfo, response_data,
26f57364 5159 sizeof(FILE_SYSTEM_DEVICE_INFO));
1da177e4
LT
5160 }
5161 }
5162 cifs_buf_release(pSMB);
5163
5164 if (rc == -EAGAIN)
5165 goto QFSDeviceRetry;
5166
5167 return rc;
5168}
5169
5170int
96daf2b0 5171CIFSSMBQFSUnixInfo(const int xid, struct cifs_tcon *tcon)
1da177e4
LT
5172{
5173/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5174 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5175 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5176 FILE_SYSTEM_UNIX_INFO *response_data;
5177 int rc = 0;
5178 int bytes_returned = 0;
5179 __u16 params, byte_count;
5180
b6b38f70 5181 cFYI(1, "In QFSUnixInfo");
1da177e4 5182QFSUnixRetry:
f569599a
JL
5183 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5184 (void **) &pSMB, (void **) &pSMBr);
1da177e4
LT
5185 if (rc)
5186 return rc;
5187
5188 params = 2; /* level */
5189 pSMB->TotalDataCount = 0;
5190 pSMB->DataCount = 0;
5191 pSMB->DataOffset = 0;
5192 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5193 /* BB find exact max SMB PDU from sess structure BB */
5194 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
5195 pSMB->MaxSetupCount = 0;
5196 pSMB->Reserved = 0;
5197 pSMB->Flags = 0;
5198 pSMB->Timeout = 0;
5199 pSMB->Reserved2 = 0;
5200 byte_count = params + 1 /* pad */ ;
5201 pSMB->ParameterCount = cpu_to_le16(params);
5202 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
5203 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5204 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5205 pSMB->SetupCount = 1;
5206 pSMB->Reserved3 = 0;
5207 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5208 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
be8e3b00 5209 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5210 pSMB->ByteCount = cpu_to_le16(byte_count);
5211
5212 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5213 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5214 if (rc) {
b6b38f70 5215 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
5216 } else { /* decode response */
5217 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5218
820a803f 5219 if (rc || get_bcc(&pSMBr->hdr) < 13) {
1da177e4
LT
5220 rc = -EIO; /* bad smb */
5221 } else {
5222 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5223 response_data =
5224 (FILE_SYSTEM_UNIX_INFO
5225 *) (((char *) &pSMBr->hdr.Protocol) +
5226 data_offset);
5227 memcpy(&tcon->fsUnixInfo, response_data,
26f57364 5228 sizeof(FILE_SYSTEM_UNIX_INFO));
1da177e4
LT
5229 }
5230 }
5231 cifs_buf_release(pSMB);
5232
5233 if (rc == -EAGAIN)
5234 goto QFSUnixRetry;
5235
5236
5237 return rc;
5238}
5239
ac67055e 5240int
96daf2b0 5241CIFSSMBSetFSUnixInfo(const int xid, struct cifs_tcon *tcon, __u64 cap)
ac67055e
JA
5242{
5243/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5244 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5245 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5246 int rc = 0;
5247 int bytes_returned = 0;
5248 __u16 params, param_offset, offset, byte_count;
5249
b6b38f70 5250 cFYI(1, "In SETFSUnixInfo");
ac67055e 5251SETFSUnixRetry:
f26282c9 5252 /* BB switch to small buf init to save memory */
f569599a
JL
5253 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5254 (void **) &pSMB, (void **) &pSMBr);
ac67055e
JA
5255 if (rc)
5256 return rc;
5257
5258 params = 4; /* 2 bytes zero followed by info level. */
5259 pSMB->MaxSetupCount = 0;
5260 pSMB->Reserved = 0;
5261 pSMB->Flags = 0;
5262 pSMB->Timeout = 0;
5263 pSMB->Reserved2 = 0;
50c2f753
SF
5264 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5265 - 4;
ac67055e
JA
5266 offset = param_offset + params;
5267
5268 pSMB->MaxParameterCount = cpu_to_le16(4);
582d21e5
SF
5269 /* BB find exact max SMB PDU from sess structure BB */
5270 pSMB->MaxDataCount = cpu_to_le16(100);
ac67055e
JA
5271 pSMB->SetupCount = 1;
5272 pSMB->Reserved3 = 0;
5273 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5274 byte_count = 1 /* pad */ + params + 12;
5275
5276 pSMB->DataCount = cpu_to_le16(12);
5277 pSMB->ParameterCount = cpu_to_le16(params);
5278 pSMB->TotalDataCount = pSMB->DataCount;
5279 pSMB->TotalParameterCount = pSMB->ParameterCount;
5280 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5281 pSMB->DataOffset = cpu_to_le16(offset);
5282
5283 /* Params. */
5284 pSMB->FileNum = 0;
5285 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5286
5287 /* Data. */
5288 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5289 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5290 pSMB->ClientUnixCap = cpu_to_le64(cap);
5291
be8e3b00 5292 inc_rfc1001_len(pSMB, byte_count);
ac67055e
JA
5293 pSMB->ByteCount = cpu_to_le16(byte_count);
5294
5295 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5296 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5297 if (rc) {
b6b38f70 5298 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
ac67055e
JA
5299 } else { /* decode response */
5300 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
ad7a2926 5301 if (rc)
ac67055e 5302 rc = -EIO; /* bad smb */
ac67055e
JA
5303 }
5304 cifs_buf_release(pSMB);
5305
5306 if (rc == -EAGAIN)
5307 goto SETFSUnixRetry;
5308
5309 return rc;
5310}
5311
5312
1da177e4
LT
5313
5314int
96daf2b0 5315CIFSSMBQFSPosixInfo(const int xid, struct cifs_tcon *tcon,
737b758c 5316 struct kstatfs *FSData)
1da177e4
LT
5317{
5318/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5319 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5320 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5321 FILE_SYSTEM_POSIX_INFO *response_data;
5322 int rc = 0;
5323 int bytes_returned = 0;
5324 __u16 params, byte_count;
5325
b6b38f70 5326 cFYI(1, "In QFSPosixInfo");
1da177e4
LT
5327QFSPosixRetry:
5328 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5329 (void **) &pSMBr);
5330 if (rc)
5331 return rc;
5332
5333 params = 2; /* level */
5334 pSMB->TotalDataCount = 0;
5335 pSMB->DataCount = 0;
5336 pSMB->DataOffset = 0;
5337 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5338 /* BB find exact max SMB PDU from sess structure BB */
5339 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
5340 pSMB->MaxSetupCount = 0;
5341 pSMB->Reserved = 0;
5342 pSMB->Flags = 0;
5343 pSMB->Timeout = 0;
5344 pSMB->Reserved2 = 0;
5345 byte_count = params + 1 /* pad */ ;
5346 pSMB->ParameterCount = cpu_to_le16(params);
5347 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
5348 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5349 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5350 pSMB->SetupCount = 1;
5351 pSMB->Reserved3 = 0;
5352 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5353 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
be8e3b00 5354 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5355 pSMB->ByteCount = cpu_to_le16(byte_count);
5356
5357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5359 if (rc) {
b6b38f70 5360 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
5361 } else { /* decode response */
5362 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5363
820a803f 5364 if (rc || get_bcc(&pSMBr->hdr) < 13) {
1da177e4
LT
5365 rc = -EIO; /* bad smb */
5366 } else {
5367 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5368 response_data =
5369 (FILE_SYSTEM_POSIX_INFO
5370 *) (((char *) &pSMBr->hdr.Protocol) +
5371 data_offset);
5372 FSData->f_bsize =
5373 le32_to_cpu(response_data->BlockSize);
5374 FSData->f_blocks =
5375 le64_to_cpu(response_data->TotalBlocks);
5376 FSData->f_bfree =
5377 le64_to_cpu(response_data->BlocksAvail);
790fe579 5378 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
1da177e4
LT
5379 FSData->f_bavail = FSData->f_bfree;
5380 } else {
5381 FSData->f_bavail =
50c2f753 5382 le64_to_cpu(response_data->UserBlocksAvail);
1da177e4 5383 }
790fe579 5384 if (response_data->TotalFileNodes != cpu_to_le64(-1))
1da177e4 5385 FSData->f_files =
50c2f753 5386 le64_to_cpu(response_data->TotalFileNodes);
790fe579 5387 if (response_data->FreeFileNodes != cpu_to_le64(-1))
1da177e4 5388 FSData->f_ffree =
50c2f753 5389 le64_to_cpu(response_data->FreeFileNodes);
1da177e4
LT
5390 }
5391 }
5392 cifs_buf_release(pSMB);
5393
5394 if (rc == -EAGAIN)
5395 goto QFSPosixRetry;
5396
5397 return rc;
5398}
5399
5400
50c2f753
SF
5401/* We can not use write of zero bytes trick to
5402 set file size due to need for large file support. Also note that
5403 this SetPathInfo is preferred to SetFileInfo based method in next
1da177e4
LT
5404 routine which is only needed to work around a sharing violation bug
5405 in Samba which this routine can run into */
5406
5407int
96daf2b0 5408CIFSSMBSetEOF(const int xid, struct cifs_tcon *tcon, const char *fileName,
4b18f2a9 5409 __u64 size, bool SetAllocation,
737b758c 5410 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5411{
5412 struct smb_com_transaction2_spi_req *pSMB = NULL;
5413 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5414 struct file_end_of_file_info *parm_data;
5415 int name_len;
5416 int rc = 0;
5417 int bytes_returned = 0;
5418 __u16 params, byte_count, data_count, param_offset, offset;
5419
b6b38f70 5420 cFYI(1, "In SetEOF");
1da177e4
LT
5421SetEOFRetry:
5422 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5423 (void **) &pSMBr);
5424 if (rc)
5425 return rc;
5426
5427 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5428 name_len =
acbbb76a
SF
5429 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5430 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5431 name_len++; /* trailing null */
5432 name_len *= 2;
3e87d803 5433 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5434 name_len = strnlen(fileName, PATH_MAX);
5435 name_len++; /* trailing null */
5436 strncpy(pSMB->FileName, fileName, name_len);
5437 }
5438 params = 6 + name_len;
26f57364 5439 data_count = sizeof(struct file_end_of_file_info);
1da177e4 5440 pSMB->MaxParameterCount = cpu_to_le16(2);
3e87d803 5441 pSMB->MaxDataCount = cpu_to_le16(4100);
1da177e4
LT
5442 pSMB->MaxSetupCount = 0;
5443 pSMB->Reserved = 0;
5444 pSMB->Flags = 0;
5445 pSMB->Timeout = 0;
5446 pSMB->Reserved2 = 0;
5447 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5448 InformationLevel) - 4;
1da177e4 5449 offset = param_offset + params;
790fe579 5450 if (SetAllocation) {
50c2f753
SF
5451 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5452 pSMB->InformationLevel =
5453 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5454 else
5455 pSMB->InformationLevel =
5456 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5457 } else /* Set File Size */ {
1da177e4
LT
5458 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5459 pSMB->InformationLevel =
50c2f753 5460 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
5461 else
5462 pSMB->InformationLevel =
50c2f753 5463 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
5464 }
5465
5466 parm_data =
5467 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5468 offset);
5469 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5470 pSMB->DataOffset = cpu_to_le16(offset);
5471 pSMB->SetupCount = 1;
5472 pSMB->Reserved3 = 0;
5473 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5474 byte_count = 3 /* pad */ + params + data_count;
5475 pSMB->DataCount = cpu_to_le16(data_count);
5476 pSMB->TotalDataCount = pSMB->DataCount;
5477 pSMB->ParameterCount = cpu_to_le16(params);
5478 pSMB->TotalParameterCount = pSMB->ParameterCount;
5479 pSMB->Reserved4 = 0;
be8e3b00 5480 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5481 parm_data->FileSize = cpu_to_le64(size);
5482 pSMB->ByteCount = cpu_to_le16(byte_count);
5483 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5484 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5485 if (rc)
b6b38f70 5486 cFYI(1, "SetPathInfo (file size) returned %d", rc);
1da177e4
LT
5487
5488 cifs_buf_release(pSMB);
5489
5490 if (rc == -EAGAIN)
5491 goto SetEOFRetry;
5492
5493 return rc;
5494}
5495
5496int
96daf2b0 5497CIFSSMBSetFileSize(const int xid, struct cifs_tcon *tcon, __u64 size,
4b18f2a9 5498 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
1da177e4
LT
5499{
5500 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
5501 struct file_end_of_file_info *parm_data;
5502 int rc = 0;
1da177e4
LT
5503 __u16 params, param_offset, offset, byte_count, count;
5504
b6b38f70
JP
5505 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5506 (long long)size);
cd63499c
SF
5507 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5508
1da177e4
LT
5509 if (rc)
5510 return rc;
5511
5512 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5513 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 5514
1da177e4
LT
5515 params = 6;
5516 pSMB->MaxSetupCount = 0;
5517 pSMB->Reserved = 0;
5518 pSMB->Flags = 0;
5519 pSMB->Timeout = 0;
5520 pSMB->Reserved2 = 0;
5521 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5522 offset = param_offset + params;
5523
1da177e4
LT
5524 count = sizeof(struct file_end_of_file_info);
5525 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5526 /* BB find exact max SMB PDU from sess structure BB */
5527 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5528 pSMB->SetupCount = 1;
5529 pSMB->Reserved3 = 0;
5530 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5531 byte_count = 3 /* pad */ + params + count;
5532 pSMB->DataCount = cpu_to_le16(count);
5533 pSMB->ParameterCount = cpu_to_le16(params);
5534 pSMB->TotalDataCount = pSMB->DataCount;
5535 pSMB->TotalParameterCount = pSMB->ParameterCount;
5536 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5537 parm_data =
50c2f753
SF
5538 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5539 + offset);
1da177e4
LT
5540 pSMB->DataOffset = cpu_to_le16(offset);
5541 parm_data->FileSize = cpu_to_le64(size);
5542 pSMB->Fid = fid;
790fe579 5543 if (SetAllocation) {
1da177e4
LT
5544 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5545 pSMB->InformationLevel =
5546 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5547 else
5548 pSMB->InformationLevel =
5549 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
50c2f753 5550 } else /* Set File Size */ {
1da177e4
LT
5551 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5552 pSMB->InformationLevel =
50c2f753 5553 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
5554 else
5555 pSMB->InformationLevel =
50c2f753 5556 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
5557 }
5558 pSMB->Reserved4 = 0;
be8e3b00 5559 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5560 pSMB->ByteCount = cpu_to_le16(byte_count);
792af7b0 5561 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
1da177e4 5562 if (rc) {
b6b38f70 5563 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
1da177e4
LT
5564 }
5565
50c2f753 5566 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
5567 since file handle passed in no longer valid */
5568
5569 return rc;
5570}
5571
50c2f753 5572/* Some legacy servers such as NT4 require that the file times be set on
1da177e4
LT
5573 an open handle, rather than by pathname - this is awkward due to
5574 potential access conflicts on the open, but it is unavoidable for these
5575 old servers since the only other choice is to go from 100 nanosecond DCE
5576 time and resort to the original setpathinfo level which takes the ancient
5577 DOS time format with 2 second granularity */
5578int
96daf2b0 5579CIFSSMBSetFileInfo(const int xid, struct cifs_tcon *tcon,
2dd2dfa0 5580 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
1da177e4
LT
5581{
5582 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
5583 char *data_offset;
5584 int rc = 0;
1da177e4
LT
5585 __u16 params, param_offset, offset, byte_count, count;
5586
b6b38f70 5587 cFYI(1, "Set Times (via SetFileInfo)");
cd63499c
SF
5588 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5589
1da177e4
LT
5590 if (rc)
5591 return rc;
5592
2dd2dfa0
JL
5593 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5594 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 5595
1da177e4
LT
5596 params = 6;
5597 pSMB->MaxSetupCount = 0;
5598 pSMB->Reserved = 0;
5599 pSMB->Flags = 0;
5600 pSMB->Timeout = 0;
5601 pSMB->Reserved2 = 0;
5602 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5603 offset = param_offset + params;
5604
b2a3ad9c
JL
5605 data_offset = (char *)pSMB +
5606 offsetof(struct smb_hdr, Protocol) + offset;
1da177e4 5607
26f57364 5608 count = sizeof(FILE_BASIC_INFO);
1da177e4 5609 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5610 /* BB find max SMB PDU from sess */
5611 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5612 pSMB->SetupCount = 1;
5613 pSMB->Reserved3 = 0;
5614 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5615 byte_count = 3 /* pad */ + params + count;
5616 pSMB->DataCount = cpu_to_le16(count);
5617 pSMB->ParameterCount = cpu_to_le16(params);
5618 pSMB->TotalDataCount = pSMB->DataCount;
5619 pSMB->TotalParameterCount = pSMB->ParameterCount;
5620 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5621 pSMB->DataOffset = cpu_to_le16(offset);
5622 pSMB->Fid = fid;
5623 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5624 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5625 else
5626 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5627 pSMB->Reserved4 = 0;
be8e3b00 5628 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5629 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 5630 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
792af7b0 5631 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
ad7a2926 5632 if (rc)
b6b38f70 5633 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
1da177e4 5634
50c2f753 5635 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
5636 since file handle passed in no longer valid */
5637
5638 return rc;
5639}
5640
6d22f098 5641int
96daf2b0 5642CIFSSMBSetFileDisposition(const int xid, struct cifs_tcon *tcon,
6d22f098
JL
5643 bool delete_file, __u16 fid, __u32 pid_of_opener)
5644{
5645 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5646 char *data_offset;
5647 int rc = 0;
5648 __u16 params, param_offset, offset, byte_count, count;
5649
b6b38f70 5650 cFYI(1, "Set File Disposition (via SetFileInfo)");
6d22f098
JL
5651 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5652
5653 if (rc)
5654 return rc;
5655
5656 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5657 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5658
5659 params = 6;
5660 pSMB->MaxSetupCount = 0;
5661 pSMB->Reserved = 0;
5662 pSMB->Flags = 0;
5663 pSMB->Timeout = 0;
5664 pSMB->Reserved2 = 0;
5665 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5666 offset = param_offset + params;
5667
5668 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5669
5670 count = 1;
5671 pSMB->MaxParameterCount = cpu_to_le16(2);
5672 /* BB find max SMB PDU from sess */
5673 pSMB->MaxDataCount = cpu_to_le16(1000);
5674 pSMB->SetupCount = 1;
5675 pSMB->Reserved3 = 0;
5676 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5677 byte_count = 3 /* pad */ + params + count;
5678 pSMB->DataCount = cpu_to_le16(count);
5679 pSMB->ParameterCount = cpu_to_le16(params);
5680 pSMB->TotalDataCount = pSMB->DataCount;
5681 pSMB->TotalParameterCount = pSMB->ParameterCount;
5682 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5683 pSMB->DataOffset = cpu_to_le16(offset);
5684 pSMB->Fid = fid;
5685 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5686 pSMB->Reserved4 = 0;
be8e3b00 5687 inc_rfc1001_len(pSMB, byte_count);
6d22f098
JL
5688 pSMB->ByteCount = cpu_to_le16(byte_count);
5689 *data_offset = delete_file ? 1 : 0;
792af7b0 5690 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
6d22f098 5691 if (rc)
b6b38f70 5692 cFYI(1, "Send error in SetFileDisposition = %d", rc);
6d22f098
JL
5693
5694 return rc;
5695}
1da177e4
LT
5696
5697int
96daf2b0 5698CIFSSMBSetPathInfo(const int xid, struct cifs_tcon *tcon,
6fc000e5
JL
5699 const char *fileName, const FILE_BASIC_INFO *data,
5700 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5701{
5702 TRANSACTION2_SPI_REQ *pSMB = NULL;
5703 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5704 int name_len;
5705 int rc = 0;
5706 int bytes_returned = 0;
5707 char *data_offset;
5708 __u16 params, param_offset, offset, byte_count, count;
5709
b6b38f70 5710 cFYI(1, "In SetTimes");
1da177e4
LT
5711
5712SetTimesRetry:
5713 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5714 (void **) &pSMBr);
5715 if (rc)
5716 return rc;
5717
5718 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5719 name_len =
acbbb76a
SF
5720 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5721 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5722 name_len++; /* trailing null */
5723 name_len *= 2;
50c2f753 5724 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5725 name_len = strnlen(fileName, PATH_MAX);
5726 name_len++; /* trailing null */
5727 strncpy(pSMB->FileName, fileName, name_len);
5728 }
5729
5730 params = 6 + name_len;
26f57364 5731 count = sizeof(FILE_BASIC_INFO);
1da177e4 5732 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5733 /* BB find max SMB PDU from sess structure BB */
5734 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5735 pSMB->MaxSetupCount = 0;
5736 pSMB->Reserved = 0;
5737 pSMB->Flags = 0;
5738 pSMB->Timeout = 0;
5739 pSMB->Reserved2 = 0;
5740 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5741 InformationLevel) - 4;
1da177e4
LT
5742 offset = param_offset + params;
5743 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5744 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5745 pSMB->DataOffset = cpu_to_le16(offset);
5746 pSMB->SetupCount = 1;
5747 pSMB->Reserved3 = 0;
5748 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5749 byte_count = 3 /* pad */ + params + count;
5750
5751 pSMB->DataCount = cpu_to_le16(count);
5752 pSMB->ParameterCount = cpu_to_le16(params);
5753 pSMB->TotalDataCount = pSMB->DataCount;
5754 pSMB->TotalParameterCount = pSMB->ParameterCount;
5755 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5756 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5757 else
5758 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5759 pSMB->Reserved4 = 0;
be8e3b00 5760 inc_rfc1001_len(pSMB, byte_count);
26f57364 5761 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
1da177e4
LT
5762 pSMB->ByteCount = cpu_to_le16(byte_count);
5763 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5765 if (rc)
b6b38f70 5766 cFYI(1, "SetPathInfo (times) returned %d", rc);
1da177e4
LT
5767
5768 cifs_buf_release(pSMB);
5769
5770 if (rc == -EAGAIN)
5771 goto SetTimesRetry;
5772
5773 return rc;
5774}
5775
5776/* Can not be used to set time stamps yet (due to old DOS time format) */
5777/* Can be used to set attributes */
5778#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5779 handling it anyway and NT4 was what we thought it would be needed for
5780 Do not delete it until we prove whether needed for Win9x though */
5781int
96daf2b0 5782CIFSSMBSetAttrLegacy(int xid, struct cifs_tcon *tcon, char *fileName,
1da177e4
LT
5783 __u16 dos_attrs, const struct nls_table *nls_codepage)
5784{
5785 SETATTR_REQ *pSMB = NULL;
5786 SETATTR_RSP *pSMBr = NULL;
5787 int rc = 0;
5788 int bytes_returned;
5789 int name_len;
5790
b6b38f70 5791 cFYI(1, "In SetAttrLegacy");
1da177e4
LT
5792
5793SetAttrLgcyRetry:
5794 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5795 (void **) &pSMBr);
5796 if (rc)
5797 return rc;
5798
5799 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5800 name_len =
acbbb76a
SF
5801 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5802 PATH_MAX, nls_codepage);
1da177e4
LT
5803 name_len++; /* trailing null */
5804 name_len *= 2;
50c2f753 5805 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5806 name_len = strnlen(fileName, PATH_MAX);
5807 name_len++; /* trailing null */
5808 strncpy(pSMB->fileName, fileName, name_len);
5809 }
5810 pSMB->attr = cpu_to_le16(dos_attrs);
5811 pSMB->BufferFormat = 0x04;
be8e3b00 5812 inc_rfc1001_len(pSMB, name_len + 1);
1da177e4
LT
5813 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5816 if (rc)
b6b38f70 5817 cFYI(1, "Error in LegacySetAttr = %d", rc);
1da177e4
LT
5818
5819 cifs_buf_release(pSMB);
5820
5821 if (rc == -EAGAIN)
5822 goto SetAttrLgcyRetry;
5823
5824 return rc;
5825}
5826#endif /* temporarily unneeded SetAttr legacy function */
5827
654cf14a
JL
5828static void
5829cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5830 const struct cifs_unix_set_info_args *args)
5831{
5832 u64 mode = args->mode;
5833
5834 /*
5835 * Samba server ignores set of file size to zero due to bugs in some
5836 * older clients, but we should be precise - we use SetFileSize to
5837 * set file size and do not want to truncate file size to zero
25985edc 5838 * accidentally as happened on one Samba server beta by putting
654cf14a
JL
5839 * zero instead of -1 here
5840 */
5841 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5842 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5843 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5844 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5845 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5846 data_offset->Uid = cpu_to_le64(args->uid);
5847 data_offset->Gid = cpu_to_le64(args->gid);
5848 /* better to leave device as zero when it is */
5849 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5850 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5851 data_offset->Permissions = cpu_to_le64(mode);
5852
5853 if (S_ISREG(mode))
5854 data_offset->Type = cpu_to_le32(UNIX_FILE);
5855 else if (S_ISDIR(mode))
5856 data_offset->Type = cpu_to_le32(UNIX_DIR);
5857 else if (S_ISLNK(mode))
5858 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5859 else if (S_ISCHR(mode))
5860 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5861 else if (S_ISBLK(mode))
5862 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5863 else if (S_ISFIFO(mode))
5864 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5865 else if (S_ISSOCK(mode))
5866 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5867}
5868
3bbeeb3c 5869int
96daf2b0 5870CIFSSMBUnixSetFileInfo(const int xid, struct cifs_tcon *tcon,
3bbeeb3c
JL
5871 const struct cifs_unix_set_info_args *args,
5872 u16 fid, u32 pid_of_opener)
5873{
5874 struct smb_com_transaction2_sfi_req *pSMB = NULL;
b2a3ad9c 5875 char *data_offset;
3bbeeb3c
JL
5876 int rc = 0;
5877 u16 params, param_offset, offset, byte_count, count;
5878
b6b38f70 5879 cFYI(1, "Set Unix Info (via SetFileInfo)");
3bbeeb3c
JL
5880 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5881
5882 if (rc)
5883 return rc;
5884
5885 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5886 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5887
5888 params = 6;
5889 pSMB->MaxSetupCount = 0;
5890 pSMB->Reserved = 0;
5891 pSMB->Flags = 0;
5892 pSMB->Timeout = 0;
5893 pSMB->Reserved2 = 0;
5894 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5895 offset = param_offset + params;
5896
b2a3ad9c
JL
5897 data_offset = (char *)pSMB +
5898 offsetof(struct smb_hdr, Protocol) + offset;
5899
3bbeeb3c
JL
5900 count = sizeof(FILE_UNIX_BASIC_INFO);
5901
5902 pSMB->MaxParameterCount = cpu_to_le16(2);
5903 /* BB find max SMB PDU from sess */
5904 pSMB->MaxDataCount = cpu_to_le16(1000);
5905 pSMB->SetupCount = 1;
5906 pSMB->Reserved3 = 0;
5907 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5908 byte_count = 3 /* pad */ + params + count;
5909 pSMB->DataCount = cpu_to_le16(count);
5910 pSMB->ParameterCount = cpu_to_le16(params);
5911 pSMB->TotalDataCount = pSMB->DataCount;
5912 pSMB->TotalParameterCount = pSMB->ParameterCount;
5913 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5914 pSMB->DataOffset = cpu_to_le16(offset);
5915 pSMB->Fid = fid;
5916 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5917 pSMB->Reserved4 = 0;
be8e3b00 5918 inc_rfc1001_len(pSMB, byte_count);
3bbeeb3c
JL
5919 pSMB->ByteCount = cpu_to_le16(byte_count);
5920
b2a3ad9c 5921 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
3bbeeb3c 5922
792af7b0 5923 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
3bbeeb3c 5924 if (rc)
b6b38f70 5925 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
3bbeeb3c
JL
5926
5927 /* Note: On -EAGAIN error only caller can retry on handle based calls
5928 since file handle passed in no longer valid */
5929
5930 return rc;
5931}
5932
1da177e4 5933int
96daf2b0 5934CIFSSMBUnixSetPathInfo(const int xid, struct cifs_tcon *tcon, char *fileName,
01ea95e3
JL
5935 const struct cifs_unix_set_info_args *args,
5936 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5937{
5938 TRANSACTION2_SPI_REQ *pSMB = NULL;
5939 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5940 int name_len;
5941 int rc = 0;
5942 int bytes_returned = 0;
5943 FILE_UNIX_BASIC_INFO *data_offset;
5944 __u16 params, param_offset, offset, count, byte_count;
5945
b6b38f70 5946 cFYI(1, "In SetUID/GID/Mode");
1da177e4
LT
5947setPermsRetry:
5948 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5949 (void **) &pSMBr);
5950 if (rc)
5951 return rc;
5952
5953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5954 name_len =
acbbb76a
SF
5955 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5956 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5957 name_len++; /* trailing null */
5958 name_len *= 2;
3e87d803 5959 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5960 name_len = strnlen(fileName, PATH_MAX);
5961 name_len++; /* trailing null */
5962 strncpy(pSMB->FileName, fileName, name_len);
5963 }
5964
5965 params = 6 + name_len;
26f57364 5966 count = sizeof(FILE_UNIX_BASIC_INFO);
1da177e4 5967 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5968 /* BB find max SMB PDU from sess structure BB */
5969 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5970 pSMB->MaxSetupCount = 0;
5971 pSMB->Reserved = 0;
5972 pSMB->Flags = 0;
5973 pSMB->Timeout = 0;
5974 pSMB->Reserved2 = 0;
5975 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5976 InformationLevel) - 4;
1da177e4
LT
5977 offset = param_offset + params;
5978 data_offset =
5979 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5980 offset);
5981 memset(data_offset, 0, count);
5982 pSMB->DataOffset = cpu_to_le16(offset);
5983 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5984 pSMB->SetupCount = 1;
5985 pSMB->Reserved3 = 0;
5986 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5987 byte_count = 3 /* pad */ + params + count;
5988 pSMB->ParameterCount = cpu_to_le16(params);
5989 pSMB->DataCount = cpu_to_le16(count);
5990 pSMB->TotalParameterCount = pSMB->ParameterCount;
5991 pSMB->TotalDataCount = pSMB->DataCount;
5992 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5993 pSMB->Reserved4 = 0;
be8e3b00 5994 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5995
654cf14a 5996 cifs_fill_unix_set_info(data_offset, args);
1da177e4
LT
5997
5998 pSMB->ByteCount = cpu_to_le16(byte_count);
5999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 6001 if (rc)
b6b38f70 6002 cFYI(1, "SetPathInfo (perms) returned %d", rc);
1da177e4 6003
0d817bc0 6004 cifs_buf_release(pSMB);
1da177e4
LT
6005 if (rc == -EAGAIN)
6006 goto setPermsRetry;
6007 return rc;
6008}
6009
1da177e4 6010#ifdef CONFIG_CIFS_XATTR
31c0519f
JL
6011/*
6012 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6013 * function used by listxattr and getxattr type calls. When ea_name is set,
6014 * it looks for that attribute name and stuffs that value into the EAData
6015 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6016 * buffer. In both cases, the return value is either the length of the
6017 * resulting data or a negative error code. If EAData is a NULL pointer then
6018 * the data isn't copied to it, but the length is returned.
6019 */
1da177e4 6020ssize_t
96daf2b0 6021CIFSSMBQAllEAs(const int xid, struct cifs_tcon *tcon,
31c0519f
JL
6022 const unsigned char *searchName, const unsigned char *ea_name,
6023 char *EAData, size_t buf_size,
6024 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
6025{
6026 /* BB assumes one setup word */
6027 TRANSACTION2_QPI_REQ *pSMB = NULL;
6028 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6029 int rc = 0;
6030 int bytes_returned;
6e462b9f 6031 int list_len;
f0d3868b 6032 struct fealist *ea_response_data;
50c2f753
SF
6033 struct fea *temp_fea;
6034 char *temp_ptr;
0cd126b5 6035 char *end_of_smb;
f0d3868b 6036 __u16 params, byte_count, data_offset;
5980fc96 6037 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
1da177e4 6038
b6b38f70 6039 cFYI(1, "In Query All EAs path %s", searchName);
1da177e4
LT
6040QAllEAsRetry:
6041 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6042 (void **) &pSMBr);
6043 if (rc)
6044 return rc;
6045
6046 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6e462b9f 6047 list_len =
acbbb76a
SF
6048 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6049 PATH_MAX, nls_codepage, remap);
6e462b9f
JL
6050 list_len++; /* trailing null */
6051 list_len *= 2;
1da177e4 6052 } else { /* BB improve the check for buffer overruns BB */
6e462b9f
JL
6053 list_len = strnlen(searchName, PATH_MAX);
6054 list_len++; /* trailing null */
6055 strncpy(pSMB->FileName, searchName, list_len);
1da177e4
LT
6056 }
6057
6e462b9f 6058 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
1da177e4
LT
6059 pSMB->TotalDataCount = 0;
6060 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5 6061 /* BB find exact max SMB PDU from sess structure BB */
e529614a 6062 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
1da177e4
LT
6063 pSMB->MaxSetupCount = 0;
6064 pSMB->Reserved = 0;
6065 pSMB->Flags = 0;
6066 pSMB->Timeout = 0;
6067 pSMB->Reserved2 = 0;
6068 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 6069 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
6070 pSMB->DataCount = 0;
6071 pSMB->DataOffset = 0;
6072 pSMB->SetupCount = 1;
6073 pSMB->Reserved3 = 0;
6074 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6075 byte_count = params + 1 /* pad */ ;
6076 pSMB->TotalParameterCount = cpu_to_le16(params);
6077 pSMB->ParameterCount = pSMB->TotalParameterCount;
6078 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6079 pSMB->Reserved4 = 0;
be8e3b00 6080 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
6081 pSMB->ByteCount = cpu_to_le16(byte_count);
6082
6083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6085 if (rc) {
b6b38f70 6086 cFYI(1, "Send error in QueryAllEAs = %d", rc);
f0d3868b
JL
6087 goto QAllEAsOut;
6088 }
1da177e4 6089
f0d3868b
JL
6090
6091 /* BB also check enough total bytes returned */
6092 /* BB we need to improve the validity checking
6093 of these trans2 responses */
6094
6095 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
820a803f 6096 if (rc || get_bcc(&pSMBr->hdr) < 4) {
f0d3868b
JL
6097 rc = -EIO; /* bad smb */
6098 goto QAllEAsOut;
6099 }
6100
6101 /* check that length of list is not more than bcc */
6102 /* check that each entry does not go beyond length
6103 of list */
6104 /* check that each element of each entry does not
6105 go beyond end of list */
6106 /* validate_trans2_offsets() */
6107 /* BB check if start of smb + data_offset > &bcc+ bcc */
6108
6109 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6110 ea_response_data = (struct fealist *)
6111 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6112
6e462b9f 6113 list_len = le32_to_cpu(ea_response_data->list_len);
b6b38f70 6114 cFYI(1, "ea length %d", list_len);
6e462b9f 6115 if (list_len <= 8) {
b6b38f70 6116 cFYI(1, "empty EA list returned from server");
f0d3868b
JL
6117 goto QAllEAsOut;
6118 }
6119
0cd126b5 6120 /* make sure list_len doesn't go past end of SMB */
690c522f 6121 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
0cd126b5 6122 if ((char *)ea_response_data + list_len > end_of_smb) {
b6b38f70 6123 cFYI(1, "EA list appears to go beyond SMB");
0cd126b5
JL
6124 rc = -EIO;
6125 goto QAllEAsOut;
6126 }
6127
f0d3868b 6128 /* account for ea list len */
6e462b9f 6129 list_len -= 4;
f0d3868b
JL
6130 temp_fea = ea_response_data->list;
6131 temp_ptr = (char *)temp_fea;
6e462b9f 6132 while (list_len > 0) {
122ca007 6133 unsigned int name_len;
f0d3868b 6134 __u16 value_len;
0cd126b5 6135
6e462b9f 6136 list_len -= 4;
f0d3868b 6137 temp_ptr += 4;
0cd126b5
JL
6138 /* make sure we can read name_len and value_len */
6139 if (list_len < 0) {
b6b38f70 6140 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
6141 rc = -EIO;
6142 goto QAllEAsOut;
6143 }
6144
6145 name_len = temp_fea->name_len;
6146 value_len = le16_to_cpu(temp_fea->value_len);
6147 list_len -= name_len + 1 + value_len;
6148 if (list_len < 0) {
b6b38f70 6149 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
6150 rc = -EIO;
6151 goto QAllEAsOut;
6152 }
6153
31c0519f 6154 if (ea_name) {
91d065c4 6155 if (ea_name_len == name_len &&
ac423446 6156 memcmp(ea_name, temp_ptr, name_len) == 0) {
31c0519f
JL
6157 temp_ptr += name_len + 1;
6158 rc = value_len;
6159 if (buf_size == 0)
6160 goto QAllEAsOut;
6161 if ((size_t)value_len > buf_size) {
6162 rc = -ERANGE;
6163 goto QAllEAsOut;
6164 }
6165 memcpy(EAData, temp_ptr, value_len);
6166 goto QAllEAsOut;
6167 }
f0d3868b 6168 } else {
31c0519f
JL
6169 /* account for prefix user. and trailing null */
6170 rc += (5 + 1 + name_len);
6171 if (rc < (int) buf_size) {
6172 memcpy(EAData, "user.", 5);
6173 EAData += 5;
6174 memcpy(EAData, temp_ptr, name_len);
6175 EAData += name_len;
6176 /* null terminate name */
6177 *EAData = 0;
6178 ++EAData;
6179 } else if (buf_size == 0) {
6180 /* skip copy - calc size only */
6181 } else {
6182 /* stop before overrun buffer */
6183 rc = -ERANGE;
6184 break;
6185 }
1da177e4 6186 }
0cd126b5 6187 temp_ptr += name_len + 1 + value_len;
f0d3868b 6188 temp_fea = (struct fea *)temp_ptr;
1da177e4 6189 }
f0d3868b 6190
31c0519f
JL
6191 /* didn't find the named attribute */
6192 if (ea_name)
6193 rc = -ENODATA;
6194
f0d3868b 6195QAllEAsOut:
0d817bc0 6196 cifs_buf_release(pSMB);
1da177e4
LT
6197 if (rc == -EAGAIN)
6198 goto QAllEAsRetry;
6199
6200 return (ssize_t)rc;
6201}
6202
1da177e4 6203int
96daf2b0 6204CIFSSMBSetEA(const int xid, struct cifs_tcon *tcon, const char *fileName,
50c2f753
SF
6205 const char *ea_name, const void *ea_value,
6206 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6207 int remap)
1da177e4
LT
6208{
6209 struct smb_com_transaction2_spi_req *pSMB = NULL;
6210 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6211 struct fealist *parm_data;
6212 int name_len;
6213 int rc = 0;
6214 int bytes_returned = 0;
6215 __u16 params, param_offset, byte_count, offset, count;
6216
b6b38f70 6217 cFYI(1, "In SetEA");
1da177e4
LT
6218SetEARetry:
6219 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6220 (void **) &pSMBr);
6221 if (rc)
6222 return rc;
6223
6224 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6225 name_len =
acbbb76a
SF
6226 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6227 PATH_MAX, nls_codepage, remap);
1da177e4
LT
6228 name_len++; /* trailing null */
6229 name_len *= 2;
50c2f753 6230 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
6231 name_len = strnlen(fileName, PATH_MAX);
6232 name_len++; /* trailing null */
6233 strncpy(pSMB->FileName, fileName, name_len);
6234 }
6235
6236 params = 6 + name_len;
6237
6238 /* done calculating parms using name_len of file name,
6239 now use name_len to calculate length of ea name
6240 we are going to create in the inode xattrs */
790fe579 6241 if (ea_name == NULL)
1da177e4
LT
6242 name_len = 0;
6243 else
50c2f753 6244 name_len = strnlen(ea_name, 255);
1da177e4 6245
dae5dbdb 6246 count = sizeof(*parm_data) + ea_value_len + name_len;
1da177e4 6247 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
6248 /* BB find max SMB PDU from sess */
6249 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
6250 pSMB->MaxSetupCount = 0;
6251 pSMB->Reserved = 0;
6252 pSMB->Flags = 0;
6253 pSMB->Timeout = 0;
6254 pSMB->Reserved2 = 0;
6255 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 6256 InformationLevel) - 4;
1da177e4
LT
6257 offset = param_offset + params;
6258 pSMB->InformationLevel =
6259 cpu_to_le16(SMB_SET_FILE_EA);
6260
6261 parm_data =
6262 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6263 offset);
6264 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6265 pSMB->DataOffset = cpu_to_le16(offset);
6266 pSMB->SetupCount = 1;
6267 pSMB->Reserved3 = 0;
6268 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6269 byte_count = 3 /* pad */ + params + count;
6270 pSMB->DataCount = cpu_to_le16(count);
6271 parm_data->list_len = cpu_to_le32(count);
6272 parm_data->list[0].EA_flags = 0;
6273 /* we checked above that name len is less than 255 */
53b3531b 6274 parm_data->list[0].name_len = (__u8)name_len;
1da177e4 6275 /* EA names are always ASCII */
790fe579 6276 if (ea_name)
50c2f753 6277 strncpy(parm_data->list[0].name, ea_name, name_len);
1da177e4
LT
6278 parm_data->list[0].name[name_len] = 0;
6279 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6280 /* caller ensures that ea_value_len is less than 64K but
6281 we need to ensure that it fits within the smb */
6282
50c2f753
SF
6283 /*BB add length check to see if it would fit in
6284 negotiated SMB buffer size BB */
790fe579
SF
6285 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6286 if (ea_value_len)
50c2f753
SF
6287 memcpy(parm_data->list[0].name+name_len+1,
6288 ea_value, ea_value_len);
1da177e4
LT
6289
6290 pSMB->TotalDataCount = pSMB->DataCount;
6291 pSMB->ParameterCount = cpu_to_le16(params);
6292 pSMB->TotalParameterCount = pSMB->ParameterCount;
6293 pSMB->Reserved4 = 0;
be8e3b00 6294 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
6295 pSMB->ByteCount = cpu_to_le16(byte_count);
6296 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6297 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 6298 if (rc)
b6b38f70 6299 cFYI(1, "SetPathInfo (EA) returned %d", rc);
1da177e4
LT
6300
6301 cifs_buf_release(pSMB);
6302
6303 if (rc == -EAGAIN)
6304 goto SetEARetry;
6305
6306 return rc;
6307}
1da177e4 6308#endif
0eff0e26
SF
6309
6310#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6311/*
6312 * Years ago the kernel added a "dnotify" function for Samba server,
6313 * to allow network clients (such as Windows) to display updated
6314 * lists of files in directory listings automatically when
6315 * files are added by one user when another user has the
6316 * same directory open on their desktop. The Linux cifs kernel
6317 * client hooked into the kernel side of this interface for
6318 * the same reason, but ironically when the VFS moved from
6319 * "dnotify" to "inotify" it became harder to plug in Linux
6320 * network file system clients (the most obvious use case
6321 * for notify interfaces is when multiple users can update
6322 * the contents of the same directory - exactly what network
6323 * file systems can do) although the server (Samba) could
6324 * still use it. For the short term we leave the worker
6325 * function ifdeffed out (below) until inotify is fixed
6326 * in the VFS to make it easier to plug in network file
6327 * system clients. If inotify turns out to be permanently
6328 * incompatible for network fs clients, we could instead simply
6329 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6330 */
96daf2b0 6331int CIFSSMBNotify(const int xid, struct cifs_tcon *tcon,
0eff0e26
SF
6332 const int notify_subdirs, const __u16 netfid,
6333 __u32 filter, struct file *pfile, int multishot,
6334 const struct nls_table *nls_codepage)
6335{
6336 int rc = 0;
6337 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6338 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6339 struct dir_notify_req *dnotify_req;
6340 int bytes_returned;
6341
6342 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6343 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6344 (void **) &pSMBr);
6345 if (rc)
6346 return rc;
6347
6348 pSMB->TotalParameterCount = 0 ;
6349 pSMB->TotalDataCount = 0;
6350 pSMB->MaxParameterCount = cpu_to_le32(2);
c974befa 6351 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
0eff0e26
SF
6352 pSMB->MaxSetupCount = 4;
6353 pSMB->Reserved = 0;
6354 pSMB->ParameterOffset = 0;
6355 pSMB->DataCount = 0;
6356 pSMB->DataOffset = 0;
6357 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6358 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6359 pSMB->ParameterCount = pSMB->TotalParameterCount;
6360 if (notify_subdirs)
6361 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6362 pSMB->Reserved2 = 0;
6363 pSMB->CompletionFilter = cpu_to_le32(filter);
6364 pSMB->Fid = netfid; /* file handle always le */
6365 pSMB->ByteCount = 0;
6366
6367 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6368 (struct smb_hdr *)pSMBr, &bytes_returned,
6369 CIFS_ASYNC_OP);
6370 if (rc) {
6371 cFYI(1, "Error in Notify = %d", rc);
6372 } else {
6373 /* Add file to outstanding requests */
6374 /* BB change to kmem cache alloc */
6375 dnotify_req = kmalloc(
6376 sizeof(struct dir_notify_req),
6377 GFP_KERNEL);
6378 if (dnotify_req) {
6379 dnotify_req->Pid = pSMB->hdr.Pid;
6380 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6381 dnotify_req->Mid = pSMB->hdr.Mid;
6382 dnotify_req->Tid = pSMB->hdr.Tid;
6383 dnotify_req->Uid = pSMB->hdr.Uid;
6384 dnotify_req->netfid = netfid;
6385 dnotify_req->pfile = pfile;
6386 dnotify_req->filter = filter;
6387 dnotify_req->multishot = multishot;
6388 spin_lock(&GlobalMid_Lock);
6389 list_add_tail(&dnotify_req->lhead,
6390 &GlobalDnotifyReqList);
6391 spin_unlock(&GlobalMid_Lock);
6392 } else
6393 rc = -ENOMEM;
6394 }
6395 cifs_buf_release(pSMB);
6396 return rc;
6397}
6398#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */
This page took 1.028671 seconds and 5 git commands to generate.