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