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