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