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