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