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