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