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