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