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