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