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