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