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