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