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