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