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