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