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