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