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