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