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