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