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