]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/cifs/cifssmb.c
CIFS: Add SMB2 support for rename operation
[mirror_ubuntu-artful-kernel.git] / fs / cifs / cifssmb.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/cifssmb.c
3 *
f19159dc 4 * Copyright (C) International Business Machines Corp., 2002,2010
1da177e4
LT
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
2dd29d31
SF
27 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
1da177e4
LT
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
5a0e3ad6 33#include <linux/slab.h>
1da177e4 34#include <linux/posix_acl_xattr.h>
c28c89fc 35#include <linux/pagemap.h>
e28bc5b1
JL
36#include <linux/swap.h>
37#include <linux/task_io_accounting_ops.h>
1da177e4
LT
38#include <asm/uaccess.h>
39#include "cifspdu.h"
40#include "cifsglob.h"
d0d66c44 41#include "cifsacl.h"
1da177e4
LT
42#include "cifsproto.h"
43#include "cifs_unicode.h"
44#include "cifs_debug.h"
e28bc5b1 45#include "fscache.h"
1da177e4
LT
46
47#ifdef CONFIG_CIFS_POSIX
48static struct {
49 int index;
50 char *name;
51} protocols[] = {
3979877e
SF
52#ifdef CONFIG_CIFS_WEAK_PW_HASH
53 {LANMAN_PROT, "\2LM1.2X002"},
9ac00b7d 54 {LANMAN2_PROT, "\2LANMAN2.1"},
3979877e 55#endif /* weak password hashing for legacy clients */
50c2f753 56 {CIFS_PROT, "\2NT LM 0.12"},
3979877e 57 {POSIX_PROT, "\2POSIX 2"},
1da177e4
LT
58 {BAD_PROT, "\2"}
59};
60#else
61static struct {
62 int index;
63 char *name;
64} protocols[] = {
3979877e
SF
65#ifdef CONFIG_CIFS_WEAK_PW_HASH
66 {LANMAN_PROT, "\2LM1.2X002"},
18f75ca0 67 {LANMAN2_PROT, "\2LANMAN2.1"},
3979877e 68#endif /* weak password hashing for legacy clients */
790fe579 69 {CIFS_PROT, "\2NT LM 0.12"},
1da177e4
LT
70 {BAD_PROT, "\2"}
71};
72#endif
73
3979877e
SF
74/* define the number of elements in the cifs dialect array */
75#ifdef CONFIG_CIFS_POSIX
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
9ac00b7d 77#define CIFS_NUM_PROT 4
3979877e
SF
78#else
79#define CIFS_NUM_PROT 2
80#endif /* CIFS_WEAK_PW_HASH */
81#else /* not posix */
82#ifdef CONFIG_CIFS_WEAK_PW_HASH
9ac00b7d 83#define CIFS_NUM_PROT 3
3979877e
SF
84#else
85#define CIFS_NUM_PROT 1
86#endif /* CONFIG_CIFS_WEAK_PW_HASH */
87#endif /* CIFS_POSIX */
88
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,
1da177e4 2927 const char *fromName, const char *toName,
737b758c 2928 const struct nls_table *nls_codepage, int remap)
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;
2936
b6b38f70 2937 cFYI(1, "In CIFSCreateHardLink");
1da177e4
LT
2938winCreateHardLinkRetry:
2939
2940 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2941 (void **) &pSMBr);
2942 if (rc)
2943 return rc;
2944
2945 pSMB->SearchAttributes =
2946 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2947 ATTR_DIRECTORY);
2948 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2949 pSMB->ClusterCount = 0;
2950
2951 pSMB->BufferFormat = 0x04;
2952
2953 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2954 name_len =
acbbb76a
SF
2955 cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
2956 PATH_MAX, nls_codepage, remap);
1da177e4
LT
2957 name_len++; /* trailing null */
2958 name_len *= 2;
fcc7c09d
JL
2959
2960 /* protocol specifies ASCII buffer format (0x04) for unicode */
2961 pSMB->OldFileName[name_len] = 0x04;
2962 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
1da177e4 2963 name_len2 =
acbbb76a
SF
2964 cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
2965 toName, PATH_MAX, nls_codepage, remap);
1da177e4
LT
2966 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2967 name_len2 *= 2; /* convert to bytes */
50c2f753 2968 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
2969 name_len = strnlen(fromName, PATH_MAX);
2970 name_len++; /* trailing null */
2971 strncpy(pSMB->OldFileName, fromName, name_len);
2972 name_len2 = strnlen(toName, PATH_MAX);
2973 name_len2++; /* trailing null */
2974 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2975 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2976 name_len2++; /* trailing null */
2977 name_len2++; /* signature byte */
2978 }
2979
2980 count = 1 /* string type byte */ + name_len + name_len2;
be8e3b00 2981 inc_rfc1001_len(pSMB, count);
1da177e4
LT
2982 pSMB->ByteCount = cpu_to_le16(count);
2983
2984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
44c58186 2986 cifs_stats_inc(&tcon->stats.cifs_stats.num_hardlinks);
ad7a2926 2987 if (rc)
b6b38f70 2988 cFYI(1, "Send error in hard link (NT rename) = %d", rc);
ad7a2926 2989
1da177e4
LT
2990 cifs_buf_release(pSMB);
2991 if (rc == -EAGAIN)
2992 goto winCreateHardLinkRetry;
2993
2994 return rc;
2995}
2996
2997int
6d5786a3 2998CIFSSMBUnixQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
460b9696 2999 const unsigned char *searchName, char **symlinkinfo,
1da177e4
LT
3000 const struct nls_table *nls_codepage)
3001{
3002/* SMB_QUERY_FILE_UNIX_LINK */
3003 TRANSACTION2_QPI_REQ *pSMB = NULL;
3004 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3005 int rc = 0;
3006 int bytes_returned;
3007 int name_len;
3008 __u16 params, byte_count;
460b9696 3009 char *data_start;
1da177e4 3010
b6b38f70 3011 cFYI(1, "In QPathSymLinkInfo (Unix) for path %s", searchName);
1da177e4
LT
3012
3013querySymLinkRetry:
3014 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3015 (void **) &pSMBr);
3016 if (rc)
3017 return rc;
3018
3019 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3020 name_len =
acbbb76a
SF
3021 cifs_strtoUTF16((__le16 *) pSMB->FileName, searchName,
3022 PATH_MAX, nls_codepage);
1da177e4
LT
3023 name_len++; /* trailing null */
3024 name_len *= 2;
50c2f753 3025 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3026 name_len = strnlen(searchName, PATH_MAX);
3027 name_len++; /* trailing null */
3028 strncpy(pSMB->FileName, searchName, name_len);
3029 }
3030
3031 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3032 pSMB->TotalDataCount = 0;
3033 pSMB->MaxParameterCount = cpu_to_le16(2);
46a7574c 3034 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
1da177e4
LT
3035 pSMB->MaxSetupCount = 0;
3036 pSMB->Reserved = 0;
3037 pSMB->Flags = 0;
3038 pSMB->Timeout = 0;
3039 pSMB->Reserved2 = 0;
3040 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 3041 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
3042 pSMB->DataCount = 0;
3043 pSMB->DataOffset = 0;
3044 pSMB->SetupCount = 1;
3045 pSMB->Reserved3 = 0;
3046 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3047 byte_count = params + 1 /* pad */ ;
3048 pSMB->TotalParameterCount = cpu_to_le16(params);
3049 pSMB->ParameterCount = pSMB->TotalParameterCount;
3050 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
3051 pSMB->Reserved4 = 0;
be8e3b00 3052 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
3053 pSMB->ByteCount = cpu_to_le16(byte_count);
3054
3055 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3056 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3057 if (rc) {
b6b38f70 3058 cFYI(1, "Send error in QuerySymLinkInfo = %d", rc);
1da177e4
LT
3059 } else {
3060 /* decode response */
3061
3062 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 3063 /* BB also check enough total bytes returned */
820a803f 3064 if (rc || get_bcc(&pSMBr->hdr) < 2)
460b9696 3065 rc = -EIO;
1da177e4 3066 else {
0e0d2cf3 3067 bool is_unicode;
460b9696
JL
3068 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3069
3070 data_start = ((char *) &pSMBr->hdr.Protocol) +
3071 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4 3072
0e0d2cf3
SF
3073 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3074 is_unicode = true;
3075 else
3076 is_unicode = false;
3077
737b758c 3078 /* BB FIXME investigate remapping reserved chars here */
acbbb76a
SF
3079 *symlinkinfo = cifs_strndup_from_utf16(data_start,
3080 count, is_unicode, nls_codepage);
8b6427a2 3081 if (!*symlinkinfo)
460b9696 3082 rc = -ENOMEM;
1da177e4
LT
3083 }
3084 }
3085 cifs_buf_release(pSMB);
3086 if (rc == -EAGAIN)
3087 goto querySymLinkRetry;
3088 return rc;
3089}
3090
c52a9554
SF
3091#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
3092/*
3093 * Recent Windows versions now create symlinks more frequently
3094 * and they use the "reparse point" mechanism below. We can of course
3095 * do symlinks nicely to Samba and other servers which support the
3096 * CIFS Unix Extensions and we can also do SFU symlinks and "client only"
3097 * "MF" symlinks optionally, but for recent Windows we really need to
3098 * reenable the code below and fix the cifs_symlink callers to handle this.
3099 * In the interim this code has been moved to its own config option so
3100 * it is not compiled in by default until callers fixed up and more tested.
3101 */
1da177e4 3102int
6d5786a3 3103CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
1da177e4 3104 const unsigned char *searchName,
50c2f753 3105 char *symlinkinfo, const int buflen, __u16 fid,
1da177e4
LT
3106 const struct nls_table *nls_codepage)
3107{
3108 int rc = 0;
3109 int bytes_returned;
50c2f753
SF
3110 struct smb_com_transaction_ioctl_req *pSMB;
3111 struct smb_com_transaction_ioctl_rsp *pSMBr;
1da177e4 3112
b6b38f70 3113 cFYI(1, "In Windows reparse style QueryLink for path %s", searchName);
1da177e4
LT
3114 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3115 (void **) &pSMBr);
3116 if (rc)
3117 return rc;
3118
3119 pSMB->TotalParameterCount = 0 ;
3120 pSMB->TotalDataCount = 0;
3121 pSMB->MaxParameterCount = cpu_to_le32(2);
3122 /* BB find exact data count max from sess structure BB */
c974befa 3123 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
1da177e4
LT
3124 pSMB->MaxSetupCount = 4;
3125 pSMB->Reserved = 0;
3126 pSMB->ParameterOffset = 0;
3127 pSMB->DataCount = 0;
3128 pSMB->DataOffset = 0;
3129 pSMB->SetupCount = 4;
3130 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
3131 pSMB->ParameterCount = pSMB->TotalParameterCount;
3132 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
3133 pSMB->IsFsctl = 1; /* FSCTL */
3134 pSMB->IsRootFlag = 0;
3135 pSMB->Fid = fid; /* file handle always le */
3136 pSMB->ByteCount = 0;
3137
3138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3139 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3140 if (rc) {
b6b38f70 3141 cFYI(1, "Send error in QueryReparseLinkInfo = %d", rc);
1da177e4
LT
3142 } else { /* decode response */
3143 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
3144 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
820a803f
JL
3145 if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
3146 /* BB also check enough total bytes returned */
1da177e4 3147 rc = -EIO; /* bad smb */
afe48c31
SF
3148 goto qreparse_out;
3149 }
3150 if (data_count && (data_count < 2048)) {
3151 char *end_of_smb = 2 /* sizeof byte count */ +
820a803f 3152 get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
1da177e4 3153
afe48c31 3154 struct reparse_data *reparse_buf =
50c2f753
SF
3155 (struct reparse_data *)
3156 ((char *)&pSMBr->hdr.Protocol
3157 + data_offset);
afe48c31
SF
3158 if ((char *)reparse_buf >= end_of_smb) {
3159 rc = -EIO;
3160 goto qreparse_out;
3161 }
3162 if ((reparse_buf->LinkNamesBuf +
3163 reparse_buf->TargetNameOffset +
3164 reparse_buf->TargetNameLen) > end_of_smb) {
b6b38f70 3165 cFYI(1, "reparse buf beyond SMB");
afe48c31
SF
3166 rc = -EIO;
3167 goto qreparse_out;
3168 }
50c2f753 3169
afe48c31
SF
3170 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3171 cifs_from_ucs2(symlinkinfo, (__le16 *)
50c2f753
SF
3172 (reparse_buf->LinkNamesBuf +
3173 reparse_buf->TargetNameOffset),
afe48c31
SF
3174 buflen,
3175 reparse_buf->TargetNameLen,
3176 nls_codepage, 0);
3177 } else { /* ASCII names */
3178 strncpy(symlinkinfo,
3179 reparse_buf->LinkNamesBuf +
3180 reparse_buf->TargetNameOffset,
3181 min_t(const int, buflen,
3182 reparse_buf->TargetNameLen));
1da177e4 3183 }
afe48c31
SF
3184 } else {
3185 rc = -EIO;
b6b38f70
JP
3186 cFYI(1, "Invalid return data count on "
3187 "get reparse info ioctl");
1da177e4 3188 }
afe48c31
SF
3189 symlinkinfo[buflen] = 0; /* just in case so the caller
3190 does not go off the end of the buffer */
b6b38f70 3191 cFYI(1, "readlink result - %s", symlinkinfo);
1da177e4 3192 }
989c7e51 3193
1da177e4 3194qreparse_out:
4a6d87f1 3195 cifs_buf_release(pSMB);
1da177e4
LT
3196
3197 /* Note: On -EAGAIN error only caller can retry on handle based calls
3198 since file handle passed in no longer valid */
3199
3200 return rc;
3201}
c52a9554 3202#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
1da177e4
LT
3203
3204#ifdef CONFIG_CIFS_POSIX
3205
3206/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
50c2f753
SF
3207static void cifs_convert_ace(posix_acl_xattr_entry *ace,
3208 struct cifs_posix_ace *cifs_ace)
1da177e4
LT
3209{
3210 /* u8 cifs fields do not need le conversion */
ff7feac9
SF
3211 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
3212 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
3213 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
b6b38f70 3214 /* cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id); */
1da177e4
LT
3215
3216 return;
3217}
3218
3219/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
50c2f753
SF
3220static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
3221 const int acl_type, const int size_of_data_area)
1da177e4
LT
3222{
3223 int size = 0;
3224 int i;
3225 __u16 count;
50c2f753
SF
3226 struct cifs_posix_ace *pACE;
3227 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
3228 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
1da177e4
LT
3229
3230 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
3231 return -EOPNOTSUPP;
3232
790fe579 3233 if (acl_type & ACL_TYPE_ACCESS) {
1da177e4
LT
3234 count = le16_to_cpu(cifs_acl->access_entry_count);
3235 pACE = &cifs_acl->ace_array[0];
3236 size = sizeof(struct cifs_posix_acl);
3237 size += sizeof(struct cifs_posix_ace) * count;
3238 /* check if we would go beyond end of SMB */
790fe579 3239 if (size_of_data_area < size) {
b6b38f70
JP
3240 cFYI(1, "bad CIFS POSIX ACL size %d vs. %d",
3241 size_of_data_area, size);
1da177e4
LT
3242 return -EINVAL;
3243 }
790fe579 3244 } else if (acl_type & ACL_TYPE_DEFAULT) {
1da177e4
LT
3245 count = le16_to_cpu(cifs_acl->access_entry_count);
3246 size = sizeof(struct cifs_posix_acl);
3247 size += sizeof(struct cifs_posix_ace) * count;
3248/* skip past access ACEs to get to default ACEs */
3249 pACE = &cifs_acl->ace_array[count];
3250 count = le16_to_cpu(cifs_acl->default_entry_count);
3251 size += sizeof(struct cifs_posix_ace) * count;
3252 /* check if we would go beyond end of SMB */
790fe579 3253 if (size_of_data_area < size)
1da177e4
LT
3254 return -EINVAL;
3255 } else {
3256 /* illegal type */
3257 return -EINVAL;
3258 }
3259
3260 size = posix_acl_xattr_size(count);
790fe579 3261 if ((buflen == 0) || (local_acl == NULL)) {
50c2f753 3262 /* used to query ACL EA size */
790fe579 3263 } else if (size > buflen) {
1da177e4
LT
3264 return -ERANGE;
3265 } else /* buffer big enough */ {
ff7feac9 3266 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
50c2f753
SF
3267 for (i = 0; i < count ; i++) {
3268 cifs_convert_ace(&local_acl->a_entries[i], pACE);
3269 pACE++;
1da177e4
LT
3270 }
3271 }
3272 return size;
3273}
3274
50c2f753
SF
3275static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
3276 const posix_acl_xattr_entry *local_ace)
1da177e4
LT
3277{
3278 __u16 rc = 0; /* 0 = ACL converted ok */
3279
ff7feac9
SF
3280 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
3281 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
1da177e4 3282 /* BB is there a better way to handle the large uid? */
790fe579 3283 if (local_ace->e_id == cpu_to_le32(-1)) {
1da177e4
LT
3284 /* Probably no need to le convert -1 on any arch but can not hurt */
3285 cifs_ace->cifs_uid = cpu_to_le64(-1);
50c2f753 3286 } else
ff7feac9 3287 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
b6b38f70 3288 /*cFYI(1, "perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id);*/
1da177e4
LT
3289 return rc;
3290}
3291
3292/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
50c2f753
SF
3293static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
3294 const int buflen, const int acl_type)
1da177e4
LT
3295{
3296 __u16 rc = 0;
50c2f753
SF
3297 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
3298 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
1da177e4
LT
3299 int count;
3300 int i;
3301
790fe579 3302 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1da177e4
LT
3303 return 0;
3304
3305 count = posix_acl_xattr_count((size_t)buflen);
b6b38f70 3306 cFYI(1, "setting acl with %d entries from buf of length %d and "
63135e08 3307 "version of %d",
b6b38f70 3308 count, buflen, le32_to_cpu(local_acl->a_version));
790fe579 3309 if (le32_to_cpu(local_acl->a_version) != 2) {
b6b38f70
JP
3310 cFYI(1, "unknown POSIX ACL version %d",
3311 le32_to_cpu(local_acl->a_version));
1da177e4
LT
3312 return 0;
3313 }
3314 cifs_acl->version = cpu_to_le16(1);
790fe579 3315 if (acl_type == ACL_TYPE_ACCESS)
ff7feac9 3316 cifs_acl->access_entry_count = cpu_to_le16(count);
790fe579 3317 else if (acl_type == ACL_TYPE_DEFAULT)
ff7feac9 3318 cifs_acl->default_entry_count = cpu_to_le16(count);
1da177e4 3319 else {
b6b38f70 3320 cFYI(1, "unknown ACL type %d", acl_type);
1da177e4
LT
3321 return 0;
3322 }
50c2f753 3323 for (i = 0; i < count; i++) {
1da177e4
LT
3324 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
3325 &local_acl->a_entries[i]);
790fe579 3326 if (rc != 0) {
1da177e4
LT
3327 /* ACE not converted */
3328 break;
3329 }
3330 }
790fe579 3331 if (rc == 0) {
1da177e4
LT
3332 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
3333 rc += sizeof(struct cifs_posix_acl);
3334 /* BB add check to make sure ACL does not overflow SMB */
3335 }
3336 return rc;
3337}
3338
3339int
6d5786a3 3340CIFSSMBGetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
50c2f753
SF
3341 const unsigned char *searchName,
3342 char *acl_inf, const int buflen, const int acl_type,
3343 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3344{
3345/* SMB_QUERY_POSIX_ACL */
3346 TRANSACTION2_QPI_REQ *pSMB = NULL;
3347 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3348 int rc = 0;
3349 int bytes_returned;
3350 int name_len;
3351 __u16 params, byte_count;
50c2f753 3352
b6b38f70 3353 cFYI(1, "In GetPosixACL (Unix) for path %s", searchName);
1da177e4
LT
3354
3355queryAclRetry:
3356 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3357 (void **) &pSMBr);
3358 if (rc)
3359 return rc;
50c2f753 3360
1da177e4
LT
3361 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3362 name_len =
acbbb76a
SF
3363 cifsConvertToUTF16((__le16 *) pSMB->FileName,
3364 searchName, PATH_MAX, nls_codepage,
3365 remap);
1da177e4
LT
3366 name_len++; /* trailing null */
3367 name_len *= 2;
3368 pSMB->FileName[name_len] = 0;
3369 pSMB->FileName[name_len+1] = 0;
50c2f753 3370 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3371 name_len = strnlen(searchName, PATH_MAX);
3372 name_len++; /* trailing null */
3373 strncpy(pSMB->FileName, searchName, name_len);
3374 }
3375
3376 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3377 pSMB->TotalDataCount = 0;
3378 pSMB->MaxParameterCount = cpu_to_le16(2);
50c2f753 3379 /* BB find exact max data count below from sess structure BB */
1da177e4
LT
3380 pSMB->MaxDataCount = cpu_to_le16(4000);
3381 pSMB->MaxSetupCount = 0;
3382 pSMB->Reserved = 0;
3383 pSMB->Flags = 0;
3384 pSMB->Timeout = 0;
3385 pSMB->Reserved2 = 0;
3386 pSMB->ParameterOffset = cpu_to_le16(
50c2f753
SF
3387 offsetof(struct smb_com_transaction2_qpi_req,
3388 InformationLevel) - 4);
1da177e4
LT
3389 pSMB->DataCount = 0;
3390 pSMB->DataOffset = 0;
3391 pSMB->SetupCount = 1;
3392 pSMB->Reserved3 = 0;
3393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3394 byte_count = params + 1 /* pad */ ;
3395 pSMB->TotalParameterCount = cpu_to_le16(params);
3396 pSMB->ParameterCount = pSMB->TotalParameterCount;
3397 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
3398 pSMB->Reserved4 = 0;
be8e3b00 3399 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
3400 pSMB->ByteCount = cpu_to_le16(byte_count);
3401
3402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
44c58186 3404 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
1da177e4 3405 if (rc) {
b6b38f70 3406 cFYI(1, "Send error in Query POSIX ACL = %d", rc);
1da177e4
LT
3407 } else {
3408 /* decode response */
50c2f753 3409
1da177e4 3410 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 3411 /* BB also check enough total bytes returned */
820a803f 3412 if (rc || get_bcc(&pSMBr->hdr) < 2)
1da177e4
LT
3413 rc = -EIO; /* bad smb */
3414 else {
3415 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3416 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3417 rc = cifs_copy_posix_acl(acl_inf,
3418 (char *)&pSMBr->hdr.Protocol+data_offset,
50c2f753 3419 buflen, acl_type, count);
1da177e4
LT
3420 }
3421 }
3422 cifs_buf_release(pSMB);
3423 if (rc == -EAGAIN)
3424 goto queryAclRetry;
3425 return rc;
3426}
3427
3428int
6d5786a3 3429CIFSSMBSetPosixACL(const unsigned int xid, struct cifs_tcon *tcon,
50c2f753
SF
3430 const unsigned char *fileName,
3431 const char *local_acl, const int buflen,
3432 const int acl_type,
3433 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
3434{
3435 struct smb_com_transaction2_spi_req *pSMB = NULL;
3436 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3437 char *parm_data;
3438 int name_len;
3439 int rc = 0;
3440 int bytes_returned = 0;
3441 __u16 params, byte_count, data_count, param_offset, offset;
3442
b6b38f70 3443 cFYI(1, "In SetPosixACL (Unix) for path %s", fileName);
1da177e4
LT
3444setAclRetry:
3445 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 3446 (void **) &pSMBr);
1da177e4
LT
3447 if (rc)
3448 return rc;
3449 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3450 name_len =
acbbb76a
SF
3451 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
3452 PATH_MAX, nls_codepage, remap);
1da177e4
LT
3453 name_len++; /* trailing null */
3454 name_len *= 2;
50c2f753 3455 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
3456 name_len = strnlen(fileName, PATH_MAX);
3457 name_len++; /* trailing null */
3458 strncpy(pSMB->FileName, fileName, name_len);
3459 }
3460 params = 6 + name_len;
3461 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
3462 /* BB find max SMB size from sess */
3463 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
3464 pSMB->MaxSetupCount = 0;
3465 pSMB->Reserved = 0;
3466 pSMB->Flags = 0;
3467 pSMB->Timeout = 0;
3468 pSMB->Reserved2 = 0;
3469 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 3470 InformationLevel) - 4;
1da177e4
LT
3471 offset = param_offset + params;
3472 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
3473 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3474
3475 /* convert to on the wire format for POSIX ACL */
50c2f753 3476 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
1da177e4 3477
790fe579 3478 if (data_count == 0) {
1da177e4
LT
3479 rc = -EOPNOTSUPP;
3480 goto setACLerrorExit;
3481 }
3482 pSMB->DataOffset = cpu_to_le16(offset);
3483 pSMB->SetupCount = 1;
3484 pSMB->Reserved3 = 0;
3485 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3486 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
3487 byte_count = 3 /* pad */ + params + data_count;
3488 pSMB->DataCount = cpu_to_le16(data_count);
3489 pSMB->TotalDataCount = pSMB->DataCount;
3490 pSMB->ParameterCount = cpu_to_le16(params);
3491 pSMB->TotalParameterCount = pSMB->ParameterCount;
3492 pSMB->Reserved4 = 0;
be8e3b00 3493 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
3494 pSMB->ByteCount = cpu_to_le16(byte_count);
3495 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 3496 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 3497 if (rc)
b6b38f70 3498 cFYI(1, "Set POSIX ACL returned %d", rc);
1da177e4
LT
3499
3500setACLerrorExit:
3501 cifs_buf_release(pSMB);
3502 if (rc == -EAGAIN)
3503 goto setAclRetry;
3504 return rc;
3505}
3506
f654bac2
SF
3507/* BB fix tabs in this function FIXME BB */
3508int
6d5786a3 3509CIFSGetExtAttr(const unsigned int xid, struct cifs_tcon *tcon,
ad7a2926 3510 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
f654bac2 3511{
50c2f753
SF
3512 int rc = 0;
3513 struct smb_t2_qfi_req *pSMB = NULL;
3514 struct smb_t2_qfi_rsp *pSMBr = NULL;
3515 int bytes_returned;
3516 __u16 params, byte_count;
f654bac2 3517
b6b38f70 3518 cFYI(1, "In GetExtAttr");
790fe579
SF
3519 if (tcon == NULL)
3520 return -ENODEV;
f654bac2
SF
3521
3522GetExtAttrRetry:
790fe579
SF
3523 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3524 (void **) &pSMBr);
3525 if (rc)
3526 return rc;
f654bac2 3527
ad7a2926 3528 params = 2 /* level */ + 2 /* fid */;
790fe579
SF
3529 pSMB->t2.TotalDataCount = 0;
3530 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3531 /* BB find exact max data count below from sess structure BB */
3532 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3533 pSMB->t2.MaxSetupCount = 0;
3534 pSMB->t2.Reserved = 0;
3535 pSMB->t2.Flags = 0;
3536 pSMB->t2.Timeout = 0;
3537 pSMB->t2.Reserved2 = 0;
3538 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3539 Fid) - 4);
3540 pSMB->t2.DataCount = 0;
3541 pSMB->t2.DataOffset = 0;
3542 pSMB->t2.SetupCount = 1;
3543 pSMB->t2.Reserved3 = 0;
3544 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3545 byte_count = params + 1 /* pad */ ;
3546 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3547 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3548 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3549 pSMB->Pad = 0;
f654bac2 3550 pSMB->Fid = netfid;
be8e3b00 3551 inc_rfc1001_len(pSMB, byte_count);
790fe579
SF
3552 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
3553
3554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3556 if (rc) {
b6b38f70 3557 cFYI(1, "error %d in GetExtAttr", rc);
790fe579
SF
3558 } else {
3559 /* decode response */
3560 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
790fe579 3561 /* BB also check enough total bytes returned */
820a803f 3562 if (rc || get_bcc(&pSMBr->hdr) < 2)
790fe579
SF
3563 /* If rc should we check for EOPNOSUPP and
3564 disable the srvino flag? or in caller? */
3565 rc = -EIO; /* bad smb */
3566 else {
3567 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3568 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3569 struct file_chattr_info *pfinfo;
3570 /* BB Do we need a cast or hash here ? */
3571 if (count != 16) {
b6b38f70 3572 cFYI(1, "Illegal size ret in GetExtAttr");
790fe579
SF
3573 rc = -EIO;
3574 goto GetExtAttrOut;
3575 }
3576 pfinfo = (struct file_chattr_info *)
3577 (data_offset + (char *) &pSMBr->hdr.Protocol);
3578 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
f654bac2 3579 *pMask = le64_to_cpu(pfinfo->mask);
790fe579
SF
3580 }
3581 }
f654bac2 3582GetExtAttrOut:
790fe579
SF
3583 cifs_buf_release(pSMB);
3584 if (rc == -EAGAIN)
3585 goto GetExtAttrRetry;
3586 return rc;
f654bac2
SF
3587}
3588
f654bac2 3589#endif /* CONFIG_POSIX */
1da177e4 3590
79df1bae
JL
3591#ifdef CONFIG_CIFS_ACL
3592/*
3593 * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that
3594 * all NT TRANSACTS that we init here have total parm and data under about 400
3595 * bytes (to fit in small cifs buffer size), which is the case so far, it
3596 * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of
3597 * returned setup area) and MaxParameterCount (returned parms size) must be set
3598 * by caller
3599 */
3600static int
3601smb_init_nttransact(const __u16 sub_command, const int setup_count,
96daf2b0 3602 const int parm_len, struct cifs_tcon *tcon,
79df1bae
JL
3603 void **ret_buf)
3604{
3605 int rc;
3606 __u32 temp_offset;
3607 struct smb_com_ntransact_req *pSMB;
3608
3609 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
3610 (void **)&pSMB);
3611 if (rc)
3612 return rc;
3613 *ret_buf = (void *)pSMB;
3614 pSMB->Reserved = 0;
3615 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
3616 pSMB->TotalDataCount = 0;
c974befa 3617 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
79df1bae
JL
3618 pSMB->ParameterCount = pSMB->TotalParameterCount;
3619 pSMB->DataCount = pSMB->TotalDataCount;
3620 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
3621 (setup_count * 2) - 4 /* for rfc1001 length itself */;
3622 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
3623 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
3624 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
3625 pSMB->SubCommand = cpu_to_le16(sub_command);
3626 return 0;
3627}
3628
3629static int
3630validate_ntransact(char *buf, char **ppparm, char **ppdata,
3631 __u32 *pparmlen, __u32 *pdatalen)
3632{
3633 char *end_of_smb;
3634 __u32 data_count, data_offset, parm_count, parm_offset;
3635 struct smb_com_ntransact_rsp *pSMBr;
820a803f 3636 u16 bcc;
79df1bae
JL
3637
3638 *pdatalen = 0;
3639 *pparmlen = 0;
3640
3641 if (buf == NULL)
3642 return -EINVAL;
3643
3644 pSMBr = (struct smb_com_ntransact_rsp *)buf;
3645
820a803f
JL
3646 bcc = get_bcc(&pSMBr->hdr);
3647 end_of_smb = 2 /* sizeof byte count */ + bcc +
79df1bae
JL
3648 (char *)&pSMBr->ByteCount;
3649
3650 data_offset = le32_to_cpu(pSMBr->DataOffset);
3651 data_count = le32_to_cpu(pSMBr->DataCount);
3652 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
3653 parm_count = le32_to_cpu(pSMBr->ParameterCount);
3654
3655 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
3656 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
3657
3658 /* should we also check that parm and data areas do not overlap? */
3659 if (*ppparm > end_of_smb) {
3660 cFYI(1, "parms start after end of smb");
3661 return -EINVAL;
3662 } else if (parm_count + *ppparm > end_of_smb) {
3663 cFYI(1, "parm end after end of smb");
3664 return -EINVAL;
3665 } else if (*ppdata > end_of_smb) {
3666 cFYI(1, "data starts after end of smb");
3667 return -EINVAL;
3668 } else if (data_count + *ppdata > end_of_smb) {
3669 cFYI(1, "data %p + count %d (%p) past smb end %p start %p",
3670 *ppdata, data_count, (data_count + *ppdata),
3671 end_of_smb, pSMBr);
3672 return -EINVAL;
820a803f 3673 } else if (parm_count + data_count > bcc) {
79df1bae
JL
3674 cFYI(1, "parm count and data count larger than SMB");
3675 return -EINVAL;
3676 }
3677 *pdatalen = data_count;
3678 *pparmlen = parm_count;
3679 return 0;
3680}
3681
0a4b92c0
SF
3682/* Get Security Descriptor (by handle) from remote server for a file or dir */
3683int
6d5786a3 3684CIFSSMBGetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
630f3f0c 3685 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
0a4b92c0
SF
3686{
3687 int rc = 0;
3688 int buf_type = 0;
ad7a2926 3689 QUERY_SEC_DESC_REQ *pSMB;
0a4b92c0
SF
3690 struct kvec iov[1];
3691
b6b38f70 3692 cFYI(1, "GetCifsACL");
0a4b92c0 3693
630f3f0c
SF
3694 *pbuflen = 0;
3695 *acl_inf = NULL;
3696
b9c7a2bb 3697 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
0a4b92c0
SF
3698 8 /* parm len */, tcon, (void **) &pSMB);
3699 if (rc)
3700 return rc;
3701
3702 pSMB->MaxParameterCount = cpu_to_le32(4);
3703 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3704 pSMB->MaxSetupCount = 0;
3705 pSMB->Fid = fid; /* file handle always le */
3706 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3707 CIFS_ACL_DACL);
3708 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
be8e3b00 3709 inc_rfc1001_len(pSMB, 11);
0a4b92c0 3710 iov[0].iov_base = (char *)pSMB;
be8e3b00 3711 iov[0].iov_len = be32_to_cpu(pSMB->hdr.smb_buf_length) + 4;
0a4b92c0 3712
a761ac57 3713 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
7749981e 3714 0);
44c58186 3715 cifs_stats_inc(&tcon->stats.cifs_stats.num_acl_get);
0a4b92c0 3716 if (rc) {
b6b38f70 3717 cFYI(1, "Send error in QuerySecDesc = %d", rc);
0a4b92c0 3718 } else { /* decode response */
ad7a2926 3719 __le32 *parm;
630f3f0c
SF
3720 __u32 parm_len;
3721 __u32 acl_len;
50c2f753 3722 struct smb_com_ntransact_rsp *pSMBr;
630f3f0c 3723 char *pdata;
0a4b92c0
SF
3724
3725/* validate_nttransact */
50c2f753 3726 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
630f3f0c 3727 &pdata, &parm_len, pbuflen);
790fe579 3728 if (rc)
0a4b92c0
SF
3729 goto qsec_out;
3730 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3731
b6b38f70 3732 cFYI(1, "smb %p parm %p data %p", pSMBr, parm, *acl_inf);
0a4b92c0
SF
3733
3734 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3735 rc = -EIO; /* bad smb */
630f3f0c 3736 *pbuflen = 0;
0a4b92c0
SF
3737 goto qsec_out;
3738 }
3739
3740/* BB check that data area is minimum length and as big as acl_len */
3741
af6f4612 3742 acl_len = le32_to_cpu(*parm);
630f3f0c 3743 if (acl_len != *pbuflen) {
b6b38f70
JP
3744 cERROR(1, "acl length %d does not match %d",
3745 acl_len, *pbuflen);
630f3f0c
SF
3746 if (*pbuflen > acl_len)
3747 *pbuflen = acl_len;
3748 }
0a4b92c0 3749
630f3f0c
SF
3750 /* check if buffer is big enough for the acl
3751 header followed by the smallest SID */
3752 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3753 (*pbuflen >= 64 * 1024)) {
b6b38f70 3754 cERROR(1, "bad acl length %d", *pbuflen);
630f3f0c
SF
3755 rc = -EINVAL;
3756 *pbuflen = 0;
3757 } else {
3758 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3759 if (*acl_inf == NULL) {
3760 *pbuflen = 0;
3761 rc = -ENOMEM;
3762 }
3763 memcpy(*acl_inf, pdata, *pbuflen);
3764 }
0a4b92c0
SF
3765 }
3766qsec_out:
790fe579 3767 if (buf_type == CIFS_SMALL_BUFFER)
0a4b92c0 3768 cifs_small_buf_release(iov[0].iov_base);
790fe579 3769 else if (buf_type == CIFS_LARGE_BUFFER)
0a4b92c0 3770 cifs_buf_release(iov[0].iov_base);
4b8f930f 3771/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
0a4b92c0
SF
3772 return rc;
3773}
97837582
SF
3774
3775int
6d5786a3 3776CIFSSMBSetCIFSACL(const unsigned int xid, struct cifs_tcon *tcon, __u16 fid,
a5ff3769 3777 struct cifs_ntsd *pntsd, __u32 acllen, int aclflag)
97837582
SF
3778{
3779 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3780 int rc = 0;
3781 int bytes_returned = 0;
3782 SET_SEC_DESC_REQ *pSMB = NULL;
b2a3ad9c 3783 void *pSMBr;
97837582
SF
3784
3785setCifsAclRetry:
b2a3ad9c 3786 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB, &pSMBr);
97837582 3787 if (rc)
b2a3ad9c 3788 return rc;
97837582
SF
3789
3790 pSMB->MaxSetupCount = 0;
3791 pSMB->Reserved = 0;
3792
3793 param_count = 8;
3794 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3795 data_count = acllen;
3796 data_offset = param_offset + param_count;
3797 byte_count = 3 /* pad */ + param_count;
3798
3799 pSMB->DataCount = cpu_to_le32(data_count);
3800 pSMB->TotalDataCount = pSMB->DataCount;
3801 pSMB->MaxParameterCount = cpu_to_le32(4);
3802 pSMB->MaxDataCount = cpu_to_le32(16384);
3803 pSMB->ParameterCount = cpu_to_le32(param_count);
3804 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3805 pSMB->TotalParameterCount = pSMB->ParameterCount;
3806 pSMB->DataOffset = cpu_to_le32(data_offset);
3807 pSMB->SetupCount = 0;
3808 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3809 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3810
3811 pSMB->Fid = fid; /* file handle always le */
3812 pSMB->Reserved2 = 0;
a5ff3769 3813 pSMB->AclFlags = cpu_to_le32(aclflag);
97837582
SF
3814
3815 if (pntsd && acllen) {
b2a3ad9c
JL
3816 memcpy((char *)pSMBr + offsetof(struct smb_hdr, Protocol) +
3817 data_offset, pntsd, acllen);
be8e3b00 3818 inc_rfc1001_len(pSMB, byte_count + data_count);
97837582 3819 } else
be8e3b00 3820 inc_rfc1001_len(pSMB, byte_count);
97837582
SF
3821
3822 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3823 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3824
b6b38f70 3825 cFYI(1, "SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc);
97837582 3826 if (rc)
b6b38f70 3827 cFYI(1, "Set CIFS ACL returned %d", rc);
97837582
SF
3828 cifs_buf_release(pSMB);
3829
3830 if (rc == -EAGAIN)
3831 goto setCifsAclRetry;
3832
3833 return (rc);
3834}
3835
79df1bae 3836#endif /* CONFIG_CIFS_ACL */
0a4b92c0 3837
6b8edfe0
SF
3838/* Legacy Query Path Information call for lookup to old servers such
3839 as Win9x/WinME */
68889f26
PS
3840int
3841SMBQueryInformation(const unsigned int xid, struct cifs_tcon *tcon,
3842 const char *search_name, FILE_ALL_INFO *data,
3843 const struct nls_table *nls_codepage, int remap)
6b8edfe0 3844{
ad7a2926
SF
3845 QUERY_INFORMATION_REQ *pSMB;
3846 QUERY_INFORMATION_RSP *pSMBr;
6b8edfe0
SF
3847 int rc = 0;
3848 int bytes_returned;
3849 int name_len;
3850
68889f26 3851 cFYI(1, "In SMBQPath path %s", search_name);
6b8edfe0
SF
3852QInfRetry:
3853 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
50c2f753 3854 (void **) &pSMBr);
6b8edfe0
SF
3855 if (rc)
3856 return rc;
3857
3858 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3859 name_len =
acbbb76a 3860 cifsConvertToUTF16((__le16 *) pSMB->FileName,
68889f26 3861 search_name, PATH_MAX, nls_codepage,
acbbb76a 3862 remap);
6b8edfe0
SF
3863 name_len++; /* trailing null */
3864 name_len *= 2;
50c2f753 3865 } else {
68889f26 3866 name_len = strnlen(search_name, PATH_MAX);
6b8edfe0 3867 name_len++; /* trailing null */
68889f26 3868 strncpy(pSMB->FileName, search_name, name_len);
6b8edfe0
SF
3869 }
3870 pSMB->BufferFormat = 0x04;
50c2f753 3871 name_len++; /* account for buffer type byte */
be8e3b00 3872 inc_rfc1001_len(pSMB, (__u16)name_len);
6b8edfe0
SF
3873 pSMB->ByteCount = cpu_to_le16(name_len);
3874
3875 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
50c2f753 3876 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6b8edfe0 3877 if (rc) {
b6b38f70 3878 cFYI(1, "Send error in QueryInfo = %d", rc);
68889f26 3879 } else if (data) {
1bd5bbcb
SF
3880 struct timespec ts;
3881 __u32 time = le32_to_cpu(pSMBr->last_write_time);
ad7a2926
SF
3882
3883 /* decode response */
1bd5bbcb 3884 /* BB FIXME - add time zone adjustment BB */
68889f26 3885 memset(data, 0, sizeof(FILE_ALL_INFO));
1bd5bbcb
SF
3886 ts.tv_nsec = 0;
3887 ts.tv_sec = time;
3888 /* decode time fields */
68889f26
PS
3889 data->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
3890 data->LastWriteTime = data->ChangeTime;
3891 data->LastAccessTime = 0;
3892 data->AllocationSize =
70ca734a 3893 cpu_to_le64(le32_to_cpu(pSMBr->size));
68889f26
PS
3894 data->EndOfFile = data->AllocationSize;
3895 data->Attributes =
70ca734a 3896 cpu_to_le32(le16_to_cpu(pSMBr->attr));
6b8edfe0
SF
3897 } else
3898 rc = -EIO; /* bad buffer passed in */
3899
3900 cifs_buf_release(pSMB);
3901
3902 if (rc == -EAGAIN)
3903 goto QInfRetry;
3904
3905 return rc;
3906}
3907
bcd5357f 3908int
6d5786a3 3909CIFSSMBQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
bcd5357f
JL
3910 u16 netfid, FILE_ALL_INFO *pFindData)
3911{
3912 struct smb_t2_qfi_req *pSMB = NULL;
3913 struct smb_t2_qfi_rsp *pSMBr = NULL;
3914 int rc = 0;
3915 int bytes_returned;
3916 __u16 params, byte_count;
3917
3918QFileInfoRetry:
3919 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3920 (void **) &pSMBr);
3921 if (rc)
3922 return rc;
3923
3924 params = 2 /* level */ + 2 /* fid */;
3925 pSMB->t2.TotalDataCount = 0;
3926 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3927 /* BB find exact max data count below from sess structure BB */
3928 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
3929 pSMB->t2.MaxSetupCount = 0;
3930 pSMB->t2.Reserved = 0;
3931 pSMB->t2.Flags = 0;
3932 pSMB->t2.Timeout = 0;
3933 pSMB->t2.Reserved2 = 0;
3934 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3935 Fid) - 4);
3936 pSMB->t2.DataCount = 0;
3937 pSMB->t2.DataOffset = 0;
3938 pSMB->t2.SetupCount = 1;
3939 pSMB->t2.Reserved3 = 0;
3940 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3941 byte_count = params + 1 /* pad */ ;
3942 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3943 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3944 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3945 pSMB->Pad = 0;
3946 pSMB->Fid = netfid;
be8e3b00 3947 inc_rfc1001_len(pSMB, byte_count);
6b8edfe0 3948
bcd5357f
JL
3949 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3950 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3951 if (rc) {
f19159dc 3952 cFYI(1, "Send error in QPathInfo = %d", rc);
bcd5357f
JL
3953 } else { /* decode response */
3954 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
6b8edfe0 3955
bcd5357f
JL
3956 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3957 rc = -EIO;
820a803f 3958 else if (get_bcc(&pSMBr->hdr) < 40)
bcd5357f
JL
3959 rc = -EIO; /* bad smb */
3960 else if (pFindData) {
3961 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3962 memcpy((char *) pFindData,
3963 (char *) &pSMBr->hdr.Protocol +
3964 data_offset, sizeof(FILE_ALL_INFO));
3965 } else
3966 rc = -ENOMEM;
3967 }
3968 cifs_buf_release(pSMB);
3969 if (rc == -EAGAIN)
3970 goto QFileInfoRetry;
6b8edfe0 3971
bcd5357f
JL
3972 return rc;
3973}
6b8edfe0 3974
1da177e4 3975int
6d5786a3 3976CIFSSMBQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
68889f26 3977 const char *search_name, FILE_ALL_INFO *data,
acf1a1b1 3978 int legacy /* old style infolevel */,
737b758c 3979 const struct nls_table *nls_codepage, int remap)
1da177e4 3980{
68889f26 3981 /* level 263 SMB_QUERY_FILE_ALL_INFO */
1da177e4
LT
3982 TRANSACTION2_QPI_REQ *pSMB = NULL;
3983 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3984 int rc = 0;
3985 int bytes_returned;
3986 int name_len;
3987 __u16 params, byte_count;
3988
68889f26 3989 /* cFYI(1, "In QPathInfo path %s", search_name); */
1da177e4
LT
3990QPathInfoRetry:
3991 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3992 (void **) &pSMBr);
3993 if (rc)
3994 return rc;
3995
3996 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3997 name_len =
68889f26 3998 cifsConvertToUTF16((__le16 *) pSMB->FileName, search_name,
acbbb76a 3999 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4000 name_len++; /* trailing null */
4001 name_len *= 2;
50c2f753 4002 } else { /* BB improve the check for buffer overruns BB */
68889f26 4003 name_len = strnlen(search_name, PATH_MAX);
1da177e4 4004 name_len++; /* trailing null */
68889f26 4005 strncpy(pSMB->FileName, search_name, name_len);
1da177e4
LT
4006 }
4007
50c2f753 4008 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
4009 pSMB->TotalDataCount = 0;
4010 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
4011 /* BB find exact max SMB PDU from sess structure BB */
4012 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4013 pSMB->MaxSetupCount = 0;
4014 pSMB->Reserved = 0;
4015 pSMB->Flags = 0;
4016 pSMB->Timeout = 0;
4017 pSMB->Reserved2 = 0;
4018 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4019 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
4020 pSMB->DataCount = 0;
4021 pSMB->DataOffset = 0;
4022 pSMB->SetupCount = 1;
4023 pSMB->Reserved3 = 0;
4024 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4025 byte_count = params + 1 /* pad */ ;
4026 pSMB->TotalParameterCount = cpu_to_le16(params);
4027 pSMB->ParameterCount = pSMB->TotalParameterCount;
790fe579 4028 if (legacy)
acf1a1b1
SF
4029 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
4030 else
4031 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
1da177e4 4032 pSMB->Reserved4 = 0;
be8e3b00 4033 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4034 pSMB->ByteCount = cpu_to_le16(byte_count);
4035
4036 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4037 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4038 if (rc) {
b6b38f70 4039 cFYI(1, "Send error in QPathInfo = %d", rc);
1da177e4
LT
4040 } else { /* decode response */
4041 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4042
acf1a1b1
SF
4043 if (rc) /* BB add auto retry on EOPNOTSUPP? */
4044 rc = -EIO;
820a803f 4045 else if (!legacy && get_bcc(&pSMBr->hdr) < 40)
1da177e4 4046 rc = -EIO; /* bad smb */
820a803f 4047 else if (legacy && get_bcc(&pSMBr->hdr) < 24)
50c2f753
SF
4048 rc = -EIO; /* 24 or 26 expected but we do not read
4049 last field */
68889f26 4050 else if (data) {
acf1a1b1 4051 int size;
1da177e4 4052 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
ad7a2926 4053
68889f26
PS
4054 /*
4055 * On legacy responses we do not read the last field,
4056 * EAsize, fortunately since it varies by subdialect and
4057 * also note it differs on Set vs Get, ie two bytes or 4
4058 * bytes depending but we don't care here.
4059 */
ad7a2926 4060 if (legacy)
acf1a1b1
SF
4061 size = sizeof(FILE_INFO_STANDARD);
4062 else
4063 size = sizeof(FILE_ALL_INFO);
68889f26 4064 memcpy((char *) data, (char *) &pSMBr->hdr.Protocol +
acf1a1b1 4065 data_offset, size);
1da177e4
LT
4066 } else
4067 rc = -ENOMEM;
4068 }
4069 cifs_buf_release(pSMB);
4070 if (rc == -EAGAIN)
4071 goto QPathInfoRetry;
4072
4073 return rc;
4074}
4075
c8634fd3 4076int
6d5786a3 4077CIFSSMBUnixQFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
c8634fd3
JL
4078 u16 netfid, FILE_UNIX_BASIC_INFO *pFindData)
4079{
4080 struct smb_t2_qfi_req *pSMB = NULL;
4081 struct smb_t2_qfi_rsp *pSMBr = NULL;
4082 int rc = 0;
4083 int bytes_returned;
4084 __u16 params, byte_count;
4085
4086UnixQFileInfoRetry:
4087 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4088 (void **) &pSMBr);
4089 if (rc)
4090 return rc;
4091
4092 params = 2 /* level */ + 2 /* fid */;
4093 pSMB->t2.TotalDataCount = 0;
4094 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
4095 /* BB find exact max data count below from sess structure BB */
4096 pSMB->t2.MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
4097 pSMB->t2.MaxSetupCount = 0;
4098 pSMB->t2.Reserved = 0;
4099 pSMB->t2.Flags = 0;
4100 pSMB->t2.Timeout = 0;
4101 pSMB->t2.Reserved2 = 0;
4102 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
4103 Fid) - 4);
4104 pSMB->t2.DataCount = 0;
4105 pSMB->t2.DataOffset = 0;
4106 pSMB->t2.SetupCount = 1;
4107 pSMB->t2.Reserved3 = 0;
4108 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
4109 byte_count = params + 1 /* pad */ ;
4110 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
4111 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
4112 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4113 pSMB->Pad = 0;
4114 pSMB->Fid = netfid;
be8e3b00 4115 inc_rfc1001_len(pSMB, byte_count);
c8634fd3
JL
4116
4117 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4118 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4119 if (rc) {
f19159dc 4120 cFYI(1, "Send error in QPathInfo = %d", rc);
c8634fd3
JL
4121 } else { /* decode response */
4122 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4123
820a803f 4124 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
ac3aa2f8 4125 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
c8634fd3 4126 "Unix Extensions can be disabled on mount "
f19159dc 4127 "by specifying the nosfu mount option.");
c8634fd3
JL
4128 rc = -EIO; /* bad smb */
4129 } else {
4130 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4131 memcpy((char *) pFindData,
4132 (char *) &pSMBr->hdr.Protocol +
4133 data_offset,
4134 sizeof(FILE_UNIX_BASIC_INFO));
4135 }
4136 }
4137
4138 cifs_buf_release(pSMB);
4139 if (rc == -EAGAIN)
4140 goto UnixQFileInfoRetry;
4141
4142 return rc;
4143}
4144
1da177e4 4145int
6d5786a3 4146CIFSSMBUnixQPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
1da177e4 4147 const unsigned char *searchName,
582d21e5 4148 FILE_UNIX_BASIC_INFO *pFindData,
737b758c 4149 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4150{
4151/* SMB_QUERY_FILE_UNIX_BASIC */
4152 TRANSACTION2_QPI_REQ *pSMB = NULL;
4153 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4154 int rc = 0;
4155 int bytes_returned = 0;
4156 int name_len;
4157 __u16 params, byte_count;
4158
b6b38f70 4159 cFYI(1, "In QPathInfo (Unix) the path %s", searchName);
1da177e4
LT
4160UnixQPathInfoRetry:
4161 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4162 (void **) &pSMBr);
4163 if (rc)
4164 return rc;
4165
4166 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4167 name_len =
acbbb76a
SF
4168 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4169 PATH_MAX, nls_codepage, remap);
1da177e4
LT
4170 name_len++; /* trailing null */
4171 name_len *= 2;
50c2f753 4172 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
4173 name_len = strnlen(searchName, PATH_MAX);
4174 name_len++; /* trailing null */
4175 strncpy(pSMB->FileName, searchName, name_len);
4176 }
4177
50c2f753 4178 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
1da177e4
LT
4179 pSMB->TotalDataCount = 0;
4180 pSMB->MaxParameterCount = cpu_to_le16(2);
4181 /* BB find exact max SMB PDU from sess structure BB */
50c2f753 4182 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4183 pSMB->MaxSetupCount = 0;
4184 pSMB->Reserved = 0;
4185 pSMB->Flags = 0;
4186 pSMB->Timeout = 0;
4187 pSMB->Reserved2 = 0;
4188 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4189 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
4190 pSMB->DataCount = 0;
4191 pSMB->DataOffset = 0;
4192 pSMB->SetupCount = 1;
4193 pSMB->Reserved3 = 0;
4194 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4195 byte_count = params + 1 /* pad */ ;
4196 pSMB->TotalParameterCount = cpu_to_le16(params);
4197 pSMB->ParameterCount = pSMB->TotalParameterCount;
4198 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
4199 pSMB->Reserved4 = 0;
be8e3b00 4200 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4201 pSMB->ByteCount = cpu_to_le16(byte_count);
4202
4203 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4204 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4205 if (rc) {
b6b38f70 4206 cFYI(1, "Send error in QPathInfo = %d", rc);
1da177e4
LT
4207 } else { /* decode response */
4208 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4209
820a803f 4210 if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) {
ac3aa2f8 4211 cERROR(1, "Malformed FILE_UNIX_BASIC_INFO response. "
1e71f25d 4212 "Unix Extensions can be disabled on mount "
b6b38f70 4213 "by specifying the nosfu mount option.");
1da177e4
LT
4214 rc = -EIO; /* bad smb */
4215 } else {
4216 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4217 memcpy((char *) pFindData,
4218 (char *) &pSMBr->hdr.Protocol +
4219 data_offset,
630f3f0c 4220 sizeof(FILE_UNIX_BASIC_INFO));
1da177e4
LT
4221 }
4222 }
4223 cifs_buf_release(pSMB);
4224 if (rc == -EAGAIN)
4225 goto UnixQPathInfoRetry;
4226
4227 return rc;
4228}
4229
1da177e4
LT
4230/* xid, tcon, searchName and codepage are input parms, rest are returned */
4231int
6d5786a3 4232CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
50c2f753 4233 const char *searchName,
1da177e4 4234 const struct nls_table *nls_codepage,
2608bee7 4235 __u16 *pnetfid, __u16 search_flags,
50c2f753 4236 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
1da177e4
LT
4237{
4238/* level 257 SMB_ */
4239 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
4240 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
ad7a2926 4241 T2_FFIRST_RSP_PARMS *parms;
1da177e4
LT
4242 int rc = 0;
4243 int bytes_returned = 0;
4244 int name_len;
4245 __u16 params, byte_count;
4246
b6b38f70 4247 cFYI(1, "In FindFirst for %s", searchName);
1da177e4
LT
4248
4249findFirstRetry:
4250 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4251 (void **) &pSMBr);
4252 if (rc)
4253 return rc;
4254
4255 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4256 name_len =
acbbb76a
SF
4257 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
4258 PATH_MAX, nls_codepage, remap);
737b758c
SF
4259 /* We can not add the asterik earlier in case
4260 it got remapped to 0xF03A as if it were part of the
4261 directory name instead of a wildcard */
1da177e4 4262 name_len *= 2;
ac67055e 4263 pSMB->FileName[name_len] = dirsep;
737b758c
SF
4264 pSMB->FileName[name_len+1] = 0;
4265 pSMB->FileName[name_len+2] = '*';
4266 pSMB->FileName[name_len+3] = 0;
4267 name_len += 4; /* now the trailing null */
1da177e4
LT
4268 pSMB->FileName[name_len] = 0; /* null terminate just in case */
4269 pSMB->FileName[name_len+1] = 0;
737b758c 4270 name_len += 2;
1da177e4
LT
4271 } else { /* BB add check for overrun of SMB buf BB */
4272 name_len = strnlen(searchName, PATH_MAX);
1da177e4 4273/* BB fix here and in unicode clause above ie
790fe579 4274 if (name_len > buffersize-header)
1da177e4
LT
4275 free buffer exit; BB */
4276 strncpy(pSMB->FileName, searchName, name_len);
ac67055e 4277 pSMB->FileName[name_len] = dirsep;
68575476
SF
4278 pSMB->FileName[name_len+1] = '*';
4279 pSMB->FileName[name_len+2] = 0;
4280 name_len += 3;
1da177e4
LT
4281 }
4282
4283 params = 12 + name_len /* includes null */ ;
4284 pSMB->TotalDataCount = 0; /* no EAs */
4285 pSMB->MaxParameterCount = cpu_to_le16(10);
c974befa 4286 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
1da177e4
LT
4287 pSMB->MaxSetupCount = 0;
4288 pSMB->Reserved = 0;
4289 pSMB->Flags = 0;
4290 pSMB->Timeout = 0;
4291 pSMB->Reserved2 = 0;
4292 byte_count = params + 1 /* pad */ ;
4293 pSMB->TotalParameterCount = cpu_to_le16(params);
4294 pSMB->ParameterCount = pSMB->TotalParameterCount;
4295 pSMB->ParameterOffset = cpu_to_le16(
88274815
SF
4296 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
4297 - 4);
1da177e4
LT
4298 pSMB->DataCount = 0;
4299 pSMB->DataOffset = 0;
4300 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
4301 pSMB->Reserved3 = 0;
4302 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
4303 pSMB->SearchAttributes =
4304 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
4305 ATTR_DIRECTORY);
50c2f753 4306 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2608bee7 4307 pSMB->SearchFlags = cpu_to_le16(search_flags);
1da177e4
LT
4308 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4309
4310 /* BB what should we set StorageType to? Does it matter? BB */
4311 pSMB->SearchStorageType = 0;
be8e3b00 4312 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4313 pSMB->ByteCount = cpu_to_le16(byte_count);
4314
4315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
44c58186 4317 cifs_stats_inc(&tcon->stats.cifs_stats.num_ffirst);
1da177e4 4318
88274815
SF
4319 if (rc) {/* BB add logic to retry regular search if Unix search
4320 rejected unexpectedly by server */
1da177e4 4321 /* BB Add code to handle unsupported level rc */
b6b38f70 4322 cFYI(1, "Error in FindFirst = %d", rc);
1982c344 4323
88274815 4324 cifs_buf_release(pSMB);
1da177e4
LT
4325
4326 /* BB eventually could optimize out free and realloc of buf */
4327 /* for this case */
4328 if (rc == -EAGAIN)
4329 goto findFirstRetry;
4330 } else { /* decode response */
4331 /* BB remember to free buffer if error BB */
4332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
790fe579 4333 if (rc == 0) {
b77d753c
SF
4334 unsigned int lnoff;
4335
1da177e4 4336 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 4337 psrch_inf->unicode = true;
1da177e4 4338 else
4b18f2a9 4339 psrch_inf->unicode = false;
1da177e4
LT
4340
4341 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
d47d7c1a 4342 psrch_inf->smallBuf = 0;
50c2f753
SF
4343 psrch_inf->srch_entries_start =
4344 (char *) &pSMBr->hdr.Protocol +
1da177e4 4345 le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
4346 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
4347 le16_to_cpu(pSMBr->t2.ParameterOffset));
4348
790fe579 4349 if (parms->EndofSearch)
4b18f2a9 4350 psrch_inf->endOfSearch = true;
1da177e4 4351 else
4b18f2a9 4352 psrch_inf->endOfSearch = false;
1da177e4 4353
50c2f753
SF
4354 psrch_inf->entries_in_buffer =
4355 le16_to_cpu(parms->SearchCount);
60808233 4356 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
1da177e4 4357 psrch_inf->entries_in_buffer;
b77d753c 4358 lnoff = le16_to_cpu(parms->LastNameOffset);
c974befa 4359 if (CIFSMaxBufSize < lnoff) {
b6b38f70 4360 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
4361 psrch_inf->last_entry = NULL;
4362 return rc;
4363 }
4364
0752f152 4365 psrch_inf->last_entry = psrch_inf->srch_entries_start +
b77d753c
SF
4366 lnoff;
4367
1da177e4
LT
4368 *pnetfid = parms->SearchHandle;
4369 } else {
4370 cifs_buf_release(pSMB);
4371 }
4372 }
4373
4374 return rc;
4375}
4376
6d5786a3
PS
4377int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
4378 __u16 searchHandle, __u16 search_flags,
4379 struct cifs_search_info *psrch_inf)
1da177e4
LT
4380{
4381 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
4382 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
ad7a2926 4383 T2_FNEXT_RSP_PARMS *parms;
1da177e4
LT
4384 char *response_data;
4385 int rc = 0;
9438fabb
JL
4386 int bytes_returned;
4387 unsigned int name_len;
1da177e4
LT
4388 __u16 params, byte_count;
4389
b6b38f70 4390 cFYI(1, "In FindNext");
1da177e4 4391
4b18f2a9 4392 if (psrch_inf->endOfSearch)
1da177e4
LT
4393 return -ENOENT;
4394
4395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4396 (void **) &pSMBr);
4397 if (rc)
4398 return rc;
4399
50c2f753 4400 params = 14; /* includes 2 bytes of null string, converted to LE below*/
1da177e4
LT
4401 byte_count = 0;
4402 pSMB->TotalDataCount = 0; /* no EAs */
4403 pSMB->MaxParameterCount = cpu_to_le16(8);
c974befa 4404 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00);
1da177e4
LT
4405 pSMB->MaxSetupCount = 0;
4406 pSMB->Reserved = 0;
4407 pSMB->Flags = 0;
4408 pSMB->Timeout = 0;
4409 pSMB->Reserved2 = 0;
4410 pSMB->ParameterOffset = cpu_to_le16(
4411 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
4412 pSMB->DataCount = 0;
4413 pSMB->DataOffset = 0;
4414 pSMB->SetupCount = 1;
4415 pSMB->Reserved3 = 0;
4416 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
4417 pSMB->SearchHandle = searchHandle; /* always kept as le */
4418 pSMB->SearchCount =
630f3f0c 4419 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
1da177e4
LT
4420 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
4421 pSMB->ResumeKey = psrch_inf->resume_key;
2608bee7 4422 pSMB->SearchFlags = cpu_to_le16(search_flags);
1da177e4
LT
4423
4424 name_len = psrch_inf->resume_name_len;
4425 params += name_len;
790fe579 4426 if (name_len < PATH_MAX) {
1da177e4
LT
4427 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
4428 byte_count += name_len;
ef6724e3
SF
4429 /* 14 byte parm len above enough for 2 byte null terminator */
4430 pSMB->ResumeFileName[name_len] = 0;
4431 pSMB->ResumeFileName[name_len+1] = 0;
1da177e4
LT
4432 } else {
4433 rc = -EINVAL;
4434 goto FNext2_err_exit;
4435 }
4436 byte_count = params + 1 /* pad */ ;
4437 pSMB->TotalParameterCount = cpu_to_le16(params);
4438 pSMB->ParameterCount = pSMB->TotalParameterCount;
be8e3b00 4439 inc_rfc1001_len(pSMB, byte_count);
1da177e4 4440 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 4441
1da177e4
LT
4442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
44c58186 4444 cifs_stats_inc(&tcon->stats.cifs_stats.num_fnext);
1da177e4
LT
4445 if (rc) {
4446 if (rc == -EBADF) {
4b18f2a9 4447 psrch_inf->endOfSearch = true;
6353450a 4448 cifs_buf_release(pSMB);
50c2f753 4449 rc = 0; /* search probably was closed at end of search*/
1da177e4 4450 } else
b6b38f70 4451 cFYI(1, "FindNext returned = %d", rc);
1da177e4
LT
4452 } else { /* decode response */
4453 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
50c2f753 4454
790fe579 4455 if (rc == 0) {
b77d753c
SF
4456 unsigned int lnoff;
4457
1da177e4
LT
4458 /* BB fixme add lock for file (srch_info) struct here */
4459 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4b18f2a9 4460 psrch_inf->unicode = true;
1da177e4 4461 else
4b18f2a9 4462 psrch_inf->unicode = false;
1da177e4
LT
4463 response_data = (char *) &pSMBr->hdr.Protocol +
4464 le16_to_cpu(pSMBr->t2.ParameterOffset);
4465 parms = (T2_FNEXT_RSP_PARMS *)response_data;
4466 response_data = (char *)&pSMBr->hdr.Protocol +
4467 le16_to_cpu(pSMBr->t2.DataOffset);
790fe579 4468 if (psrch_inf->smallBuf)
d47d7c1a
SF
4469 cifs_small_buf_release(
4470 psrch_inf->ntwrk_buf_start);
4471 else
4472 cifs_buf_release(psrch_inf->ntwrk_buf_start);
1da177e4
LT
4473 psrch_inf->srch_entries_start = response_data;
4474 psrch_inf->ntwrk_buf_start = (char *)pSMB;
d47d7c1a 4475 psrch_inf->smallBuf = 0;
790fe579 4476 if (parms->EndofSearch)
4b18f2a9 4477 psrch_inf->endOfSearch = true;
1da177e4 4478 else
4b18f2a9 4479 psrch_inf->endOfSearch = false;
50c2f753
SF
4480 psrch_inf->entries_in_buffer =
4481 le16_to_cpu(parms->SearchCount);
1da177e4
LT
4482 psrch_inf->index_of_last_entry +=
4483 psrch_inf->entries_in_buffer;
b77d753c 4484 lnoff = le16_to_cpu(parms->LastNameOffset);
c974befa 4485 if (CIFSMaxBufSize < lnoff) {
b6b38f70 4486 cERROR(1, "ignoring corrupt resume name");
b77d753c
SF
4487 psrch_inf->last_entry = NULL;
4488 return rc;
4489 } else
4490 psrch_inf->last_entry =
4491 psrch_inf->srch_entries_start + lnoff;
4492
b6b38f70
JP
4493/* cFYI(1, "fnxt2 entries in buf %d index_of_last %d",
4494 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry); */
1da177e4
LT
4495
4496 /* BB fixme add unlock here */
4497 }
4498
4499 }
4500
4501 /* BB On error, should we leave previous search buf (and count and
4502 last entry fields) intact or free the previous one? */
4503
4504 /* Note: On -EAGAIN error only caller can retry on handle based calls
4505 since file handle passed in no longer valid */
4506FNext2_err_exit:
4507 if (rc != 0)
4508 cifs_buf_release(pSMB);
1da177e4
LT
4509 return rc;
4510}
4511
4512int
6d5786a3 4513CIFSFindClose(const unsigned int xid, struct cifs_tcon *tcon,
50c2f753 4514 const __u16 searchHandle)
1da177e4
LT
4515{
4516 int rc = 0;
4517 FINDCLOSE_REQ *pSMB = NULL;
1da177e4 4518
b6b38f70 4519 cFYI(1, "In CIFSSMBFindClose");
1da177e4
LT
4520 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
4521
4522 /* no sense returning error if session restarted
4523 as file handle has been closed */
790fe579 4524 if (rc == -EAGAIN)
1da177e4
LT
4525 return 0;
4526 if (rc)
4527 return rc;
4528
1da177e4
LT
4529 pSMB->FileID = searchHandle;
4530 pSMB->ByteCount = 0;
792af7b0 4531 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
ad7a2926 4532 if (rc)
b6b38f70 4533 cERROR(1, "Send error in FindClose = %d", rc);
ad7a2926 4534
44c58186 4535 cifs_stats_inc(&tcon->stats.cifs_stats.num_fclose);
1da177e4
LT
4536
4537 /* Since session is dead, search handle closed on server already */
4538 if (rc == -EAGAIN)
4539 rc = 0;
4540
4541 return rc;
4542}
4543
1da177e4 4544int
6d5786a3 4545CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
1208ef1f 4546 const char *search_name, __u64 *inode_number,
50c2f753 4547 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4548{
4549 int rc = 0;
4550 TRANSACTION2_QPI_REQ *pSMB = NULL;
4551 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4552 int name_len, bytes_returned;
4553 __u16 params, byte_count;
4554
1208ef1f 4555 cFYI(1, "In GetSrvInodeNum for %s", search_name);
790fe579 4556 if (tcon == NULL)
50c2f753 4557 return -ENODEV;
1da177e4
LT
4558
4559GetInodeNumberRetry:
4560 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
50c2f753 4561 (void **) &pSMBr);
1da177e4
LT
4562 if (rc)
4563 return rc;
4564
1da177e4
LT
4565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4566 name_len =
acbbb76a 4567 cifsConvertToUTF16((__le16 *) pSMB->FileName,
1208ef1f 4568 search_name, PATH_MAX, nls_codepage,
acbbb76a 4569 remap);
1da177e4
LT
4570 name_len++; /* trailing null */
4571 name_len *= 2;
50c2f753 4572 } else { /* BB improve the check for buffer overruns BB */
1208ef1f 4573 name_len = strnlen(search_name, PATH_MAX);
1da177e4 4574 name_len++; /* trailing null */
1208ef1f 4575 strncpy(pSMB->FileName, search_name, name_len);
1da177e4
LT
4576 }
4577
4578 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
4579 pSMB->TotalDataCount = 0;
4580 pSMB->MaxParameterCount = cpu_to_le16(2);
4581 /* BB find exact max data count below from sess structure BB */
4582 pSMB->MaxDataCount = cpu_to_le16(4000);
4583 pSMB->MaxSetupCount = 0;
4584 pSMB->Reserved = 0;
4585 pSMB->Flags = 0;
4586 pSMB->Timeout = 0;
4587 pSMB->Reserved2 = 0;
4588 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4589 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
4590 pSMB->DataCount = 0;
4591 pSMB->DataOffset = 0;
4592 pSMB->SetupCount = 1;
4593 pSMB->Reserved3 = 0;
4594 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4595 byte_count = params + 1 /* pad */ ;
4596 pSMB->TotalParameterCount = cpu_to_le16(params);
4597 pSMB->ParameterCount = pSMB->TotalParameterCount;
4598 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
4599 pSMB->Reserved4 = 0;
be8e3b00 4600 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4601 pSMB->ByteCount = cpu_to_le16(byte_count);
4602
4603 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4604 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4605 if (rc) {
b6b38f70 4606 cFYI(1, "error %d in QueryInternalInfo", rc);
1da177e4
LT
4607 } else {
4608 /* decode response */
4609 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4610 /* BB also check enough total bytes returned */
820a803f 4611 if (rc || get_bcc(&pSMBr->hdr) < 2)
1da177e4
LT
4612 /* If rc should we check for EOPNOSUPP and
4613 disable the srvino flag? or in caller? */
4614 rc = -EIO; /* bad smb */
50c2f753 4615 else {
1da177e4
LT
4616 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4617 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
50c2f753 4618 struct file_internal_info *pfinfo;
1da177e4 4619 /* BB Do we need a cast or hash here ? */
790fe579 4620 if (count < 8) {
b6b38f70 4621 cFYI(1, "Illegal size ret in QryIntrnlInf");
1da177e4
LT
4622 rc = -EIO;
4623 goto GetInodeNumOut;
4624 }
4625 pfinfo = (struct file_internal_info *)
4626 (data_offset + (char *) &pSMBr->hdr.Protocol);
85a6dac5 4627 *inode_number = le64_to_cpu(pfinfo->UniqueId);
1da177e4
LT
4628 }
4629 }
4630GetInodeNumOut:
4631 cifs_buf_release(pSMB);
4632 if (rc == -EAGAIN)
4633 goto GetInodeNumberRetry;
4634 return rc;
4635}
1da177e4 4636
fec4585f
IM
4637/* parses DFS refferal V3 structure
4638 * caller is responsible for freeing target_nodes
4639 * returns:
4640 * on success - 0
4641 * on failure - errno
4642 */
4643static int
a1fe78f1 4644parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
fec4585f
IM
4645 unsigned int *num_of_nodes,
4646 struct dfs_info3_param **target_nodes,
2c55608f
IM
4647 const struct nls_table *nls_codepage, int remap,
4648 const char *searchName)
fec4585f
IM
4649{
4650 int i, rc = 0;
4651 char *data_end;
4652 bool is_unicode;
4653 struct dfs_referral_level_3 *ref;
4654
5ca33c6a
HH
4655 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
4656 is_unicode = true;
4657 else
4658 is_unicode = false;
fec4585f
IM
4659 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
4660
4661 if (*num_of_nodes < 1) {
b6b38f70 4662 cERROR(1, "num_referrals: must be at least > 0,"
ac3aa2f8 4663 "but we get num_referrals = %d", *num_of_nodes);
fec4585f 4664 rc = -EINVAL;
a1fe78f1 4665 goto parse_DFS_referrals_exit;
fec4585f
IM
4666 }
4667
4668 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
1d92cfd5 4669 if (ref->VersionNumber != cpu_to_le16(3)) {
b6b38f70
JP
4670 cERROR(1, "Referrals of V%d version are not supported,"
4671 "should be V3", le16_to_cpu(ref->VersionNumber));
fec4585f 4672 rc = -EINVAL;
a1fe78f1 4673 goto parse_DFS_referrals_exit;
fec4585f
IM
4674 }
4675
4676 /* get the upper boundary of the resp buffer */
4677 data_end = (char *)(&(pSMBr->PathConsumed)) +
4678 le16_to_cpu(pSMBr->t2.DataCount);
4679
ac3aa2f8 4680 cFYI(1, "num_referrals: %d dfs flags: 0x%x ...",
fec4585f 4681 *num_of_nodes,
b6b38f70 4682 le32_to_cpu(pSMBr->DFSFlags));
fec4585f
IM
4683
4684 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
4685 *num_of_nodes, GFP_KERNEL);
4686 if (*target_nodes == NULL) {
ac3aa2f8 4687 cERROR(1, "Failed to allocate buffer for target_nodes");
fec4585f 4688 rc = -ENOMEM;
a1fe78f1 4689 goto parse_DFS_referrals_exit;
fec4585f
IM
4690 }
4691
3ad2f3fb 4692 /* collect necessary data from referrals */
fec4585f
IM
4693 for (i = 0; i < *num_of_nodes; i++) {
4694 char *temp;
4695 int max_len;
4696 struct dfs_info3_param *node = (*target_nodes)+i;
4697
0e0d2cf3 4698 node->flags = le32_to_cpu(pSMBr->DFSFlags);
2c55608f 4699 if (is_unicode) {
331c3135
JL
4700 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
4701 GFP_KERNEL);
2920ee2b
SF
4702 if (tmp == NULL) {
4703 rc = -ENOMEM;
4704 goto parse_DFS_referrals_exit;
4705 }
acbbb76a
SF
4706 cifsConvertToUTF16((__le16 *) tmp, searchName,
4707 PATH_MAX, nls_codepage, remap);
4708 node->path_consumed = cifs_utf16_bytes(tmp,
69f801fc 4709 le16_to_cpu(pSMBr->PathConsumed),
2c55608f
IM
4710 nls_codepage);
4711 kfree(tmp);
4712 } else
4713 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
4714
fec4585f
IM
4715 node->server_type = le16_to_cpu(ref->ServerType);
4716 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
4717
4718 /* copy DfsPath */
4719 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
4720 max_len = data_end - temp;
acbbb76a
SF
4721 node->path_name = cifs_strndup_from_utf16(temp, max_len,
4722 is_unicode, nls_codepage);
d8e2f53a
JL
4723 if (!node->path_name) {
4724 rc = -ENOMEM;
a1fe78f1 4725 goto parse_DFS_referrals_exit;
066ce689 4726 }
fec4585f
IM
4727
4728 /* copy link target UNC */
4729 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
4730 max_len = data_end - temp;
acbbb76a
SF
4731 node->node_name = cifs_strndup_from_utf16(temp, max_len,
4732 is_unicode, nls_codepage);
d8f2799b 4733 if (!node->node_name) {
d8e2f53a 4734 rc = -ENOMEM;
d8f2799b
SM
4735 goto parse_DFS_referrals_exit;
4736 }
4737
4738 ref++;
fec4585f
IM
4739 }
4740
a1fe78f1 4741parse_DFS_referrals_exit:
fec4585f
IM
4742 if (rc) {
4743 free_dfs_info_array(*target_nodes, *num_of_nodes);
4744 *target_nodes = NULL;
4745 *num_of_nodes = 0;
4746 }
4747 return rc;
4748}
4749
1da177e4 4750int
6d5786a3 4751CIFSGetDFSRefer(const unsigned int xid, struct cifs_ses *ses,
b669f33c 4752 const char *search_name, struct dfs_info3_param **target_nodes,
c2cf07d5 4753 unsigned int *num_of_nodes,
737b758c 4754 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
4755{
4756/* TRANS2_GET_DFS_REFERRAL */
4757 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
4758 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
1da177e4
LT
4759 int rc = 0;
4760 int bytes_returned;
4761 int name_len;
1da177e4 4762 __u16 params, byte_count;
c2cf07d5
SF
4763 *num_of_nodes = 0;
4764 *target_nodes = NULL;
1da177e4 4765
b669f33c 4766 cFYI(1, "In GetDFSRefer the path %s", search_name);
1da177e4
LT
4767 if (ses == NULL)
4768 return -ENODEV;
4769getDFSRetry:
4770 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
4771 (void **) &pSMBr);
4772 if (rc)
4773 return rc;
50c2f753
SF
4774
4775 /* server pointer checked in called function,
1982c344 4776 but should never be null here anyway */
88257360 4777 pSMB->hdr.Mid = get_next_mid(ses->server);
1da177e4
LT
4778 pSMB->hdr.Tid = ses->ipc_tid;
4779 pSMB->hdr.Uid = ses->Suid;
26f57364 4780 if (ses->capabilities & CAP_STATUS32)
1da177e4 4781 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
26f57364 4782 if (ses->capabilities & CAP_DFS)
1da177e4 4783 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
1da177e4
LT
4784
4785 if (ses->capabilities & CAP_UNICODE) {
4786 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
4787 name_len =
acbbb76a 4788 cifsConvertToUTF16((__le16 *) pSMB->RequestFileName,
b669f33c 4789 search_name, PATH_MAX, nls_codepage,
acbbb76a 4790 remap);
1da177e4
LT
4791 name_len++; /* trailing null */
4792 name_len *= 2;
50c2f753 4793 } else { /* BB improve the check for buffer overruns BB */
b669f33c 4794 name_len = strnlen(search_name, PATH_MAX);
1da177e4 4795 name_len++; /* trailing null */
b669f33c 4796 strncpy(pSMB->RequestFileName, search_name, name_len);
1da177e4
LT
4797 }
4798
790fe579 4799 if (ses->server) {
96daf2b0 4800 if (ses->server->sec_mode &
1a4e15a0
SF
4801 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
4802 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4803 }
4804
50c2f753 4805 pSMB->hdr.Uid = ses->Suid;
1a4e15a0 4806
1da177e4
LT
4807 params = 2 /* level */ + name_len /*includes null */ ;
4808 pSMB->TotalDataCount = 0;
4809 pSMB->DataCount = 0;
4810 pSMB->DataOffset = 0;
4811 pSMB->MaxParameterCount = 0;
582d21e5
SF
4812 /* BB find exact max SMB PDU from sess structure BB */
4813 pSMB->MaxDataCount = cpu_to_le16(4000);
1da177e4
LT
4814 pSMB->MaxSetupCount = 0;
4815 pSMB->Reserved = 0;
4816 pSMB->Flags = 0;
4817 pSMB->Timeout = 0;
4818 pSMB->Reserved2 = 0;
4819 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4820 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
1da177e4
LT
4821 pSMB->SetupCount = 1;
4822 pSMB->Reserved3 = 0;
4823 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4824 byte_count = params + 3 /* pad */ ;
4825 pSMB->ParameterCount = cpu_to_le16(params);
4826 pSMB->TotalParameterCount = pSMB->ParameterCount;
4827 pSMB->MaxReferralLevel = cpu_to_le16(3);
be8e3b00 4828 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4829 pSMB->ByteCount = cpu_to_le16(byte_count);
4830
4831 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4833 if (rc) {
b6b38f70 4834 cFYI(1, "Send error in GetDFSRefer = %d", rc);
c2cf07d5
SF
4835 goto GetDFSRefExit;
4836 }
4837 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4838
c2cf07d5 4839 /* BB Also check if enough total bytes returned? */
820a803f 4840 if (rc || get_bcc(&pSMBr->hdr) < 17) {
c2cf07d5 4841 rc = -EIO; /* bad smb */
fec4585f
IM
4842 goto GetDFSRefExit;
4843 }
c2cf07d5 4844
b6b38f70 4845 cFYI(1, "Decoding GetDFSRefer response BCC: %d Offset %d",
820a803f 4846 get_bcc(&pSMBr->hdr),
b6b38f70 4847 le16_to_cpu(pSMBr->t2.DataOffset));
1da177e4 4848
fec4585f 4849 /* parse returned result into more usable form */
a1fe78f1 4850 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
2c55608f 4851 target_nodes, nls_codepage, remap,
b669f33c 4852 search_name);
c2cf07d5 4853
1da177e4 4854GetDFSRefExit:
0d817bc0 4855 cifs_buf_release(pSMB);
1da177e4
LT
4856
4857 if (rc == -EAGAIN)
4858 goto getDFSRetry;
4859
4860 return rc;
4861}
4862
20962438
SF
4863/* Query File System Info such as free space to old servers such as Win 9x */
4864int
6d5786a3
PS
4865SMBOldQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4866 struct kstatfs *FSData)
20962438
SF
4867{
4868/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4869 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4870 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4871 FILE_SYSTEM_ALLOC_INFO *response_data;
4872 int rc = 0;
4873 int bytes_returned = 0;
4874 __u16 params, byte_count;
4875
b6b38f70 4876 cFYI(1, "OldQFSInfo");
20962438
SF
4877oldQFSInfoRetry:
4878 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4879 (void **) &pSMBr);
4880 if (rc)
4881 return rc;
20962438
SF
4882
4883 params = 2; /* level */
4884 pSMB->TotalDataCount = 0;
4885 pSMB->MaxParameterCount = cpu_to_le16(2);
4886 pSMB->MaxDataCount = cpu_to_le16(1000);
4887 pSMB->MaxSetupCount = 0;
4888 pSMB->Reserved = 0;
4889 pSMB->Flags = 0;
4890 pSMB->Timeout = 0;
4891 pSMB->Reserved2 = 0;
4892 byte_count = params + 1 /* pad */ ;
4893 pSMB->TotalParameterCount = cpu_to_le16(params);
4894 pSMB->ParameterCount = pSMB->TotalParameterCount;
4895 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4896 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4897 pSMB->DataCount = 0;
4898 pSMB->DataOffset = 0;
4899 pSMB->SetupCount = 1;
4900 pSMB->Reserved3 = 0;
4901 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4902 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
be8e3b00 4903 inc_rfc1001_len(pSMB, byte_count);
20962438
SF
4904 pSMB->ByteCount = cpu_to_le16(byte_count);
4905
4906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4908 if (rc) {
b6b38f70 4909 cFYI(1, "Send error in QFSInfo = %d", rc);
20962438
SF
4910 } else { /* decode response */
4911 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4912
820a803f 4913 if (rc || get_bcc(&pSMBr->hdr) < 18)
20962438
SF
4914 rc = -EIO; /* bad smb */
4915 else {
4916 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
b6b38f70 4917 cFYI(1, "qfsinf resp BCC: %d Offset %d",
820a803f 4918 get_bcc(&pSMBr->hdr), data_offset);
20962438 4919
50c2f753 4920 response_data = (FILE_SYSTEM_ALLOC_INFO *)
20962438
SF
4921 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4922 FSData->f_bsize =
4923 le16_to_cpu(response_data->BytesPerSector) *
4924 le32_to_cpu(response_data->
4925 SectorsPerAllocationUnit);
4926 FSData->f_blocks =
50c2f753 4927 le32_to_cpu(response_data->TotalAllocationUnits);
20962438
SF
4928 FSData->f_bfree = FSData->f_bavail =
4929 le32_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
4930 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
4931 (unsigned long long)FSData->f_blocks,
4932 (unsigned long long)FSData->f_bfree,
4933 FSData->f_bsize);
20962438
SF
4934 }
4935 }
4936 cifs_buf_release(pSMB);
4937
4938 if (rc == -EAGAIN)
4939 goto oldQFSInfoRetry;
4940
4941 return rc;
4942}
4943
1da177e4 4944int
6d5786a3
PS
4945CIFSSMBQFSInfo(const unsigned int xid, struct cifs_tcon *tcon,
4946 struct kstatfs *FSData)
1da177e4
LT
4947{
4948/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4949 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4950 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4951 FILE_SYSTEM_INFO *response_data;
4952 int rc = 0;
4953 int bytes_returned = 0;
4954 __u16 params, byte_count;
4955
b6b38f70 4956 cFYI(1, "In QFSInfo");
1da177e4
LT
4957QFSInfoRetry:
4958 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4959 (void **) &pSMBr);
4960 if (rc)
4961 return rc;
4962
4963 params = 2; /* level */
4964 pSMB->TotalDataCount = 0;
4965 pSMB->MaxParameterCount = cpu_to_le16(2);
20962438 4966 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
4967 pSMB->MaxSetupCount = 0;
4968 pSMB->Reserved = 0;
4969 pSMB->Flags = 0;
4970 pSMB->Timeout = 0;
4971 pSMB->Reserved2 = 0;
4972 byte_count = params + 1 /* pad */ ;
4973 pSMB->TotalParameterCount = cpu_to_le16(params);
4974 pSMB->ParameterCount = pSMB->TotalParameterCount;
4975 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 4976 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
4977 pSMB->DataCount = 0;
4978 pSMB->DataOffset = 0;
4979 pSMB->SetupCount = 1;
4980 pSMB->Reserved3 = 0;
4981 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4982 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
be8e3b00 4983 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
4984 pSMB->ByteCount = cpu_to_le16(byte_count);
4985
4986 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4987 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4988 if (rc) {
b6b38f70 4989 cFYI(1, "Send error in QFSInfo = %d", rc);
1da177e4 4990 } else { /* decode response */
50c2f753 4991 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1da177e4 4992
820a803f 4993 if (rc || get_bcc(&pSMBr->hdr) < 24)
1da177e4
LT
4994 rc = -EIO; /* bad smb */
4995 else {
4996 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1da177e4
LT
4997
4998 response_data =
4999 (FILE_SYSTEM_INFO
5000 *) (((char *) &pSMBr->hdr.Protocol) +
5001 data_offset);
5002 FSData->f_bsize =
5003 le32_to_cpu(response_data->BytesPerSector) *
5004 le32_to_cpu(response_data->
5005 SectorsPerAllocationUnit);
5006 FSData->f_blocks =
5007 le64_to_cpu(response_data->TotalAllocationUnits);
5008 FSData->f_bfree = FSData->f_bavail =
5009 le64_to_cpu(response_data->FreeAllocationUnits);
b6b38f70
JP
5010 cFYI(1, "Blocks: %lld Free: %lld Block size %ld",
5011 (unsigned long long)FSData->f_blocks,
5012 (unsigned long long)FSData->f_bfree,
5013 FSData->f_bsize);
1da177e4
LT
5014 }
5015 }
5016 cifs_buf_release(pSMB);
5017
5018 if (rc == -EAGAIN)
5019 goto QFSInfoRetry;
5020
5021 return rc;
5022}
5023
5024int
6d5786a3 5025CIFSSMBQFSAttributeInfo(const unsigned int xid, struct cifs_tcon *tcon)
1da177e4
LT
5026{
5027/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
5028 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5029 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5030 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
5031 int rc = 0;
5032 int bytes_returned = 0;
5033 __u16 params, byte_count;
5034
b6b38f70 5035 cFYI(1, "In QFSAttributeInfo");
1da177e4
LT
5036QFSAttributeRetry:
5037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5038 (void **) &pSMBr);
5039 if (rc)
5040 return rc;
5041
5042 params = 2; /* level */
5043 pSMB->TotalDataCount = 0;
5044 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5045 /* BB find exact max SMB PDU from sess structure BB */
5046 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5047 pSMB->MaxSetupCount = 0;
5048 pSMB->Reserved = 0;
5049 pSMB->Flags = 0;
5050 pSMB->Timeout = 0;
5051 pSMB->Reserved2 = 0;
5052 byte_count = params + 1 /* pad */ ;
5053 pSMB->TotalParameterCount = cpu_to_le16(params);
5054 pSMB->ParameterCount = pSMB->TotalParameterCount;
5055 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5056 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5057 pSMB->DataCount = 0;
5058 pSMB->DataOffset = 0;
5059 pSMB->SetupCount = 1;
5060 pSMB->Reserved3 = 0;
5061 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5062 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
be8e3b00 5063 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5064 pSMB->ByteCount = cpu_to_le16(byte_count);
5065
5066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5068 if (rc) {
b6b38f70 5069 cERROR(1, "Send error in QFSAttributeInfo = %d", rc);
1da177e4
LT
5070 } else { /* decode response */
5071 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5072
820a803f 5073 if (rc || get_bcc(&pSMBr->hdr) < 13) {
50c2f753 5074 /* BB also check if enough bytes returned */
1da177e4
LT
5075 rc = -EIO; /* bad smb */
5076 } else {
5077 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5078 response_data =
5079 (FILE_SYSTEM_ATTRIBUTE_INFO
5080 *) (((char *) &pSMBr->hdr.Protocol) +
5081 data_offset);
5082 memcpy(&tcon->fsAttrInfo, response_data,
26f57364 5083 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
1da177e4
LT
5084 }
5085 }
5086 cifs_buf_release(pSMB);
5087
5088 if (rc == -EAGAIN)
5089 goto QFSAttributeRetry;
5090
5091 return rc;
5092}
5093
5094int
6d5786a3 5095CIFSSMBQFSDeviceInfo(const unsigned int xid, struct cifs_tcon *tcon)
1da177e4
LT
5096{
5097/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
5098 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5099 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5100 FILE_SYSTEM_DEVICE_INFO *response_data;
5101 int rc = 0;
5102 int bytes_returned = 0;
5103 __u16 params, byte_count;
5104
b6b38f70 5105 cFYI(1, "In QFSDeviceInfo");
1da177e4
LT
5106QFSDeviceRetry:
5107 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5108 (void **) &pSMBr);
5109 if (rc)
5110 return rc;
5111
5112 params = 2; /* level */
5113 pSMB->TotalDataCount = 0;
5114 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5115 /* BB find exact max SMB PDU from sess structure BB */
5116 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5117 pSMB->MaxSetupCount = 0;
5118 pSMB->Reserved = 0;
5119 pSMB->Flags = 0;
5120 pSMB->Timeout = 0;
5121 pSMB->Reserved2 = 0;
5122 byte_count = params + 1 /* pad */ ;
5123 pSMB->TotalParameterCount = cpu_to_le16(params);
5124 pSMB->ParameterCount = pSMB->TotalParameterCount;
5125 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 5126 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5127
5128 pSMB->DataCount = 0;
5129 pSMB->DataOffset = 0;
5130 pSMB->SetupCount = 1;
5131 pSMB->Reserved3 = 0;
5132 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5133 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
be8e3b00 5134 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5135 pSMB->ByteCount = cpu_to_le16(byte_count);
5136
5137 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5138 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5139 if (rc) {
b6b38f70 5140 cFYI(1, "Send error in QFSDeviceInfo = %d", rc);
1da177e4
LT
5141 } else { /* decode response */
5142 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5143
820a803f
JL
5144 if (rc || get_bcc(&pSMBr->hdr) <
5145 sizeof(FILE_SYSTEM_DEVICE_INFO))
1da177e4
LT
5146 rc = -EIO; /* bad smb */
5147 else {
5148 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5149 response_data =
737b758c
SF
5150 (FILE_SYSTEM_DEVICE_INFO *)
5151 (((char *) &pSMBr->hdr.Protocol) +
1da177e4
LT
5152 data_offset);
5153 memcpy(&tcon->fsDevInfo, response_data,
26f57364 5154 sizeof(FILE_SYSTEM_DEVICE_INFO));
1da177e4
LT
5155 }
5156 }
5157 cifs_buf_release(pSMB);
5158
5159 if (rc == -EAGAIN)
5160 goto QFSDeviceRetry;
5161
5162 return rc;
5163}
5164
5165int
6d5786a3 5166CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon)
1da177e4
LT
5167{
5168/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
5169 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5170 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5171 FILE_SYSTEM_UNIX_INFO *response_data;
5172 int rc = 0;
5173 int bytes_returned = 0;
5174 __u16 params, byte_count;
5175
b6b38f70 5176 cFYI(1, "In QFSUnixInfo");
1da177e4 5177QFSUnixRetry:
f569599a
JL
5178 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5179 (void **) &pSMB, (void **) &pSMBr);
1da177e4
LT
5180 if (rc)
5181 return rc;
5182
5183 params = 2; /* level */
5184 pSMB->TotalDataCount = 0;
5185 pSMB->DataCount = 0;
5186 pSMB->DataOffset = 0;
5187 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5188 /* BB find exact max SMB PDU from sess structure BB */
5189 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
5190 pSMB->MaxSetupCount = 0;
5191 pSMB->Reserved = 0;
5192 pSMB->Flags = 0;
5193 pSMB->Timeout = 0;
5194 pSMB->Reserved2 = 0;
5195 byte_count = params + 1 /* pad */ ;
5196 pSMB->ParameterCount = cpu_to_le16(params);
5197 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
5198 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5199 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5200 pSMB->SetupCount = 1;
5201 pSMB->Reserved3 = 0;
5202 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5203 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
be8e3b00 5204 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5205 pSMB->ByteCount = cpu_to_le16(byte_count);
5206
5207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5209 if (rc) {
b6b38f70 5210 cERROR(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
5211 } else { /* decode response */
5212 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5213
820a803f 5214 if (rc || get_bcc(&pSMBr->hdr) < 13) {
1da177e4
LT
5215 rc = -EIO; /* bad smb */
5216 } else {
5217 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5218 response_data =
5219 (FILE_SYSTEM_UNIX_INFO
5220 *) (((char *) &pSMBr->hdr.Protocol) +
5221 data_offset);
5222 memcpy(&tcon->fsUnixInfo, response_data,
26f57364 5223 sizeof(FILE_SYSTEM_UNIX_INFO));
1da177e4
LT
5224 }
5225 }
5226 cifs_buf_release(pSMB);
5227
5228 if (rc == -EAGAIN)
5229 goto QFSUnixRetry;
5230
5231
5232 return rc;
5233}
5234
ac67055e 5235int
6d5786a3 5236CIFSSMBSetFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon, __u64 cap)
ac67055e
JA
5237{
5238/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
5239 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
5240 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
5241 int rc = 0;
5242 int bytes_returned = 0;
5243 __u16 params, param_offset, offset, byte_count;
5244
b6b38f70 5245 cFYI(1, "In SETFSUnixInfo");
ac67055e 5246SETFSUnixRetry:
f26282c9 5247 /* BB switch to small buf init to save memory */
f569599a
JL
5248 rc = smb_init_no_reconnect(SMB_COM_TRANSACTION2, 15, tcon,
5249 (void **) &pSMB, (void **) &pSMBr);
ac67055e
JA
5250 if (rc)
5251 return rc;
5252
5253 params = 4; /* 2 bytes zero followed by info level. */
5254 pSMB->MaxSetupCount = 0;
5255 pSMB->Reserved = 0;
5256 pSMB->Flags = 0;
5257 pSMB->Timeout = 0;
5258 pSMB->Reserved2 = 0;
50c2f753
SF
5259 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
5260 - 4;
ac67055e
JA
5261 offset = param_offset + params;
5262
5263 pSMB->MaxParameterCount = cpu_to_le16(4);
582d21e5
SF
5264 /* BB find exact max SMB PDU from sess structure BB */
5265 pSMB->MaxDataCount = cpu_to_le16(100);
ac67055e
JA
5266 pSMB->SetupCount = 1;
5267 pSMB->Reserved3 = 0;
5268 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
5269 byte_count = 1 /* pad */ + params + 12;
5270
5271 pSMB->DataCount = cpu_to_le16(12);
5272 pSMB->ParameterCount = cpu_to_le16(params);
5273 pSMB->TotalDataCount = pSMB->DataCount;
5274 pSMB->TotalParameterCount = pSMB->ParameterCount;
5275 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5276 pSMB->DataOffset = cpu_to_le16(offset);
5277
5278 /* Params. */
5279 pSMB->FileNum = 0;
5280 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
5281
5282 /* Data. */
5283 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
5284 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
5285 pSMB->ClientUnixCap = cpu_to_le64(cap);
5286
be8e3b00 5287 inc_rfc1001_len(pSMB, byte_count);
ac67055e
JA
5288 pSMB->ByteCount = cpu_to_le16(byte_count);
5289
5290 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5291 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5292 if (rc) {
b6b38f70 5293 cERROR(1, "Send error in SETFSUnixInfo = %d", rc);
ac67055e
JA
5294 } else { /* decode response */
5295 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
ad7a2926 5296 if (rc)
ac67055e 5297 rc = -EIO; /* bad smb */
ac67055e
JA
5298 }
5299 cifs_buf_release(pSMB);
5300
5301 if (rc == -EAGAIN)
5302 goto SETFSUnixRetry;
5303
5304 return rc;
5305}
5306
5307
1da177e4
LT
5308
5309int
6d5786a3 5310CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
737b758c 5311 struct kstatfs *FSData)
1da177e4
LT
5312{
5313/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
5314 TRANSACTION2_QFSI_REQ *pSMB = NULL;
5315 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
5316 FILE_SYSTEM_POSIX_INFO *response_data;
5317 int rc = 0;
5318 int bytes_returned = 0;
5319 __u16 params, byte_count;
5320
b6b38f70 5321 cFYI(1, "In QFSPosixInfo");
1da177e4
LT
5322QFSPosixRetry:
5323 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5324 (void **) &pSMBr);
5325 if (rc)
5326 return rc;
5327
5328 params = 2; /* level */
5329 pSMB->TotalDataCount = 0;
5330 pSMB->DataCount = 0;
5331 pSMB->DataOffset = 0;
5332 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5333 /* BB find exact max SMB PDU from sess structure BB */
5334 pSMB->MaxDataCount = cpu_to_le16(100);
1da177e4
LT
5335 pSMB->MaxSetupCount = 0;
5336 pSMB->Reserved = 0;
5337 pSMB->Flags = 0;
5338 pSMB->Timeout = 0;
5339 pSMB->Reserved2 = 0;
5340 byte_count = params + 1 /* pad */ ;
5341 pSMB->ParameterCount = cpu_to_le16(params);
5342 pSMB->TotalParameterCount = pSMB->ParameterCount;
50c2f753
SF
5343 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
5344 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
1da177e4
LT
5345 pSMB->SetupCount = 1;
5346 pSMB->Reserved3 = 0;
5347 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
5348 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
be8e3b00 5349 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5350 pSMB->ByteCount = cpu_to_le16(byte_count);
5351
5352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5354 if (rc) {
b6b38f70 5355 cFYI(1, "Send error in QFSUnixInfo = %d", rc);
1da177e4
LT
5356 } else { /* decode response */
5357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5358
820a803f 5359 if (rc || get_bcc(&pSMBr->hdr) < 13) {
1da177e4
LT
5360 rc = -EIO; /* bad smb */
5361 } else {
5362 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5363 response_data =
5364 (FILE_SYSTEM_POSIX_INFO
5365 *) (((char *) &pSMBr->hdr.Protocol) +
5366 data_offset);
5367 FSData->f_bsize =
5368 le32_to_cpu(response_data->BlockSize);
5369 FSData->f_blocks =
5370 le64_to_cpu(response_data->TotalBlocks);
5371 FSData->f_bfree =
5372 le64_to_cpu(response_data->BlocksAvail);
790fe579 5373 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
1da177e4
LT
5374 FSData->f_bavail = FSData->f_bfree;
5375 } else {
5376 FSData->f_bavail =
50c2f753 5377 le64_to_cpu(response_data->UserBlocksAvail);
1da177e4 5378 }
790fe579 5379 if (response_data->TotalFileNodes != cpu_to_le64(-1))
1da177e4 5380 FSData->f_files =
50c2f753 5381 le64_to_cpu(response_data->TotalFileNodes);
790fe579 5382 if (response_data->FreeFileNodes != cpu_to_le64(-1))
1da177e4 5383 FSData->f_ffree =
50c2f753 5384 le64_to_cpu(response_data->FreeFileNodes);
1da177e4
LT
5385 }
5386 }
5387 cifs_buf_release(pSMB);
5388
5389 if (rc == -EAGAIN)
5390 goto QFSPosixRetry;
5391
5392 return rc;
5393}
5394
5395
50c2f753
SF
5396/* We can not use write of zero bytes trick to
5397 set file size due to need for large file support. Also note that
5398 this SetPathInfo is preferred to SetFileInfo based method in next
1da177e4
LT
5399 routine which is only needed to work around a sharing violation bug
5400 in Samba which this routine can run into */
5401
5402int
6d5786a3
PS
5403CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
5404 const char *fileName, __u64 size, bool SetAllocation,
737b758c 5405 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5406{
5407 struct smb_com_transaction2_spi_req *pSMB = NULL;
5408 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5409 struct file_end_of_file_info *parm_data;
5410 int name_len;
5411 int rc = 0;
5412 int bytes_returned = 0;
5413 __u16 params, byte_count, data_count, param_offset, offset;
5414
b6b38f70 5415 cFYI(1, "In SetEOF");
1da177e4
LT
5416SetEOFRetry:
5417 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5418 (void **) &pSMBr);
5419 if (rc)
5420 return rc;
5421
5422 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5423 name_len =
acbbb76a
SF
5424 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5425 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5426 name_len++; /* trailing null */
5427 name_len *= 2;
3e87d803 5428 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5429 name_len = strnlen(fileName, PATH_MAX);
5430 name_len++; /* trailing null */
5431 strncpy(pSMB->FileName, fileName, name_len);
5432 }
5433 params = 6 + name_len;
26f57364 5434 data_count = sizeof(struct file_end_of_file_info);
1da177e4 5435 pSMB->MaxParameterCount = cpu_to_le16(2);
3e87d803 5436 pSMB->MaxDataCount = cpu_to_le16(4100);
1da177e4
LT
5437 pSMB->MaxSetupCount = 0;
5438 pSMB->Reserved = 0;
5439 pSMB->Flags = 0;
5440 pSMB->Timeout = 0;
5441 pSMB->Reserved2 = 0;
5442 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5443 InformationLevel) - 4;
1da177e4 5444 offset = param_offset + params;
790fe579 5445 if (SetAllocation) {
50c2f753
SF
5446 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5447 pSMB->InformationLevel =
5448 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5449 else
5450 pSMB->InformationLevel =
5451 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
5452 } else /* Set File Size */ {
1da177e4
LT
5453 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5454 pSMB->InformationLevel =
50c2f753 5455 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
5456 else
5457 pSMB->InformationLevel =
50c2f753 5458 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
5459 }
5460
5461 parm_data =
5462 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
5463 offset);
5464 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5465 pSMB->DataOffset = cpu_to_le16(offset);
5466 pSMB->SetupCount = 1;
5467 pSMB->Reserved3 = 0;
5468 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5469 byte_count = 3 /* pad */ + params + data_count;
5470 pSMB->DataCount = cpu_to_le16(data_count);
5471 pSMB->TotalDataCount = pSMB->DataCount;
5472 pSMB->ParameterCount = cpu_to_le16(params);
5473 pSMB->TotalParameterCount = pSMB->ParameterCount;
5474 pSMB->Reserved4 = 0;
be8e3b00 5475 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
5476 parm_data->FileSize = cpu_to_le64(size);
5477 pSMB->ByteCount = cpu_to_le16(byte_count);
5478 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5479 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5480 if (rc)
b6b38f70 5481 cFYI(1, "SetPathInfo (file size) returned %d", rc);
1da177e4
LT
5482
5483 cifs_buf_release(pSMB);
5484
5485 if (rc == -EAGAIN)
5486 goto SetEOFRetry;
5487
5488 return rc;
5489}
5490
5491int
6d5786a3 5492CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
4b18f2a9 5493 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
1da177e4
LT
5494{
5495 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
5496 struct file_end_of_file_info *parm_data;
5497 int rc = 0;
1da177e4
LT
5498 __u16 params, param_offset, offset, byte_count, count;
5499
b6b38f70
JP
5500 cFYI(1, "SetFileSize (via SetFileInfo) %lld",
5501 (long long)size);
cd63499c
SF
5502 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5503
1da177e4
LT
5504 if (rc)
5505 return rc;
5506
5507 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5508 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 5509
1da177e4
LT
5510 params = 6;
5511 pSMB->MaxSetupCount = 0;
5512 pSMB->Reserved = 0;
5513 pSMB->Flags = 0;
5514 pSMB->Timeout = 0;
5515 pSMB->Reserved2 = 0;
5516 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5517 offset = param_offset + params;
5518
1da177e4
LT
5519 count = sizeof(struct file_end_of_file_info);
5520 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5521 /* BB find exact max SMB PDU from sess structure BB */
5522 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5523 pSMB->SetupCount = 1;
5524 pSMB->Reserved3 = 0;
5525 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5526 byte_count = 3 /* pad */ + params + count;
5527 pSMB->DataCount = cpu_to_le16(count);
5528 pSMB->ParameterCount = cpu_to_le16(params);
5529 pSMB->TotalDataCount = pSMB->DataCount;
5530 pSMB->TotalParameterCount = pSMB->ParameterCount;
5531 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5532 parm_data =
50c2f753
SF
5533 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
5534 + offset);
1da177e4
LT
5535 pSMB->DataOffset = cpu_to_le16(offset);
5536 parm_data->FileSize = cpu_to_le64(size);
5537 pSMB->Fid = fid;
790fe579 5538 if (SetAllocation) {
1da177e4
LT
5539 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5540 pSMB->InformationLevel =
5541 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
5542 else
5543 pSMB->InformationLevel =
5544 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
50c2f753 5545 } else /* Set File Size */ {
1da177e4
LT
5546 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5547 pSMB->InformationLevel =
50c2f753 5548 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
1da177e4
LT
5549 else
5550 pSMB->InformationLevel =
50c2f753 5551 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
1da177e4
LT
5552 }
5553 pSMB->Reserved4 = 0;
be8e3b00 5554 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5555 pSMB->ByteCount = cpu_to_le16(byte_count);
792af7b0 5556 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
1da177e4 5557 if (rc) {
b6b38f70 5558 cFYI(1, "Send error in SetFileInfo (SetFileSize) = %d", rc);
1da177e4
LT
5559 }
5560
50c2f753 5561 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
5562 since file handle passed in no longer valid */
5563
5564 return rc;
5565}
5566
50c2f753 5567/* Some legacy servers such as NT4 require that the file times be set on
1da177e4
LT
5568 an open handle, rather than by pathname - this is awkward due to
5569 potential access conflicts on the open, but it is unavoidable for these
5570 old servers since the only other choice is to go from 100 nanosecond DCE
5571 time and resort to the original setpathinfo level which takes the ancient
5572 DOS time format with 2 second granularity */
5573int
6d5786a3 5574CIFSSMBSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
2dd2dfa0 5575 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
1da177e4
LT
5576{
5577 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1da177e4
LT
5578 char *data_offset;
5579 int rc = 0;
1da177e4
LT
5580 __u16 params, param_offset, offset, byte_count, count;
5581
b6b38f70 5582 cFYI(1, "Set Times (via SetFileInfo)");
cd63499c
SF
5583 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5584
1da177e4
LT
5585 if (rc)
5586 return rc;
5587
2dd2dfa0
JL
5588 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5589 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
50c2f753 5590
1da177e4
LT
5591 params = 6;
5592 pSMB->MaxSetupCount = 0;
5593 pSMB->Reserved = 0;
5594 pSMB->Flags = 0;
5595 pSMB->Timeout = 0;
5596 pSMB->Reserved2 = 0;
5597 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5598 offset = param_offset + params;
5599
b2a3ad9c
JL
5600 data_offset = (char *)pSMB +
5601 offsetof(struct smb_hdr, Protocol) + offset;
1da177e4 5602
26f57364 5603 count = sizeof(FILE_BASIC_INFO);
1da177e4 5604 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5605 /* BB find max SMB PDU from sess */
5606 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5607 pSMB->SetupCount = 1;
5608 pSMB->Reserved3 = 0;
5609 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5610 byte_count = 3 /* pad */ + params + count;
5611 pSMB->DataCount = cpu_to_le16(count);
5612 pSMB->ParameterCount = cpu_to_le16(params);
5613 pSMB->TotalDataCount = pSMB->DataCount;
5614 pSMB->TotalParameterCount = pSMB->ParameterCount;
5615 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5616 pSMB->DataOffset = cpu_to_le16(offset);
5617 pSMB->Fid = fid;
5618 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5619 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5620 else
5621 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5622 pSMB->Reserved4 = 0;
be8e3b00 5623 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5624 pSMB->ByteCount = cpu_to_le16(byte_count);
50c2f753 5625 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
792af7b0 5626 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
ad7a2926 5627 if (rc)
b6b38f70 5628 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
1da177e4 5629
50c2f753 5630 /* Note: On -EAGAIN error only caller can retry on handle based calls
1da177e4
LT
5631 since file handle passed in no longer valid */
5632
5633 return rc;
5634}
5635
6d22f098 5636int
6d5786a3 5637CIFSSMBSetFileDisposition(const unsigned int xid, struct cifs_tcon *tcon,
6d22f098
JL
5638 bool delete_file, __u16 fid, __u32 pid_of_opener)
5639{
5640 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5641 char *data_offset;
5642 int rc = 0;
5643 __u16 params, param_offset, offset, byte_count, count;
5644
b6b38f70 5645 cFYI(1, "Set File Disposition (via SetFileInfo)");
6d22f098
JL
5646 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5647
5648 if (rc)
5649 return rc;
5650
5651 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5652 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5653
5654 params = 6;
5655 pSMB->MaxSetupCount = 0;
5656 pSMB->Reserved = 0;
5657 pSMB->Flags = 0;
5658 pSMB->Timeout = 0;
5659 pSMB->Reserved2 = 0;
5660 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5661 offset = param_offset + params;
5662
5663 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5664
5665 count = 1;
5666 pSMB->MaxParameterCount = cpu_to_le16(2);
5667 /* BB find max SMB PDU from sess */
5668 pSMB->MaxDataCount = cpu_to_le16(1000);
5669 pSMB->SetupCount = 1;
5670 pSMB->Reserved3 = 0;
5671 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5672 byte_count = 3 /* pad */ + params + count;
5673 pSMB->DataCount = cpu_to_le16(count);
5674 pSMB->ParameterCount = cpu_to_le16(params);
5675 pSMB->TotalDataCount = pSMB->DataCount;
5676 pSMB->TotalParameterCount = pSMB->ParameterCount;
5677 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5678 pSMB->DataOffset = cpu_to_le16(offset);
5679 pSMB->Fid = fid;
5680 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
5681 pSMB->Reserved4 = 0;
be8e3b00 5682 inc_rfc1001_len(pSMB, byte_count);
6d22f098
JL
5683 pSMB->ByteCount = cpu_to_le16(byte_count);
5684 *data_offset = delete_file ? 1 : 0;
792af7b0 5685 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
6d22f098 5686 if (rc)
b6b38f70 5687 cFYI(1, "Send error in SetFileDisposition = %d", rc);
6d22f098
JL
5688
5689 return rc;
5690}
1da177e4
LT
5691
5692int
6d5786a3 5693CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
6fc000e5
JL
5694 const char *fileName, const FILE_BASIC_INFO *data,
5695 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5696{
5697 TRANSACTION2_SPI_REQ *pSMB = NULL;
5698 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5699 int name_len;
5700 int rc = 0;
5701 int bytes_returned = 0;
5702 char *data_offset;
5703 __u16 params, param_offset, offset, byte_count, count;
5704
b6b38f70 5705 cFYI(1, "In SetTimes");
1da177e4
LT
5706
5707SetTimesRetry:
5708 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5709 (void **) &pSMBr);
5710 if (rc)
5711 return rc;
5712
5713 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5714 name_len =
acbbb76a
SF
5715 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
5716 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5717 name_len++; /* trailing null */
5718 name_len *= 2;
50c2f753 5719 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5720 name_len = strnlen(fileName, PATH_MAX);
5721 name_len++; /* trailing null */
5722 strncpy(pSMB->FileName, fileName, name_len);
5723 }
5724
5725 params = 6 + name_len;
26f57364 5726 count = sizeof(FILE_BASIC_INFO);
1da177e4 5727 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5728 /* BB find max SMB PDU from sess structure BB */
5729 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5730 pSMB->MaxSetupCount = 0;
5731 pSMB->Reserved = 0;
5732 pSMB->Flags = 0;
5733 pSMB->Timeout = 0;
5734 pSMB->Reserved2 = 0;
5735 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5736 InformationLevel) - 4;
1da177e4
LT
5737 offset = param_offset + params;
5738 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
5739 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5740 pSMB->DataOffset = cpu_to_le16(offset);
5741 pSMB->SetupCount = 1;
5742 pSMB->Reserved3 = 0;
5743 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5744 byte_count = 3 /* pad */ + params + count;
5745
5746 pSMB->DataCount = cpu_to_le16(count);
5747 pSMB->ParameterCount = cpu_to_le16(params);
5748 pSMB->TotalDataCount = pSMB->DataCount;
5749 pSMB->TotalParameterCount = pSMB->ParameterCount;
5750 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
5751 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
5752 else
5753 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
5754 pSMB->Reserved4 = 0;
be8e3b00 5755 inc_rfc1001_len(pSMB, byte_count);
26f57364 5756 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
1da177e4
LT
5757 pSMB->ByteCount = cpu_to_le16(byte_count);
5758 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5759 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5760 if (rc)
b6b38f70 5761 cFYI(1, "SetPathInfo (times) returned %d", rc);
1da177e4
LT
5762
5763 cifs_buf_release(pSMB);
5764
5765 if (rc == -EAGAIN)
5766 goto SetTimesRetry;
5767
5768 return rc;
5769}
5770
5771/* Can not be used to set time stamps yet (due to old DOS time format) */
5772/* Can be used to set attributes */
5773#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
5774 handling it anyway and NT4 was what we thought it would be needed for
5775 Do not delete it until we prove whether needed for Win9x though */
5776int
6d5786a3 5777CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon, char *fileName,
1da177e4
LT
5778 __u16 dos_attrs, const struct nls_table *nls_codepage)
5779{
5780 SETATTR_REQ *pSMB = NULL;
5781 SETATTR_RSP *pSMBr = NULL;
5782 int rc = 0;
5783 int bytes_returned;
5784 int name_len;
5785
b6b38f70 5786 cFYI(1, "In SetAttrLegacy");
1da177e4
LT
5787
5788SetAttrLgcyRetry:
5789 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5790 (void **) &pSMBr);
5791 if (rc)
5792 return rc;
5793
5794 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5795 name_len =
acbbb76a
SF
5796 ConvertToUTF16((__le16 *) pSMB->fileName, fileName,
5797 PATH_MAX, nls_codepage);
1da177e4
LT
5798 name_len++; /* trailing null */
5799 name_len *= 2;
50c2f753 5800 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
5801 name_len = strnlen(fileName, PATH_MAX);
5802 name_len++; /* trailing null */
5803 strncpy(pSMB->fileName, fileName, name_len);
5804 }
5805 pSMB->attr = cpu_to_le16(dos_attrs);
5806 pSMB->BufferFormat = 0x04;
be8e3b00 5807 inc_rfc1001_len(pSMB, name_len + 1);
1da177e4
LT
5808 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5809 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5810 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5811 if (rc)
b6b38f70 5812 cFYI(1, "Error in LegacySetAttr = %d", rc);
1da177e4
LT
5813
5814 cifs_buf_release(pSMB);
5815
5816 if (rc == -EAGAIN)
5817 goto SetAttrLgcyRetry;
5818
5819 return rc;
5820}
5821#endif /* temporarily unneeded SetAttr legacy function */
5822
654cf14a
JL
5823static void
5824cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5825 const struct cifs_unix_set_info_args *args)
5826{
5827 u64 mode = args->mode;
5828
5829 /*
5830 * Samba server ignores set of file size to zero due to bugs in some
5831 * older clients, but we should be precise - we use SetFileSize to
5832 * set file size and do not want to truncate file size to zero
25985edc 5833 * accidentally as happened on one Samba server beta by putting
654cf14a
JL
5834 * zero instead of -1 here
5835 */
5836 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5837 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5838 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5839 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5840 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5841 data_offset->Uid = cpu_to_le64(args->uid);
5842 data_offset->Gid = cpu_to_le64(args->gid);
5843 /* better to leave device as zero when it is */
5844 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5845 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5846 data_offset->Permissions = cpu_to_le64(mode);
5847
5848 if (S_ISREG(mode))
5849 data_offset->Type = cpu_to_le32(UNIX_FILE);
5850 else if (S_ISDIR(mode))
5851 data_offset->Type = cpu_to_le32(UNIX_DIR);
5852 else if (S_ISLNK(mode))
5853 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5854 else if (S_ISCHR(mode))
5855 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5856 else if (S_ISBLK(mode))
5857 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5858 else if (S_ISFIFO(mode))
5859 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5860 else if (S_ISSOCK(mode))
5861 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5862}
5863
3bbeeb3c 5864int
6d5786a3 5865CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
3bbeeb3c
JL
5866 const struct cifs_unix_set_info_args *args,
5867 u16 fid, u32 pid_of_opener)
5868{
5869 struct smb_com_transaction2_sfi_req *pSMB = NULL;
b2a3ad9c 5870 char *data_offset;
3bbeeb3c
JL
5871 int rc = 0;
5872 u16 params, param_offset, offset, byte_count, count;
5873
b6b38f70 5874 cFYI(1, "Set Unix Info (via SetFileInfo)");
3bbeeb3c
JL
5875 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5876
5877 if (rc)
5878 return rc;
5879
5880 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5881 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5882
5883 params = 6;
5884 pSMB->MaxSetupCount = 0;
5885 pSMB->Reserved = 0;
5886 pSMB->Flags = 0;
5887 pSMB->Timeout = 0;
5888 pSMB->Reserved2 = 0;
5889 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5890 offset = param_offset + params;
5891
b2a3ad9c
JL
5892 data_offset = (char *)pSMB +
5893 offsetof(struct smb_hdr, Protocol) + offset;
5894
3bbeeb3c
JL
5895 count = sizeof(FILE_UNIX_BASIC_INFO);
5896
5897 pSMB->MaxParameterCount = cpu_to_le16(2);
5898 /* BB find max SMB PDU from sess */
5899 pSMB->MaxDataCount = cpu_to_le16(1000);
5900 pSMB->SetupCount = 1;
5901 pSMB->Reserved3 = 0;
5902 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5903 byte_count = 3 /* pad */ + params + count;
5904 pSMB->DataCount = cpu_to_le16(count);
5905 pSMB->ParameterCount = cpu_to_le16(params);
5906 pSMB->TotalDataCount = pSMB->DataCount;
5907 pSMB->TotalParameterCount = pSMB->ParameterCount;
5908 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5909 pSMB->DataOffset = cpu_to_le16(offset);
5910 pSMB->Fid = fid;
5911 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5912 pSMB->Reserved4 = 0;
be8e3b00 5913 inc_rfc1001_len(pSMB, byte_count);
3bbeeb3c
JL
5914 pSMB->ByteCount = cpu_to_le16(byte_count);
5915
b2a3ad9c 5916 cifs_fill_unix_set_info((FILE_UNIX_BASIC_INFO *)data_offset, args);
3bbeeb3c 5917
792af7b0 5918 rc = SendReceiveNoRsp(xid, tcon->ses, (char *) pSMB, 0);
3bbeeb3c 5919 if (rc)
b6b38f70 5920 cFYI(1, "Send error in Set Time (SetFileInfo) = %d", rc);
3bbeeb3c
JL
5921
5922 /* Note: On -EAGAIN error only caller can retry on handle based calls
5923 since file handle passed in no longer valid */
5924
5925 return rc;
5926}
5927
1da177e4 5928int
6d5786a3 5929CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
ff691e96 5930 const char *file_name,
01ea95e3
JL
5931 const struct cifs_unix_set_info_args *args,
5932 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
5933{
5934 TRANSACTION2_SPI_REQ *pSMB = NULL;
5935 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5936 int name_len;
5937 int rc = 0;
5938 int bytes_returned = 0;
5939 FILE_UNIX_BASIC_INFO *data_offset;
5940 __u16 params, param_offset, offset, count, byte_count;
5941
b6b38f70 5942 cFYI(1, "In SetUID/GID/Mode");
1da177e4
LT
5943setPermsRetry:
5944 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5945 (void **) &pSMBr);
5946 if (rc)
5947 return rc;
5948
5949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5950 name_len =
ff691e96 5951 cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
acbbb76a 5952 PATH_MAX, nls_codepage, remap);
1da177e4
LT
5953 name_len++; /* trailing null */
5954 name_len *= 2;
3e87d803 5955 } else { /* BB improve the check for buffer overruns BB */
ff691e96 5956 name_len = strnlen(file_name, PATH_MAX);
1da177e4 5957 name_len++; /* trailing null */
ff691e96 5958 strncpy(pSMB->FileName, file_name, name_len);
1da177e4
LT
5959 }
5960
5961 params = 6 + name_len;
26f57364 5962 count = sizeof(FILE_UNIX_BASIC_INFO);
1da177e4 5963 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
5964 /* BB find max SMB PDU from sess structure BB */
5965 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
5966 pSMB->MaxSetupCount = 0;
5967 pSMB->Reserved = 0;
5968 pSMB->Flags = 0;
5969 pSMB->Timeout = 0;
5970 pSMB->Reserved2 = 0;
5971 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 5972 InformationLevel) - 4;
1da177e4
LT
5973 offset = param_offset + params;
5974 data_offset =
5975 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5976 offset);
5977 memset(data_offset, 0, count);
5978 pSMB->DataOffset = cpu_to_le16(offset);
5979 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5980 pSMB->SetupCount = 1;
5981 pSMB->Reserved3 = 0;
5982 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5983 byte_count = 3 /* pad */ + params + count;
5984 pSMB->ParameterCount = cpu_to_le16(params);
5985 pSMB->DataCount = cpu_to_le16(count);
5986 pSMB->TotalParameterCount = pSMB->ParameterCount;
5987 pSMB->TotalDataCount = pSMB->DataCount;
5988 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5989 pSMB->Reserved4 = 0;
be8e3b00 5990 inc_rfc1001_len(pSMB, byte_count);
1da177e4 5991
654cf14a 5992 cifs_fill_unix_set_info(data_offset, args);
1da177e4
LT
5993
5994 pSMB->ByteCount = cpu_to_le16(byte_count);
5995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 5997 if (rc)
b6b38f70 5998 cFYI(1, "SetPathInfo (perms) returned %d", rc);
1da177e4 5999
0d817bc0 6000 cifs_buf_release(pSMB);
1da177e4
LT
6001 if (rc == -EAGAIN)
6002 goto setPermsRetry;
6003 return rc;
6004}
6005
1da177e4 6006#ifdef CONFIG_CIFS_XATTR
31c0519f
JL
6007/*
6008 * Do a path-based QUERY_ALL_EAS call and parse the result. This is a common
6009 * function used by listxattr and getxattr type calls. When ea_name is set,
6010 * it looks for that attribute name and stuffs that value into the EAData
6011 * buffer. When ea_name is NULL, it stuffs a list of attribute names into the
6012 * buffer. In both cases, the return value is either the length of the
6013 * resulting data or a negative error code. If EAData is a NULL pointer then
6014 * the data isn't copied to it, but the length is returned.
6015 */
1da177e4 6016ssize_t
6d5786a3 6017CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
31c0519f
JL
6018 const unsigned char *searchName, const unsigned char *ea_name,
6019 char *EAData, size_t buf_size,
6020 const struct nls_table *nls_codepage, int remap)
1da177e4
LT
6021{
6022 /* BB assumes one setup word */
6023 TRANSACTION2_QPI_REQ *pSMB = NULL;
6024 TRANSACTION2_QPI_RSP *pSMBr = NULL;
6025 int rc = 0;
6026 int bytes_returned;
6e462b9f 6027 int list_len;
f0d3868b 6028 struct fealist *ea_response_data;
50c2f753
SF
6029 struct fea *temp_fea;
6030 char *temp_ptr;
0cd126b5 6031 char *end_of_smb;
f0d3868b 6032 __u16 params, byte_count, data_offset;
5980fc96 6033 unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
1da177e4 6034
b6b38f70 6035 cFYI(1, "In Query All EAs path %s", searchName);
1da177e4
LT
6036QAllEAsRetry:
6037 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6038 (void **) &pSMBr);
6039 if (rc)
6040 return rc;
6041
6042 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6e462b9f 6043 list_len =
acbbb76a
SF
6044 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
6045 PATH_MAX, nls_codepage, remap);
6e462b9f
JL
6046 list_len++; /* trailing null */
6047 list_len *= 2;
1da177e4 6048 } else { /* BB improve the check for buffer overruns BB */
6e462b9f
JL
6049 list_len = strnlen(searchName, PATH_MAX);
6050 list_len++; /* trailing null */
6051 strncpy(pSMB->FileName, searchName, list_len);
1da177e4
LT
6052 }
6053
6e462b9f 6054 params = 2 /* level */ + 4 /* reserved */ + list_len /* includes NUL */;
1da177e4
LT
6055 pSMB->TotalDataCount = 0;
6056 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5 6057 /* BB find exact max SMB PDU from sess structure BB */
e529614a 6058 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
1da177e4
LT
6059 pSMB->MaxSetupCount = 0;
6060 pSMB->Reserved = 0;
6061 pSMB->Flags = 0;
6062 pSMB->Timeout = 0;
6063 pSMB->Reserved2 = 0;
6064 pSMB->ParameterOffset = cpu_to_le16(offsetof(
50c2f753 6065 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
1da177e4
LT
6066 pSMB->DataCount = 0;
6067 pSMB->DataOffset = 0;
6068 pSMB->SetupCount = 1;
6069 pSMB->Reserved3 = 0;
6070 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
6071 byte_count = params + 1 /* pad */ ;
6072 pSMB->TotalParameterCount = cpu_to_le16(params);
6073 pSMB->ParameterCount = pSMB->TotalParameterCount;
6074 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
6075 pSMB->Reserved4 = 0;
be8e3b00 6076 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
6077 pSMB->ByteCount = cpu_to_le16(byte_count);
6078
6079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
6081 if (rc) {
b6b38f70 6082 cFYI(1, "Send error in QueryAllEAs = %d", rc);
f0d3868b
JL
6083 goto QAllEAsOut;
6084 }
1da177e4 6085
f0d3868b
JL
6086
6087 /* BB also check enough total bytes returned */
6088 /* BB we need to improve the validity checking
6089 of these trans2 responses */
6090
6091 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
820a803f 6092 if (rc || get_bcc(&pSMBr->hdr) < 4) {
f0d3868b
JL
6093 rc = -EIO; /* bad smb */
6094 goto QAllEAsOut;
6095 }
6096
6097 /* check that length of list is not more than bcc */
6098 /* check that each entry does not go beyond length
6099 of list */
6100 /* check that each element of each entry does not
6101 go beyond end of list */
6102 /* validate_trans2_offsets() */
6103 /* BB check if start of smb + data_offset > &bcc+ bcc */
6104
6105 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
6106 ea_response_data = (struct fealist *)
6107 (((char *) &pSMBr->hdr.Protocol) + data_offset);
6108
6e462b9f 6109 list_len = le32_to_cpu(ea_response_data->list_len);
b6b38f70 6110 cFYI(1, "ea length %d", list_len);
6e462b9f 6111 if (list_len <= 8) {
b6b38f70 6112 cFYI(1, "empty EA list returned from server");
f0d3868b
JL
6113 goto QAllEAsOut;
6114 }
6115
0cd126b5 6116 /* make sure list_len doesn't go past end of SMB */
690c522f 6117 end_of_smb = (char *)pByteArea(&pSMBr->hdr) + get_bcc(&pSMBr->hdr);
0cd126b5 6118 if ((char *)ea_response_data + list_len > end_of_smb) {
b6b38f70 6119 cFYI(1, "EA list appears to go beyond SMB");
0cd126b5
JL
6120 rc = -EIO;
6121 goto QAllEAsOut;
6122 }
6123
f0d3868b 6124 /* account for ea list len */
6e462b9f 6125 list_len -= 4;
f0d3868b
JL
6126 temp_fea = ea_response_data->list;
6127 temp_ptr = (char *)temp_fea;
6e462b9f 6128 while (list_len > 0) {
122ca007 6129 unsigned int name_len;
f0d3868b 6130 __u16 value_len;
0cd126b5 6131
6e462b9f 6132 list_len -= 4;
f0d3868b 6133 temp_ptr += 4;
0cd126b5
JL
6134 /* make sure we can read name_len and value_len */
6135 if (list_len < 0) {
b6b38f70 6136 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
6137 rc = -EIO;
6138 goto QAllEAsOut;
6139 }
6140
6141 name_len = temp_fea->name_len;
6142 value_len = le16_to_cpu(temp_fea->value_len);
6143 list_len -= name_len + 1 + value_len;
6144 if (list_len < 0) {
b6b38f70 6145 cFYI(1, "EA entry goes beyond length of list");
0cd126b5
JL
6146 rc = -EIO;
6147 goto QAllEAsOut;
6148 }
6149
31c0519f 6150 if (ea_name) {
91d065c4 6151 if (ea_name_len == name_len &&
ac423446 6152 memcmp(ea_name, temp_ptr, name_len) == 0) {
31c0519f
JL
6153 temp_ptr += name_len + 1;
6154 rc = value_len;
6155 if (buf_size == 0)
6156 goto QAllEAsOut;
6157 if ((size_t)value_len > buf_size) {
6158 rc = -ERANGE;
6159 goto QAllEAsOut;
6160 }
6161 memcpy(EAData, temp_ptr, value_len);
6162 goto QAllEAsOut;
6163 }
f0d3868b 6164 } else {
31c0519f
JL
6165 /* account for prefix user. and trailing null */
6166 rc += (5 + 1 + name_len);
6167 if (rc < (int) buf_size) {
6168 memcpy(EAData, "user.", 5);
6169 EAData += 5;
6170 memcpy(EAData, temp_ptr, name_len);
6171 EAData += name_len;
6172 /* null terminate name */
6173 *EAData = 0;
6174 ++EAData;
6175 } else if (buf_size == 0) {
6176 /* skip copy - calc size only */
6177 } else {
6178 /* stop before overrun buffer */
6179 rc = -ERANGE;
6180 break;
6181 }
1da177e4 6182 }
0cd126b5 6183 temp_ptr += name_len + 1 + value_len;
f0d3868b 6184 temp_fea = (struct fea *)temp_ptr;
1da177e4 6185 }
f0d3868b 6186
31c0519f
JL
6187 /* didn't find the named attribute */
6188 if (ea_name)
6189 rc = -ENODATA;
6190
f0d3868b 6191QAllEAsOut:
0d817bc0 6192 cifs_buf_release(pSMB);
1da177e4
LT
6193 if (rc == -EAGAIN)
6194 goto QAllEAsRetry;
6195
6196 return (ssize_t)rc;
6197}
6198
1da177e4 6199int
6d5786a3
PS
6200CIFSSMBSetEA(const unsigned int xid, struct cifs_tcon *tcon,
6201 const char *fileName, const char *ea_name, const void *ea_value,
50c2f753
SF
6202 const __u16 ea_value_len, const struct nls_table *nls_codepage,
6203 int remap)
1da177e4
LT
6204{
6205 struct smb_com_transaction2_spi_req *pSMB = NULL;
6206 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
6207 struct fealist *parm_data;
6208 int name_len;
6209 int rc = 0;
6210 int bytes_returned = 0;
6211 __u16 params, param_offset, byte_count, offset, count;
6212
b6b38f70 6213 cFYI(1, "In SetEA");
1da177e4
LT
6214SetEARetry:
6215 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
6216 (void **) &pSMBr);
6217 if (rc)
6218 return rc;
6219
6220 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
6221 name_len =
acbbb76a
SF
6222 cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
6223 PATH_MAX, nls_codepage, remap);
1da177e4
LT
6224 name_len++; /* trailing null */
6225 name_len *= 2;
50c2f753 6226 } else { /* BB improve the check for buffer overruns BB */
1da177e4
LT
6227 name_len = strnlen(fileName, PATH_MAX);
6228 name_len++; /* trailing null */
6229 strncpy(pSMB->FileName, fileName, name_len);
6230 }
6231
6232 params = 6 + name_len;
6233
6234 /* done calculating parms using name_len of file name,
6235 now use name_len to calculate length of ea name
6236 we are going to create in the inode xattrs */
790fe579 6237 if (ea_name == NULL)
1da177e4
LT
6238 name_len = 0;
6239 else
50c2f753 6240 name_len = strnlen(ea_name, 255);
1da177e4 6241
dae5dbdb 6242 count = sizeof(*parm_data) + ea_value_len + name_len;
1da177e4 6243 pSMB->MaxParameterCount = cpu_to_le16(2);
582d21e5
SF
6244 /* BB find max SMB PDU from sess */
6245 pSMB->MaxDataCount = cpu_to_le16(1000);
1da177e4
LT
6246 pSMB->MaxSetupCount = 0;
6247 pSMB->Reserved = 0;
6248 pSMB->Flags = 0;
6249 pSMB->Timeout = 0;
6250 pSMB->Reserved2 = 0;
6251 param_offset = offsetof(struct smb_com_transaction2_spi_req,
50c2f753 6252 InformationLevel) - 4;
1da177e4
LT
6253 offset = param_offset + params;
6254 pSMB->InformationLevel =
6255 cpu_to_le16(SMB_SET_FILE_EA);
6256
6257 parm_data =
6258 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
6259 offset);
6260 pSMB->ParameterOffset = cpu_to_le16(param_offset);
6261 pSMB->DataOffset = cpu_to_le16(offset);
6262 pSMB->SetupCount = 1;
6263 pSMB->Reserved3 = 0;
6264 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
6265 byte_count = 3 /* pad */ + params + count;
6266 pSMB->DataCount = cpu_to_le16(count);
6267 parm_data->list_len = cpu_to_le32(count);
6268 parm_data->list[0].EA_flags = 0;
6269 /* we checked above that name len is less than 255 */
53b3531b 6270 parm_data->list[0].name_len = (__u8)name_len;
1da177e4 6271 /* EA names are always ASCII */
790fe579 6272 if (ea_name)
50c2f753 6273 strncpy(parm_data->list[0].name, ea_name, name_len);
1da177e4
LT
6274 parm_data->list[0].name[name_len] = 0;
6275 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
6276 /* caller ensures that ea_value_len is less than 64K but
6277 we need to ensure that it fits within the smb */
6278
50c2f753
SF
6279 /*BB add length check to see if it would fit in
6280 negotiated SMB buffer size BB */
790fe579
SF
6281 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
6282 if (ea_value_len)
50c2f753
SF
6283 memcpy(parm_data->list[0].name+name_len+1,
6284 ea_value, ea_value_len);
1da177e4
LT
6285
6286 pSMB->TotalDataCount = pSMB->DataCount;
6287 pSMB->ParameterCount = cpu_to_le16(params);
6288 pSMB->TotalParameterCount = pSMB->ParameterCount;
6289 pSMB->Reserved4 = 0;
be8e3b00 6290 inc_rfc1001_len(pSMB, byte_count);
1da177e4
LT
6291 pSMB->ByteCount = cpu_to_le16(byte_count);
6292 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6293 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
ad7a2926 6294 if (rc)
b6b38f70 6295 cFYI(1, "SetPathInfo (EA) returned %d", rc);
1da177e4
LT
6296
6297 cifs_buf_release(pSMB);
6298
6299 if (rc == -EAGAIN)
6300 goto SetEARetry;
6301
6302 return rc;
6303}
1da177e4 6304#endif
0eff0e26
SF
6305
6306#ifdef CONFIG_CIFS_DNOTIFY_EXPERIMENTAL /* BB unused temporarily */
6307/*
6308 * Years ago the kernel added a "dnotify" function for Samba server,
6309 * to allow network clients (such as Windows) to display updated
6310 * lists of files in directory listings automatically when
6311 * files are added by one user when another user has the
6312 * same directory open on their desktop. The Linux cifs kernel
6313 * client hooked into the kernel side of this interface for
6314 * the same reason, but ironically when the VFS moved from
6315 * "dnotify" to "inotify" it became harder to plug in Linux
6316 * network file system clients (the most obvious use case
6317 * for notify interfaces is when multiple users can update
6318 * the contents of the same directory - exactly what network
6319 * file systems can do) although the server (Samba) could
6320 * still use it. For the short term we leave the worker
6321 * function ifdeffed out (below) until inotify is fixed
6322 * in the VFS to make it easier to plug in network file
6323 * system clients. If inotify turns out to be permanently
6324 * incompatible for network fs clients, we could instead simply
6325 * expose this config flag by adding a future cifs (and smb2) notify ioctl.
6326 */
6d5786a3 6327int CIFSSMBNotify(const unsigned int xid, struct cifs_tcon *tcon,
0eff0e26
SF
6328 const int notify_subdirs, const __u16 netfid,
6329 __u32 filter, struct file *pfile, int multishot,
6330 const struct nls_table *nls_codepage)
6331{
6332 int rc = 0;
6333 struct smb_com_transaction_change_notify_req *pSMB = NULL;
6334 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
6335 struct dir_notify_req *dnotify_req;
6336 int bytes_returned;
6337
6338 cFYI(1, "In CIFSSMBNotify for file handle %d", (int)netfid);
6339 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
6340 (void **) &pSMBr);
6341 if (rc)
6342 return rc;
6343
6344 pSMB->TotalParameterCount = 0 ;
6345 pSMB->TotalDataCount = 0;
6346 pSMB->MaxParameterCount = cpu_to_le32(2);
c974befa 6347 pSMB->MaxDataCount = cpu_to_le32(CIFSMaxBufSize & 0xFFFFFF00);
0eff0e26
SF
6348 pSMB->MaxSetupCount = 4;
6349 pSMB->Reserved = 0;
6350 pSMB->ParameterOffset = 0;
6351 pSMB->DataCount = 0;
6352 pSMB->DataOffset = 0;
6353 pSMB->SetupCount = 4; /* single byte does not need le conversion */
6354 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
6355 pSMB->ParameterCount = pSMB->TotalParameterCount;
6356 if (notify_subdirs)
6357 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
6358 pSMB->Reserved2 = 0;
6359 pSMB->CompletionFilter = cpu_to_le32(filter);
6360 pSMB->Fid = netfid; /* file handle always le */
6361 pSMB->ByteCount = 0;
6362
6363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
6364 (struct smb_hdr *)pSMBr, &bytes_returned,
6365 CIFS_ASYNC_OP);
6366 if (rc) {
6367 cFYI(1, "Error in Notify = %d", rc);
6368 } else {
6369 /* Add file to outstanding requests */
6370 /* BB change to kmem cache alloc */
6371 dnotify_req = kmalloc(
6372 sizeof(struct dir_notify_req),
6373 GFP_KERNEL);
6374 if (dnotify_req) {
6375 dnotify_req->Pid = pSMB->hdr.Pid;
6376 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
6377 dnotify_req->Mid = pSMB->hdr.Mid;
6378 dnotify_req->Tid = pSMB->hdr.Tid;
6379 dnotify_req->Uid = pSMB->hdr.Uid;
6380 dnotify_req->netfid = netfid;
6381 dnotify_req->pfile = pfile;
6382 dnotify_req->filter = filter;
6383 dnotify_req->multishot = multishot;
6384 spin_lock(&GlobalMid_Lock);
6385 list_add_tail(&dnotify_req->lhead,
6386 &GlobalDnotifyReqList);
6387 spin_unlock(&GlobalMid_Lock);
6388 } else
6389 rc = -ENOMEM;
6390 }
6391 cifs_buf_release(pSMB);
6392 return rc;
6393}
6394#endif /* was needed for dnotify, and will be needed for inotify when VFS fix */