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