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