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