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