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