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