diff options
Diffstat (limited to 'target/linux/generic-2.4/patches/107-cifs.patch')
-rw-r--r-- | target/linux/generic-2.4/patches/107-cifs.patch | 22022 |
1 files changed, 22022 insertions, 0 deletions
diff --git a/target/linux/generic-2.4/patches/107-cifs.patch b/target/linux/generic-2.4/patches/107-cifs.patch new file mode 100644 index 0000000000..bdccf4de9f --- /dev/null +++ b/target/linux/generic-2.4/patches/107-cifs.patch @@ -0,0 +1,22022 @@ +diff -urN linux-2.4.29.old/Documentation/Configure.help linux-2.4.29/Documentation/Configure.help +--- linux-2.4.29.old/Documentation/Configure.help 2005-03-21 19:30:22.000000000 +0100 ++++ linux-2.4.29/Documentation/Configure.help 2005-03-21 19:36:51.000000000 +0100 +@@ -17943,6 +17943,34 @@ + + If you don't know what all this is about, say N. + ++CIFS (Common Internet File System) support ++CONFIG_CIFS ++ This is the client VFS module for the Common Internet File System ++ (CIFS) protocol which is the successor to the Server Message Block ++ (SMB) protocol, the native file sharing mechanism for most early ++ PC operating systems. CIFS is fully supported by current network ++ file servers such as Windows 2000, Windows 2003 (including ++ Windows XP) as well by Samba (which provides excellent CIFS ++ server support for Linux and many other operating systems). ++ The smbfs module should be used instead of this cifs module for ++ mounting to older SMB servers such as OS/2. The smbfs and cifs ++ modules can coexist and do not conflict. ++ ++ The intent of this module is to provide the most advanced network ++ file system function for CIFS compliant servers, including better ++ POSIX compliance, secure per-user session establishment, high ++ performance safe distributed caching (oplock), optional packet ++ signing, Unicode support and other internationalization improvements ++ For more information see the project page at ++ http://us1.samba.org/samba/Linux_CIFS_client.html ++ ++CIFS Debugging ++CONFIG_CIFS_DEBUG ++ If you are experiencing any problems with the CIFS filesystem, say ++ Y here. This will result in additional debugging messages to be ++ written to the system log. Under normal circumstances, this ++ results in very little overhead. ++ + SMB file system support (to mount Windows shares etc.) + CONFIG_SMB_FS + SMB (Server Message Block) is the protocol Windows for Workgroups +diff -urN linux-2.4.29.old/Documentation/filesystems/00-INDEX linux-2.4.29/Documentation/filesystems/00-INDEX +--- linux-2.4.29.old/Documentation/filesystems/00-INDEX 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.29/Documentation/filesystems/00-INDEX 2005-03-21 19:36:51.000000000 +0100 +@@ -10,6 +10,8 @@ + - info for the BeOS file system (BFS) + bfs.txt + - info for the SCO UnixWare Boot Filesystem (BFS). ++cifs.txt ++ - info on the Common Internet File System (CIFS) + coda.txt + - description of the CODA filesystem. + cramfs.txt +diff -urN linux-2.4.29.old/Documentation/filesystems/cifs.txt linux-2.4.29/Documentation/filesystems/cifs.txt +--- linux-2.4.29.old/Documentation/filesystems/cifs.txt 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/Documentation/filesystems/cifs.txt 2005-03-21 19:36:51.000000000 +0100 +@@ -0,0 +1,51 @@ ++ This is the client VFS module for the Common Internet File System ++ (CIFS) protocol which is the successor to the Server Message Block ++ (SMB) protocol, the native file sharing mechanism for most early ++ PC operating systems. CIFS is fully supported by current network ++ file servers such as Windows 2000, Windows 2003 (including ++ Windows XP) as well by Samba (which provides excellent CIFS ++ server support for Linux and many other operating systems), so ++ this network filesystem client can mount to a wide variety of ++ servers. The smbfs module should be used instead of this cifs module ++ for mounting to older SMB servers such as OS/2. The smbfs and cifs ++ modules can coexist and do not conflict. The CIFS VFS filesystem ++ module is designed to work well with servers that implement the ++ newer versions (dialects) of the SMB/CIFS protocol such as Samba, ++ the program written by Andrew Tridgell that turns any Unix host ++ into a SMB/CIFS file server. ++ ++ The intent of this module is to provide the most advanced network ++ file system function for CIFS compliant servers, including better ++ POSIX compliance, secure per-user session establishment, high ++ performance safe distributed caching (oplock), optional packet ++ signing, large files, Unicode support and other internationalization ++ improvements. Since both Samba server and this filesystem client support ++ the CIFS Unix extensions, the combination can provide a reasonable ++ alternative to NFSv4 for fileserving in some Linux to Linux environments, ++ not just in Linux to Windows environments. ++ ++ This filesystem has an optional mount utility (mount.cifs) that can ++ be obtained from the project page and installed in the path in the same ++ directory with the other mount helpers (such as mount.smbfs). ++ Mounting using the cifs filesystem without installing the mount helper ++ requires specifying the server's ip address. ++ ++ For Linux 2.4: ++ mount //anything/here /mnt_target -o ++ user=username,pass=password,unc=//ip_address_of_server/sharename ++ ++ For Linux 2.5: ++ mount //ip_address_of_server/sharename /mnt_target -o user=username, pass=password ++ ++ ++ For more information on the module see the project page at ++ ++ http://us1.samba.org/samba/Linux_CIFS_client.html ++ ++ For more information on CIFS see: ++ ++ http://www.snia.org/tech_activities/CIFS ++ ++ or the Samba site: ++ ++ http://www.samba.org +diff -urN linux-2.4.29.old/fs/cifs/asn1.c linux-2.4.29/fs/cifs/asn1.c +--- linux-2.4.29.old/fs/cifs/asn1.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/asn1.c 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,614 @@ ++/* ++ * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in ++ * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich ++ * ++ * Copyright (c) 2000 RP Internet (www.rpi.net.au). ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/kernel.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifs_debug.h" ++ ++/***************************************************************************** ++ * ++ * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse) ++ * ++ *****************************************************************************/ ++ ++/* Class */ ++#define ASN1_UNI 0 /* Universal */ ++#define ASN1_APL 1 /* Application */ ++#define ASN1_CTX 2 /* Context */ ++#define ASN1_PRV 3 /* Private */ ++ ++/* Tag */ ++#define ASN1_EOC 0 /* End Of Contents or N/A */ ++#define ASN1_BOL 1 /* Boolean */ ++#define ASN1_INT 2 /* Integer */ ++#define ASN1_BTS 3 /* Bit String */ ++#define ASN1_OTS 4 /* Octet String */ ++#define ASN1_NUL 5 /* Null */ ++#define ASN1_OJI 6 /* Object Identifier */ ++#define ASN1_OJD 7 /* Object Description */ ++#define ASN1_EXT 8 /* External */ ++#define ASN1_SEQ 16 /* Sequence */ ++#define ASN1_SET 17 /* Set */ ++#define ASN1_NUMSTR 18 /* Numerical String */ ++#define ASN1_PRNSTR 19 /* Printable String */ ++#define ASN1_TEXSTR 20 /* Teletext String */ ++#define ASN1_VIDSTR 21 /* Video String */ ++#define ASN1_IA5STR 22 /* IA5 String */ ++#define ASN1_UNITIM 23 /* Universal Time */ ++#define ASN1_GENTIM 24 /* General Time */ ++#define ASN1_GRASTR 25 /* Graphical String */ ++#define ASN1_VISSTR 26 /* Visible String */ ++#define ASN1_GENSTR 27 /* General String */ ++ ++/* Primitive / Constructed methods*/ ++#define ASN1_PRI 0 /* Primitive */ ++#define ASN1_CON 1 /* Constructed */ ++ ++/* ++ * Error codes. ++ */ ++#define ASN1_ERR_NOERROR 0 ++#define ASN1_ERR_DEC_EMPTY 2 ++#define ASN1_ERR_DEC_EOC_MISMATCH 3 ++#define ASN1_ERR_DEC_LENGTH_MISMATCH 4 ++#define ASN1_ERR_DEC_BADVALUE 5 ++ ++#define SPNEGO_OID_LEN 7 ++#define NTLMSSP_OID_LEN 10 ++unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 }; ++unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 }; ++ ++/* ++ * ASN.1 context. ++ */ ++struct asn1_ctx { ++ int error; /* Error condition */ ++ unsigned char *pointer; /* Octet just to be decoded */ ++ unsigned char *begin; /* First octet */ ++ unsigned char *end; /* Octet after last octet */ ++}; ++ ++/* ++ * Octet string (not null terminated) ++ */ ++struct asn1_octstr { ++ unsigned char *data; ++ unsigned int len; ++}; ++ ++static void ++asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len) ++{ ++ ctx->begin = buf; ++ ctx->end = buf + len; ++ ctx->pointer = buf; ++ ctx->error = ASN1_ERR_NOERROR; ++} ++ ++static unsigned char ++asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch) ++{ ++ if (ctx->pointer >= ctx->end) { ++ ctx->error = ASN1_ERR_DEC_EMPTY; ++ return 0; ++ } ++ *ch = *(ctx->pointer)++; ++ return 1; ++} ++ ++static unsigned char ++asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag) ++{ ++ unsigned char ch; ++ ++ *tag = 0; ++ ++ do { ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ *tag <<= 7; ++ *tag |= ch & 0x7F; ++ } while ((ch & 0x80) == 0x80); ++ return 1; ++} ++ ++static unsigned char ++asn1_id_decode(struct asn1_ctx *ctx, ++ unsigned int *cls, unsigned int *con, unsigned int *tag) ++{ ++ unsigned char ch; ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *cls = (ch & 0xC0) >> 6; ++ *con = (ch & 0x20) >> 5; ++ *tag = (ch & 0x1F); ++ ++ if (*tag == 0x1F) { ++ if (!asn1_tag_decode(ctx, tag)) ++ return 0; ++ } ++ return 1; ++} ++ ++static unsigned char ++asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len) ++{ ++ unsigned char ch, cnt; ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ if (ch == 0x80) ++ *def = 0; ++ else { ++ *def = 1; ++ ++ if (ch < 0x80) ++ *len = ch; ++ else { ++ cnt = (unsigned char) (ch & 0x7F); ++ *len = 0; ++ ++ while (cnt > 0) { ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ *len <<= 8; ++ *len |= ch; ++ cnt--; ++ } ++ } ++ } ++ return 1; ++} ++ ++static unsigned char ++asn1_header_decode(struct asn1_ctx *ctx, ++ unsigned char **eoc, ++ unsigned int *cls, unsigned int *con, unsigned int *tag) ++{ ++ unsigned int def, len; ++ ++ if (!asn1_id_decode(ctx, cls, con, tag)) ++ return 0; ++ ++ if (!asn1_length_decode(ctx, &def, &len)) ++ return 0; ++ ++ if (def) ++ *eoc = ctx->pointer + len; ++ else ++ *eoc = NULL; ++ return 1; ++} ++ ++static unsigned char ++asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc) ++{ ++ unsigned char ch; ++ ++ if (eoc == 0) { ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ if (ch != 0x00) { ++ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; ++ return 0; ++ } ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ if (ch != 0x00) { ++ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH; ++ return 0; ++ } ++ return 1; ++ } else { ++ if (ctx->pointer != eoc) { ++ ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH; ++ return 0; ++ } ++ return 1; ++ } ++} ++ ++/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx, ++ unsigned char *eoc) ++{ ++ ctx->pointer = eoc; ++ return 1; ++} ++ ++static unsigned char asn1_long_decode(struct asn1_ctx *ctx, ++ unsigned char *eoc, long *integer) ++{ ++ unsigned char ch; ++ unsigned int len; ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *integer = (signed char) ch; ++ len = 1; ++ ++ while (ctx->pointer < eoc) { ++ if (++len > sizeof(long)) { ++ ctx->error = ASN1_ERR_DEC_BADVALUE; ++ return 0; ++ } ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *integer <<= 8; ++ *integer |= ch; ++ } ++ return 1; ++} ++ ++static unsigned char asn1_uint_decode(struct asn1_ctx *ctx, ++ unsigned char *eoc, ++ unsigned int *integer) ++{ ++ unsigned char ch; ++ unsigned int len; ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *integer = ch; ++ if (ch == 0) ++ len = 0; ++ else ++ len = 1; ++ ++ while (ctx->pointer < eoc) { ++ if (++len > sizeof(unsigned int)) { ++ ctx->error = ASN1_ERR_DEC_BADVALUE; ++ return 0; ++ } ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *integer <<= 8; ++ *integer |= ch; ++ } ++ return 1; ++} ++ ++static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx, ++ unsigned char *eoc, ++ unsigned long *integer) ++{ ++ unsigned char ch; ++ unsigned int len; ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *integer = ch; ++ if (ch == 0) ++ len = 0; ++ else ++ len = 1; ++ ++ while (ctx->pointer < eoc) { ++ if (++len > sizeof(unsigned long)) { ++ ctx->error = ASN1_ERR_DEC_BADVALUE; ++ return 0; ++ } ++ ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *integer <<= 8; ++ *integer |= ch; ++ } ++ return 1; ++} ++ ++static unsigned char ++asn1_octets_decode(struct asn1_ctx *ctx, ++ unsigned char *eoc, ++ unsigned char **octets, unsigned int *len) ++{ ++ unsigned char *ptr; ++ ++ *len = 0; ++ ++ *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); ++ if (*octets == NULL) { ++ return 0; ++ } ++ ++ ptr = *octets; ++ while (ctx->pointer < eoc) { ++ if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) { ++ kfree(*octets); ++ *octets = NULL; ++ return 0; ++ } ++ (*len)++; ++ } ++ return 1; ++} */ ++ ++static unsigned char ++asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid) ++{ ++ unsigned char ch; ++ ++ *subid = 0; ++ ++ do { ++ if (!asn1_octet_decode(ctx, &ch)) ++ return 0; ++ ++ *subid <<= 7; ++ *subid |= ch & 0x7F; ++ } while ((ch & 0x80) == 0x80); ++ return 1; ++} ++ ++static unsigned char ++asn1_oid_decode(struct asn1_ctx *ctx, ++ unsigned char *eoc, unsigned long **oid, unsigned int *len) ++{ ++ unsigned long subid; ++ unsigned int size; ++ unsigned long *optr; ++ ++ size = eoc - ctx->pointer + 1; ++ *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); ++ if (*oid == NULL) { ++ return 0; ++ } ++ ++ optr = *oid; ++ ++ if (!asn1_subid_decode(ctx, &subid)) { ++ kfree(*oid); ++ *oid = NULL; ++ return 0; ++ } ++ ++ if (subid < 40) { ++ optr[0] = 0; ++ optr[1] = subid; ++ } else if (subid < 80) { ++ optr[0] = 1; ++ optr[1] = subid - 40; ++ } else { ++ optr[0] = 2; ++ optr[1] = subid - 80; ++ } ++ ++ *len = 2; ++ optr += 2; ++ ++ while (ctx->pointer < eoc) { ++ if (++(*len) > size) { ++ ctx->error = ASN1_ERR_DEC_BADVALUE; ++ kfree(*oid); ++ *oid = NULL; ++ return 0; ++ } ++ ++ if (!asn1_subid_decode(ctx, optr++)) { ++ kfree(*oid); ++ *oid = NULL; ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++static int ++compare_oid(unsigned long *oid1, unsigned int oid1len, ++ unsigned long *oid2, unsigned int oid2len) ++{ ++ unsigned int i; ++ ++ if (oid1len != oid2len) ++ return 0; ++ else { ++ for (i = 0; i < oid1len; i++) { ++ if (oid1[i] != oid2[i]) ++ return 0; ++ } ++ return 1; ++ } ++} ++ ++ /* BB check for endian conversion issues here */ ++ ++int ++decode_negTokenInit(unsigned char *security_blob, int length, ++ enum securityEnum *secType) ++{ ++ struct asn1_ctx ctx; ++ unsigned char *end; ++ unsigned char *sequence_end; ++ unsigned long *oid; ++ unsigned int cls, con, tag, oidlen, rc; ++ int use_ntlmssp = FALSE; ++ ++ *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */ ++ ++ /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */ ++ ++ asn1_open(&ctx, security_blob, length); ++ ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ("Error decoding negTokenInit header ")); ++ return 0; ++ } else if ((cls != ASN1_APL) || (con != ASN1_CON) ++ || (tag != ASN1_EOC)) { ++ cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag)); ++ return 0; ++ } else { ++ /* remember to free obj->oid */ ++ rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); ++ if (rc) { ++ if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) { ++ rc = asn1_oid_decode(&ctx, end, &oid, &oidlen); ++ if (rc) { ++ rc = compare_oid(oid, oidlen, ++ SPNEGO_OID, ++ SPNEGO_OID_LEN); ++ kfree(oid); ++ } ++ } else ++ rc = 0; ++ } ++ ++ if (!rc) { ++ cFYI(1, ("Error decoding negTokenInit header")); ++ return 0; ++ } ++ ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ("Error decoding negTokenInit ")); ++ return 0; ++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON) ++ || (tag != ASN1_EOC)) { ++ cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0", ++ cls, con, tag, end, *end)); ++ return 0; ++ } ++ ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ("Error decoding negTokenInit ")); ++ return 0; ++ } else if ((cls != ASN1_UNI) || (con != ASN1_CON) ++ || (tag != ASN1_SEQ)) { ++ cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1", ++ cls, con, tag, end, *end)); ++ return 0; ++ } ++ ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ("Error decoding 2nd part of negTokenInit ")); ++ return 0; ++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON) ++ || (tag != ASN1_EOC)) { ++ cFYI(1, ++ ("cls = %d con = %d tag = %d end = %p (%d) exit 0", ++ cls, con, tag, end, *end)); ++ return 0; ++ } ++ ++ if (asn1_header_decode ++ (&ctx, &sequence_end, &cls, &con, &tag) == 0) { ++ cFYI(1, ("Error decoding 2nd part of negTokenInit ")); ++ return 0; ++ } else if ((cls != ASN1_UNI) || (con != ASN1_CON) ++ || (tag != ASN1_SEQ)) { ++ cFYI(1, ++ ("cls = %d con = %d tag = %d end = %p (%d) exit 1", ++ cls, con, tag, end, *end)); ++ return 0; ++ } ++ ++ while (!asn1_eoc_decode(&ctx, sequence_end)) { ++ rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag); ++ if (!rc) { ++ cFYI(1, ++ ("Error 1 decoding negTokenInit header exit 2")); ++ return 0; ++ } ++ if ((tag == ASN1_OJI) && (con == ASN1_PRI)) { ++ asn1_oid_decode(&ctx, end, &oid, &oidlen); ++ cFYI(1, ++ ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx", ++ oidlen, *oid, *(oid + 1), *(oid + 2), ++ *(oid + 3))); ++ rc = compare_oid(oid, oidlen, NTLMSSP_OID, ++ NTLMSSP_OID_LEN); ++ kfree(oid); ++ if (rc) ++ use_ntlmssp = TRUE; ++ } else { ++ cFYI(1,("This should be an oid what is going on? ")); ++ } ++ } ++ ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ++ ("Error decoding last part of negTokenInit exit 3")); ++ return 0; ++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */ ++ cFYI(1, ++ ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)", ++ cls, con, tag, end, *end)); ++ return 0; ++ } ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ++ ("Error decoding last part of negTokenInit exit 5")); ++ return 0; ++ } else if ((cls != ASN1_UNI) || (con != ASN1_CON) ++ || (tag != ASN1_SEQ)) { ++ cFYI(1, ++ ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)", ++ cls, con, tag, end, *end)); ++ } ++ ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ++ ("Error decoding last part of negTokenInit exit 7")); ++ return 0; ++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { ++ cFYI(1, ++ ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)", ++ cls, con, tag, end, *end)); ++ return 0; ++ } ++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { ++ cFYI(1, ++ ("Error decoding last part of negTokenInit exit 9")); ++ return 0; ++ } else if ((cls != ASN1_UNI) || (con != ASN1_PRI) ++ || (tag != ASN1_GENSTR)) { ++ cFYI(1, ++ ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)", ++ cls, con, tag, end, *end)); ++ return 0; ++ } ++ cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */ ++ } ++ ++ /* if (use_kerberos) ++ *secType = Kerberos ++ else */ ++ if (use_ntlmssp) { ++ *secType = NTLMSSP; ++ } ++ ++ return 1; ++} +diff -urN linux-2.4.29.old/fs/cifs/AUTHORS linux-2.4.29/fs/cifs/AUTHORS +--- linux-2.4.29.old/fs/cifs/AUTHORS 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/AUTHORS 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,37 @@ ++Original Author ++=============== ++Steve French (sfrench@samba.org) ++ ++The author wishes to express his appreciation and thanks to: ++Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS ++improvements. Thanks to IBM for allowing me the time and test resources to pursue ++this project. Jim McDonough from IBM (and the Samba Team) for his help. ++The IBM Linux JFS team for explaining many esoteric Linux filesystem features. ++Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client) ++for proving years ago that a very good smb/cifs client could be done on a Unix like ++operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin ++and others for their work on the Linux smbfs module over the years. Thanks to ++the other members of the Storage Network Industry Association CIFS Technical ++Workgroup for their work specifying this highly complex protocol and finally ++thanks to the Samba team for their technical advice and encouragement. ++ ++Patch Contributors ++------------------ ++Zwane Mwaikambo ++Andi Kleen ++Amrut Joshi ++Shobhit Dayal ++Sergey Vlasov ++Richard Hughes ++Yury Umanets ++ ++Test case and Bug Report contributors ++------------------------------------- ++Thanks to those in the community who have submitted detailed bug reports ++and debug of problems they have found: Jochen Dolze, David Blaine, ++Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori, ++Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen, ++Olaf Kirch, Kieron Briggs, Nick Millington and others. ++ ++And thanks to the IBM LTC and Power test teams and SuSE testers for ++finding multiple bugs during excellent stress test runs. +diff -urN linux-2.4.29.old/fs/cifs/CHANGES linux-2.4.29/fs/cifs/CHANGES +--- linux-2.4.29.old/fs/cifs/CHANGES 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/CHANGES 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,572 @@ ++Version 1.20 ++------------ ++Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps ++info into /proc/fs/cifs/DebugData. Fix oops in rare oops in readdir ++(in build_wildcard_path_from_dentry). Fix mknod to pass type field ++(block/char/fifo) properly. Remove spurious mount warning log entry when ++credentials passed as mount argument. Set major/minor device number in ++inode for block and char devices when unix extensions enabled. ++ ++Version 1.19 ++------------ ++Fix /proc/fs/cifs/Stats and DebugData display to handle larger ++amounts of return data. Properly limit requests to MAX_REQ (50 ++is the usual maximum active multiplex SMB/CIFS requests per server). ++Do not kill cifsd (and thus hurt the other SMB session) when more than one ++session to the same server (but with different userids) exists and one ++of the two user's smb sessions is being removed while leaving the other. ++Do not loop reconnecting in cifsd demultiplex thread when admin ++kills the thread without going through unmount. ++ ++Version 1.18 ++------------ ++Do not rename hardlinked files (since that should be a noop). Flush ++cached write behind data when reopening a file after session abend, ++except when already in write. Grab per socket sem during reconnect ++to avoid oops in sendmsg if overlapping with reconnect. Do not ++reset cached inode file size on readdir for files open for write on ++client. ++ ++ ++Version 1.17 ++------------ ++Update number of blocks in file so du command is happier (in Linux a fake ++blocksize of 512 is required for calculating number of blocks in inode). ++Fix prepare write of partial pages to read in data from server if possible. ++Fix race on tcpStatus field between unmount and reconnection code, causing ++cifsd process sometimes to hang around forever. Improve out of memory ++checks in cifs_filldir ++ ++Version 1.16 ++------------ ++Fix incorrect file size in file handle based setattr on big endian hardware. ++Fix oops in build_path_from_dentry when out of memory. Add checks for invalid ++and closing file structs in writepage/partialpagewrite. Add statistics ++for each mounted share (new menuconfig option). Fix endianness problem in ++volume information displayed in /proc/fs/cifs/DebugData (only affects ++affects big endian architectures). Prevent renames while constructing ++path names for open, mkdir and rmdir. ++ ++Version 1.15 ++------------ ++Change to mempools for alloc smb request buffers and multiplex structs ++to better handle low memory problems (and potential deadlocks). ++ ++Version 1.14 ++------------ ++Fix incomplete listings of large directories on Samba servers when Unix ++extensions enabled. Fix oops when smb_buffer can not be allocated. Fix ++rename deadlock when writing out dirty pages at same time. ++ ++Version 1.13 ++------------ ++Fix open of files in which O_CREATE can cause the mode to change in ++some cases. Fix case in which retry of write overlaps file close. ++Fix PPC64 build error. Reduce excessive stack usage in smb password ++hashing. Fix overwrite of Linux user's view of file mode to Windows servers. ++ ++Version 1.12 ++------------ ++Fixes for large file copy, signal handling, socket retry, buffer ++allocation and low memory situations. ++ ++Version 1.11 ++------------ ++Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize) ++also now allowing support for specifying client netbiosname. NT4 support added. ++ ++Version 1.10 ++------------ ++Fix reconnection (and certain failed mounts) to properly wake up the ++blocked users thread so it does not seem hung (in some cases was blocked ++until the cifs receive timeout expired). Fix spurious error logging ++to kernel log when application with open network files killed. ++ ++Version 1.09 ++------------ ++Fix /proc/fs module unload warning message (that could be logged ++to the kernel log). Fix intermittent failure in connectathon ++test7 (hardlink count not immediately refreshed in case in which ++inode metadata can be incorrectly kept cached when time near zero) ++ ++Version 1.08 ++------------ ++Allow file_mode and dir_mode (specified at mount time) to be enforced ++locally (the server already enforced its own ACLs too) for servers ++that do not report the correct mode (do not support the ++CIFS Unix Extensions). ++ ++Version 1.07 ++------------ ++Fix some small memory leaks in some unmount error paths. Fix major leak ++of cache pages in readpages causing multiple read oriented stress ++testcases (including fsx, and even large file copy) to fail over time. ++ ++Version 1.06 ++------------ ++Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server. ++This allows files that differ only in case and improves performance of file ++creation and file open to such servers. Fix semaphore conflict which causes ++slow delete of open file to Samba (which unfortunately can cause an oplock ++break to self while vfs_unlink held i_sem) which can hang for 20 seconds. ++ ++Version 1.05 ++------------ ++fixes to cifs_readpages for fsx test case ++ ++Version 1.04 ++------------ ++Fix caching data integrity bug when extending file size especially when no ++oplock on file. Fix spurious logging of valid already parsed mount options ++that are parsed outside of the cifs vfs such as nosuid. ++ ++ ++Version 1.03 ++------------ ++Connect to server when port number override not specified, and tcp port ++unitialized. Reset search to restart at correct file when kernel routine ++filldir returns error during large directory searches (readdir). ++ ++Version 1.02 ++------------ ++Fix caching problem when files opened by multiple clients in which ++page cache could contain stale data, and write through did ++not occur often enough while file was still open when read ahead ++(read oplock) not allowed. Treat "sep=" when first mount option ++as an overrride of comma as the default separator between mount ++options. ++ ++Version 1.01 ++------------ ++Allow passwords longer than 16 bytes. Allow null password string. ++ ++Version 1.00 ++------------ ++Gracefully clean up failed mounts when attempting to mount to servers such as ++Windows 98 that terminate tcp sessions during prototocol negotiation. Handle ++embedded commas in mount parsing of passwords. ++ ++Version 0.99 ++------------ ++Invalidate local inode cached pages on oplock break and when last file ++instance is closed so that the client does not continue using stale local ++copy rather than later modified server copy of file. Do not reconnect ++when server drops the tcp session prematurely before negotiate ++protocol response. Fix oops in roepen_file when dentry freed. Allow ++the support for CIFS Unix Extensions to be disabled via proc interface. ++ ++Version 0.98 ++------------ ++Fix hang in commit_write during reconnection of open files under heavy load. ++Fix unload_nls oops in a mount failure path. Serialize writes to same socket ++which also fixes any possible races when cifs signatures are enabled in SMBs ++being sent out of signature sequence number order. ++ ++Version 0.97 ++------------ ++Fix byte range locking bug (endian problem) causing bad offset and ++length. ++ ++Version 0.96 ++------------ ++Fix oops (in send_sig) caused by CIFS unmount code trying to ++wake up the demultiplex thread after it had exited. Do not log ++error on harmless oplock release of closed handle. ++ ++Version 0.95 ++------------ ++Fix unsafe global variable usage and password hash failure on gcc 3.3.1 ++Fix problem reconnecting secondary mounts to same server after session ++failure. Fix invalid dentry - race in mkdir when directory gets created ++by another client between the lookup and mkdir. ++ ++Version 0.94 ++------------ ++Fix to list processing in reopen_files. Fix reconnection when server hung ++but tcpip session still alive. Set proper timeout on socket read. ++ ++Version 0.93 ++------------ ++Add missing mount options including iocharset. SMP fixes in write and open. ++Fix errors in reconnecting after TCP session failure. Fix module unloading ++of default nls codepage ++ ++Version 0.92 ++------------ ++Active smb transactions should never go negative (fix double FreeXid). Fix ++list processing in file routines. Check return code on kmalloc in open. ++Fix spinlock usage for SMP. ++ ++Version 0.91 ++------------ ++Fix oops in reopen_files when invalid dentry. drop dentry on server rename ++and on revalidate errors. Fix cases where pid is now tgid. Fix return code ++on create hard link when server does not support them. ++ ++Version 0.90 ++------------ ++Fix scheduling while atomic error in getting inode info on newly created file. ++Fix truncate of existing files opened with O_CREAT but not O_TRUNC set. ++ ++Version 0.89 ++------------ ++Fix oops on write to dead tcp session. Remove error log write for case when file open ++O_CREAT but not O_EXCL ++ ++Version 0.88 ++------------ ++Fix non-POSIX behavior on rename of open file and delete of open file by taking ++advantage of trans2 SetFileInfo rename facility if available on target server. ++Retry on ENOSPC and EAGAIN socket errors. ++ ++Version 0.87 ++------------ ++Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix ++allocation size miscalculation. After oplock token lost do not read through ++cache. ++ ++Version 0.86 ++------------ ++Fix oops on empty file readahead. Fix for file size handling for locally cached files. ++ ++Version 0.85 ++------------ ++Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files ++during auto reconnection to server after server recovered from failure. ++ ++Version 0.84 ++------------ ++Finish support for Linux 2.5 open/create changes, which removes the ++redundant NTCreate/QPathInfo/close that was sent during file create. ++Enable oplock by default. Enable packet signing by default (needed to ++access many recent Windows servers) ++ ++Version 0.83 ++------------ ++Fix oops when mounting to long server names caused by inverted parms to kmalloc. ++Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled ++we will choose a cifs user session (smb uid) that better matches the local ++uid if a) the mount uid does not match the current uid and b) we have another ++session to the same server (ip address) for a different mount which ++matches the current local uid. ++ ++Version 0.82 ++------------ ++Add support for mknod of block or character devices. Fix oplock ++code (distributed caching) to properly send response to oplock ++break from server. ++ ++Version 0.81 ++------------ ++Finish up CIFS packet digital signing for the default ++NTLM security case. This should help Windows 2003 ++network interoperability since it is common for ++packet signing to be required now. Fix statfs (stat -f) ++which recently started returning errors due to ++invalid value (-1 instead of 0) being set in the ++struct kstatfs f_ffiles field. ++ ++Version 0.80 ++----------- ++Fix oops on stopping oplock thread when removing cifs when ++built as module. ++ ++Version 0.79 ++------------ ++Fix mount options for ro (readonly), uid, gid and file and directory mode. ++ ++Version 0.78 ++------------ ++Fix errors displayed on failed mounts to be more understandable. ++Fixed various incorrect or misleading smb to posix error code mappings. ++ ++Version 0.77 ++------------ ++Fix display of NTFS DFS junctions to display as symlinks. ++They are the network equivalent. Fix oops in ++cifs_partialpagewrite caused by missing spinlock protection ++of openfile linked list. Allow writebehind caching errors to ++be returned to the application at file close. ++ ++Version 0.76 ++------------ ++Clean up options displayed in /proc/mounts by show_options to ++be more consistent with other filesystems. ++ ++Version 0.75 ++------------ ++Fix delete of readonly file to Windows servers. Reflect ++presence or absence of read only dos attribute in mode ++bits for servers that do not support CIFS Unix extensions. ++Fix shortened results on readdir of large directories to ++servers supporting CIFS Unix extensions (caused by ++incorrect resume key). ++ ++Version 0.74 ++------------ ++Fix truncate bug (set file size) that could cause hangs e.g. running fsx ++ ++Version 0.73 ++------------ ++unload nls if mount fails. ++ ++Version 0.72 ++------------ ++Add resume key support to search (readdir) code to workaround ++Windows bug. Add /proc/fs/cifs/LookupCacheEnable which ++allows disabling caching of attribute information for ++lookups. ++ ++Version 0.71 ++------------ ++Add more oplock handling (distributed caching code). Remove ++dead code. Remove excessive stack space utilization from ++symlink routines. ++ ++Version 0.70 ++------------ ++Fix oops in get dfs referral (triggered when null path sent in to ++mount). Add support for overriding rsize at mount time. ++ ++Version 0.69 ++------------ ++Fix buffer overrun in readdir which caused intermittent kernel oopses. ++Fix writepage code to release kmap on write data. Allow "-ip=" new ++mount option to be passed in on parameter distinct from the first part ++(server name portion of) the UNC name. Allow override of the ++tcp port of the target server via new mount option "-port=" ++ ++Version 0.68 ++------------ ++Fix search handle leak on rewind. Fix setuid and gid so that they are ++reflected in the local inode immediately. Cleanup of whitespace ++to make 2.4 and 2.5 versions more consistent. ++ ++ ++Version 0.67 ++------------ ++Fix signal sending so that captive thread (cifsd) exits on umount ++(which was causing the warning in kmem_cache_free of the request buffers ++at rmmod time). This had broken as a sideeffect of the recent global ++kernel change to daemonize. Fix memory leak in readdir code which ++showed up in "ls -R" (and applications that did search rewinding). ++ ++Version 0.66 ++------------ ++Reconnect tids and fids after session reconnection (still do not ++reconnect byte range locks though). Fix problem caching ++lookup information for directory inodes, improving performance, ++especially in deep directory trees. Fix various build warnings. ++ ++Version 0.65 ++------------ ++Finish fixes to commit write for caching/readahead consistency. fsx ++now works to Samba servers. Fix oops caused when readahead ++was interrupted by a signal. ++ ++Version 0.64 ++------------ ++Fix data corruption (in partial page after truncate) that caused fsx to ++fail to Windows servers. Cleaned up some extraneous error logging in ++common error paths. Add generic sendfile support. ++ ++Version 0.63 ++------------ ++Fix memory leak in AllocMidQEntry. ++Finish reconnection logic, so connection with server can be dropped ++(or server rebooted) and the cifs client will reconnect. ++ ++Version 0.62 ++------------ ++Fix temporary socket leak when bad userid or password specified ++(or other SMBSessSetup failure). Increase maximum buffer size to slightly ++over 16K to allow negotiation of up to Samba and Windows server default read ++sizes. Add support for readpages ++ ++Version 0.61 ++------------ ++Fix oops when username not passed in on mount. Extensive fixes and improvements ++to error logging (strip redundant newlines, change debug macros to ensure newline ++passed in and to be more consistent). Fix writepage wrong file handle problem, ++a readonly file handle could be incorrectly used to attempt to write out ++file updates through the page cache to multiply open files. This could cause ++the iozone benchmark to fail on the fwrite test. Fix bug mounting two different ++shares to the same Windows server when using different usernames ++(doing this to Samba servers worked but Windows was rejecting it) - now it is ++possible to use different userids when connecting to the same server from a ++Linux client. Fix oops when treeDisconnect called during unmount on ++previously freed socket. ++ ++Version 0.60 ++------------ ++Fix oops in readpages caused by not setting address space operations in inode in ++rare code path. ++ ++Version 0.59 ++------------ ++Includes support for deleting of open files and renaming over existing files (per POSIX ++requirement). Add readlink support for Windows junction points (directory symlinks). ++ ++Version 0.58 ++------------ ++Changed read and write to go through pagecache. Added additional address space operations. ++Memory mapped operations now working. ++ ++Version 0.57 ++------------ ++Added writepage code for additional memory mapping support. Fixed leak in xids causing ++the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on ++every stat call. Additional formatting cleanup. ++ ++Version 0.56 ++------------ ++Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup. ++ ++Version 0.55 ++------------ ++Fixes from Zwane Mwaikambo for adding missing return code checking in a few places. ++Also included a modified version of his fix to protect global list manipulation of ++the smb session and tree connection and mid related global variables. ++ ++Version 0.54 ++------------ ++Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre ++changes to superblock layout. Remove wasteful allocation of smb buffers (now the send ++buffer is reused for responses). Add more oplock handling. Additional minor cleanup. ++ ++Version 0.53 ++------------ ++More stylistic updates to better match kernel style. Add additional statistics ++for filesystem which can be viewed via /proc/fs/cifs. Add more pieces of NTLMv2 ++and CIFS Packet Signing enablement. ++ ++Version 0.52 ++------------ ++Replace call to sleep_on with safer wait_on_event. ++Make stylistic changes to better match kernel style recommendations. ++Remove most typedef usage (except for the PDUs themselves). ++ ++Version 0.51 ++------------ ++Update mount so the -unc mount option is no longer required (the ip address can be specified ++in a UNC style device name. Implementation of readpage/writepage started. ++ ++Version 0.50 ++------------ ++Fix intermittent problem with incorrect smb header checking on badly ++fragmented tcp responses ++ ++Version 0.49 ++------------ ++Fixes to setting of allocation size and file size. ++ ++Version 0.48 ++------------ ++Various 2.5.38 fixes. Now works on 2.5.38 ++ ++Version 0.47 ++------------ ++Prepare for 2.5 kernel merge. Remove ifdefs. ++ ++Version 0.46 ++------------ ++Socket buffer management fixes. Fix dual free. ++ ++Version 0.45 ++------------ ++Various big endian fixes for hardlinks and symlinks and also for dfs. ++ ++Version 0.44 ++------------ ++Various big endian fixes for servers with Unix extensions such as Samba ++ ++Version 0.43 ++------------ ++Various FindNext fixes for incorrect filenames on large directory searches on big endian ++clients. basic posix file i/o tests now work on big endian machines, not just le ++ ++Version 0.42 ++------------ ++SessionSetup and NegotiateProtocol now work from Big Endian machines. ++Various Big Endian fixes found during testing on the Linux on 390. Various fixes for compatibility with older ++versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7). ++ ++Version 0.41 ++------------ ++Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked ++files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. ++ ++Version 0.40 ++------------ ++Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate ++session advanced session authentication). Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP. ++Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs ++(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos). ++ ++Version 0.38 ++------------ ++Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable ++it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU). ++ ++Version 0.37 ++------------ ++Rewrote much of connection and mount/unmount logic to handle bugs with ++multiple uses to same share, multiple users to same server etc. ++ ++Version 0.36 ++------------ ++Fixed major problem with dentry corruption (missing call to dput) ++ ++Version 0.35 ++------------ ++Rewrite of readdir code to fix bug. Various fixes for bigendian machines. ++Begin adding oplock support. Multiusermount and oplockEnabled flags added to /proc/fs/cifs ++although corresponding function not fully implemented in the vfs yet ++ ++Version 0.34 ++------------ ++Fixed dentry caching bug, misc. cleanup ++ ++Version 0.33 ++------------ ++Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes. Now can build ++on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels. ++Support for STATUS codes (newer 32 bit NT error codes) added. DFS support begun to be added. ++ ++Version 0.32 ++------------ ++Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented ++and tested against Samba 2.2.5 ++ ++ ++Version 0.31 ++------------ ++1) Fixed lockrange to be correct (it was one byte too short) ++ ++2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly ++show range as locked when there is a conflict with an existing lock. ++ ++3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories ++in most cases. Eventually will offer optional ability to query server for the correct perms. ++ ++3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded ++but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb ++session) ++ ++4) Fixed error logging of valid mount options ++ ++5) Removed logging of password field. ++ ++6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c ++and cleaned them up and made them more consistent with other cifs functions. ++ ++7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways ++(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, ++nor is the symlink support using the Unix extensions ++ ++8) Started adding the readlink and follow_link code ++ ++Version 0.3 ++----------- ++Initial drop ++ +diff -urN linux-2.4.29.old/fs/cifs/cifs_debug.c linux-2.4.29/fs/cifs/cifs_debug.c +--- linux-2.4.29.old/fs/cifs/cifs_debug.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifs_debug.c 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,797 @@ ++/* ++ * fs/cifs_debug.c ++ * ++ * Copyright (C) International Business Machines Corp., 2000,2003 ++ * ++ * Modified by Steve French (sfrench@us.ibm.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/fs.h> ++#include <linux/string.h> ++#include <linux/ctype.h> ++#include <linux/module.h> ++#include <linux/proc_fs.h> ++#include <asm/uaccess.h> ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_debug.h" ++ ++void ++cifs_dump_mem(char *label, void *data, int length) ++{ ++ int i, j; ++ int *intptr = data; ++ char *charptr = data; ++ char buf[10], line[80]; ++ ++ printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", ++ label, length, data); ++ for (i = 0; i < length; i += 16) { ++ line[0] = 0; ++ for (j = 0; (j < 4) && (i + j * 4 < length); j++) { ++ sprintf(buf, " %08x", intptr[i / 4 + j]); ++ strcat(line, buf); ++ } ++ buf[0] = ' '; ++ buf[2] = 0; ++ for (j = 0; (j < 16) && (i + j < length); j++) { ++ buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.'; ++ strcat(line, buf); ++ } ++ printk(KERN_DEBUG "%s\n", line); ++ } ++} ++ ++#ifdef CONFIG_PROC_FS ++int ++cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, ++ int count, int *eof, void *data) ++{ ++ struct list_head *tmp; ++ struct list_head *tmp1; ++ struct mid_q_entry * mid_entry; ++ struct cifsSesInfo *ses; ++ struct cifsTconInfo *tcon; ++ int i; ++ int length = 0; ++ char * original_buf = buf; ++ ++ *beginBuffer = buf + offset; ++ ++ ++ length = ++ sprintf(buf, ++ "Display Internal CIFS Data Structures for Debugging\n" ++ "---------------------------------------------------\n"); ++ buf += length; ++ ++ length = sprintf(buf, "Servers:\n"); ++ buf += length; ++ ++ i = 0; ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(tmp, &GlobalSMBSessionList) { ++ i++; ++ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ++ length = ++ sprintf(buf, ++ "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP status: %d", ++ i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse), ++ ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus); ++ buf += length; ++ if(ses->server) { ++ buf += sprintf(buf, "\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", ++ atomic_read(&ses->server->socketUseCount), ++ ses->server->secMode, ++ atomic_read(&ses->server->inFlight)); ++ ++ length = sprintf(buf, "\nMIDs: \n"); ++ buf += length; ++ ++ spin_lock(&GlobalMid_Lock); ++ list_for_each(tmp1, &ses->server->pending_mid_q) { ++ mid_entry = list_entry(tmp1, struct ++ mid_q_entry, ++ qhead); ++ if(mid_entry) { ++ length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid); ++ buf += length; ++ } ++ } ++ spin_unlock(&GlobalMid_Lock); ++ } ++ ++ } ++ read_unlock(&GlobalSMBSeslock); ++ sprintf(buf, "\n"); ++ buf++; ++ ++ length = sprintf(buf, "\nShares:\n"); ++ buf += length; ++ ++ i = 0; ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(tmp, &GlobalTreeConnectionList) { ++ i++; ++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); ++ length = ++ sprintf(buf, ++ "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", ++ i, tcon->treeName, ++ atomic_read(&tcon->useCount), ++ tcon->nativeFileSystem, ++ tcon->fsDevInfo.DeviceCharacteristics, ++ tcon->fsAttrInfo.Attributes, ++ tcon->fsAttrInfo.MaxPathNameComponentLength,tcon->tidStatus); ++ buf += length; ++ if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_DISK) ++ length = sprintf(buf, " type: DISK "); ++ else if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_CD_ROM) ++ length = sprintf(buf, " type: CDROM "); ++ else ++ length = ++ sprintf(buf, " type: %d ", ++ tcon->fsDevInfo.DeviceType); ++ buf += length; ++ if(tcon->tidStatus == CifsNeedReconnect) { ++ buf += sprintf(buf, "\tDISCONNECTED "); ++ length += 14; ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ ++ length = sprintf(buf, "\n"); ++ buf += length; ++ ++ /* BB add code to dump additional info such as TCP session info now */ ++ /* Now calculate total size of returned data */ ++ length = buf - original_buf; ++ ++ if(offset + count >= length) ++ *eof = 1; ++ if(length < offset) { ++ *eof = 1; ++ return 0; ++ } else { ++ length = length - offset; ++ } ++ if (length > count) ++ length = count; ++ ++ return length; ++} ++ ++#ifdef CONFIG_CIFS_STATS ++int ++cifs_stats_read(char *buf, char **beginBuffer, off_t offset, ++ int count, int *eof, void *data) ++{ ++ int item_length,i,length; ++ struct list_head *tmp; ++ struct cifsTconInfo *tcon; ++ ++ *beginBuffer = buf + offset; ++ ++ length = sprintf(buf, ++ "Resources in use\nCIFS Session: %d\n", ++ sesInfoAllocCount.counter); ++ buf += length; ++ item_length = ++ sprintf(buf,"Share (unique mount targets): %d\n", ++ tconInfoAllocCount.counter); ++ length += item_length; ++ buf += item_length; ++ item_length = ++ sprintf(buf,"SMB Request/Response Buffer: %d\n", ++ bufAllocCount.counter); ++ length += item_length; ++ buf += item_length; ++ item_length = ++ sprintf(buf,"Operations (MIDs): %d\n", ++ midCount.counter); ++ length += item_length; ++ buf += item_length; ++ item_length = sprintf(buf, ++ "\n%d session %d share reconnects\n", ++ tcpSesReconnectCount.counter,tconInfoReconnectCount.counter); ++ length += item_length; ++ buf += item_length; ++ ++ item_length = sprintf(buf, ++ "Total vfs operations: %d maximum at one time: %d\n", ++ GlobalCurrentXid,GlobalMaxActiveXid); ++ length += item_length; ++ buf += item_length; ++ ++ i = 0; ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(tmp, &GlobalTreeConnectionList) { ++ i++; ++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); ++ item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName); ++ buf += item_length; ++ length += item_length; ++ if(tcon->tidStatus == CifsNeedReconnect) { ++ buf += sprintf(buf, "\tDISCONNECTED "); ++ length += 14; ++ } ++ item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", ++ atomic_read(&tcon->num_smbs_sent), ++ atomic_read(&tcon->num_oplock_brks)); ++ buf += item_length; ++ length += item_length; ++ item_length = sprintf(buf,"\nReads: %d Bytes %lld", ++ atomic_read(&tcon->num_reads), ++ (long long)(tcon->bytes_read)); ++ buf += item_length; ++ length += item_length; ++ item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", ++ atomic_read(&tcon->num_writes), ++ (long long)(tcon->bytes_written)); ++ buf += item_length; ++ length += item_length; ++ item_length = sprintf(buf, ++ "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", ++ atomic_read(&tcon->num_opens), ++ atomic_read(&tcon->num_deletes), ++ atomic_read(&tcon->num_mkdirs), ++ atomic_read(&tcon->num_rmdirs)); ++ buf += item_length; ++ length += item_length; ++ item_length = sprintf(buf, ++ "\nRenames: %d T2 Renames %d", ++ atomic_read(&tcon->num_renames), ++ atomic_read(&tcon->num_t2renames)); ++ buf += item_length; ++ length += item_length; ++ } ++ read_unlock(&GlobalSMBSeslock); ++ ++ buf += sprintf(buf,"\n"); ++ length++; ++ ++ if(offset + count >= length) ++ *eof = 1; ++ if(length < offset) { ++ *eof = 1; ++ return 0; ++ } else { ++ length = length - offset; ++ } ++ if (length > count) ++ length = count; ++ ++ return length; ++} ++#endif ++ ++struct proc_dir_entry *proc_fs_cifs; ++read_proc_t cifs_txanchor_read; ++static read_proc_t cifsFYI_read; ++static write_proc_t cifsFYI_write; ++static read_proc_t oplockEnabled_read; ++static write_proc_t oplockEnabled_write; ++static read_proc_t lookupFlag_read; ++static write_proc_t lookupFlag_write; ++static read_proc_t traceSMB_read; ++static write_proc_t traceSMB_write; ++static read_proc_t multiuser_mount_read; ++static write_proc_t multiuser_mount_write; ++static read_proc_t extended_security_read; ++static write_proc_t extended_security_write; ++static read_proc_t ntlmv2_enabled_read; ++static write_proc_t ntlmv2_enabled_write; ++static read_proc_t packet_signing_enabled_read; ++static write_proc_t packet_signing_enabled_write; ++static read_proc_t quotaEnabled_read; ++static write_proc_t quotaEnabled_write; ++static read_proc_t linuxExtensionsEnabled_read; ++static write_proc_t linuxExtensionsEnabled_write; ++ ++void ++cifs_proc_init(void) ++{ ++ struct proc_dir_entry *pde; ++ ++ proc_fs_cifs = proc_mkdir("cifs", proc_root_fs); ++ if (proc_fs_cifs == NULL) ++ return; ++ ++ proc_fs_cifs->owner = THIS_MODULE; ++ create_proc_read_entry("DebugData", 0, proc_fs_cifs, ++ cifs_debug_data_read, NULL); ++ ++#ifdef CONFIG_CIFS_STATS ++ create_proc_read_entry("Stats", 0, proc_fs_cifs, ++ cifs_stats_read, NULL); ++#endif ++ pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, ++ cifsFYI_read, NULL); ++ if (pde) ++ pde->write_proc = cifsFYI_write; ++ ++ pde = ++ create_proc_read_entry("traceSMB", 0, proc_fs_cifs, ++ traceSMB_read, NULL); ++ if (pde) ++ pde->write_proc = traceSMB_write; ++ ++ pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs, ++ oplockEnabled_read, NULL); ++ if (pde) ++ pde->write_proc = oplockEnabled_write; ++ ++ pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs, ++ quotaEnabled_read, NULL); ++ if (pde) ++ pde->write_proc = quotaEnabled_write; ++ ++ pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, ++ linuxExtensionsEnabled_read, NULL); ++ if (pde) ++ pde->write_proc = linuxExtensionsEnabled_write; ++ ++ pde = ++ create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs, ++ multiuser_mount_read, NULL); ++ if (pde) ++ pde->write_proc = multiuser_mount_write; ++ ++ pde = ++ create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, ++ extended_security_read, NULL); ++ if (pde) ++ pde->write_proc = extended_security_write; ++ ++ pde = ++ create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, ++ lookupFlag_read, NULL); ++ if (pde) ++ pde->write_proc = lookupFlag_write; ++ ++ pde = ++ create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, ++ ntlmv2_enabled_read, NULL); ++ if (pde) ++ pde->write_proc = ntlmv2_enabled_write; ++ ++ pde = ++ create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, ++ packet_signing_enabled_read, NULL); ++ if (pde) ++ pde->write_proc = packet_signing_enabled_write; ++} ++ ++void ++cifs_proc_clean(void) ++{ ++ if (proc_fs_cifs == NULL) ++ return; ++ ++ remove_proc_entry("DebugData", proc_fs_cifs); ++ remove_proc_entry("cifsFYI", proc_fs_cifs); ++ remove_proc_entry("traceSMB", proc_fs_cifs); ++#ifdef CONFIG_CIFS_STATS ++ remove_proc_entry("Stats", proc_fs_cifs); ++#endif ++ remove_proc_entry("MultiuserMount", proc_fs_cifs); ++ remove_proc_entry("OplockEnabled", proc_fs_cifs); ++ remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); ++ remove_proc_entry("ExtendedSecurity",proc_fs_cifs); ++ remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); ++ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); ++ remove_proc_entry("QuotaEnabled",proc_fs_cifs); ++ remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); ++ remove_proc_entry("cifs", proc_root_fs); ++} ++ ++static int ++cifsFYI_read(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", cifsFYI); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++cifsFYI_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ cifsFYI = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ cifsFYI = 1; ++ ++ return count; ++} ++ ++static int ++oplockEnabled_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", oplockEnabled); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++oplockEnabled_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ oplockEnabled = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ oplockEnabled = 1; ++ ++ return count; ++} ++ ++static int ++quotaEnabled_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", quotaEnabled); ++/* could also check if quotas are enabled in kernel ++ as a whole first */ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++quotaEnabled_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ quotaEnabled = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ quotaEnabled = 1; ++ ++ return count; ++} ++ ++static int ++linuxExtensionsEnabled_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", linuxExtEnabled); ++/* could also check if quotas are enabled in kernel ++ as a whole first */ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++linuxExtensionsEnabled_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ linuxExtEnabled = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ linuxExtEnabled = 1; ++ ++ return count; ++} ++ ++ ++static int ++lookupFlag_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", lookupCacheEnabled); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++lookupFlag_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ lookupCacheEnabled = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ lookupCacheEnabled = 1; ++ ++ return count; ++} ++static int ++traceSMB_read(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", traceSMB); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++traceSMB_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ traceSMB = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ traceSMB = 1; ++ ++ return count; ++} ++ ++static int ++multiuser_mount_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", multiuser_mount); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++multiuser_mount_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ multiuser_mount = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ multiuser_mount = 1; ++ ++ return count; ++} ++ ++static int ++extended_security_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", extended_security); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++extended_security_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ extended_security = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ extended_security = 1; ++ ++ return count; ++} ++ ++static int ++ntlmv2_enabled_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", ntlmv2_support); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++ntlmv2_enabled_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ ntlmv2_support = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ ntlmv2_support = 1; ++ ++ return count; ++} ++ ++static int ++packet_signing_enabled_read(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", sign_CIFS_PDUs); ++ ++ len -= off; ++ *start = page + off; ++ ++ if (len > count) ++ len = count; ++ else ++ *eof = 1; ++ ++ if (len < 0) ++ len = 0; ++ ++ return len; ++} ++static int ++packet_signing_enabled_write(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char c; ++ int rc; ++ ++ rc = get_user(c, buffer); ++ if (rc) ++ return rc; ++ if (c == '0' || c == 'n' || c == 'N') ++ sign_CIFS_PDUs = 0; ++ else if (c == '1' || c == 'y' || c == 'Y') ++ sign_CIFS_PDUs = 1; ++ else if (c == '2') ++ sign_CIFS_PDUs = 2; ++ ++ return count; ++} ++ ++ ++#endif +diff -urN linux-2.4.29.old/fs/cifs/cifs_debug.h linux-2.4.29/fs/cifs/cifs_debug.h +--- linux-2.4.29.old/fs/cifs/cifs_debug.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifs_debug.h 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,66 @@ ++/* ++ * ++ * Copyright (c) International Business Machines Corp., 2000,2002 ++ * Modified by Steve French (sfrench@us.ibm.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++*/ ++#define CIFS_DEBUG /* BB temporary */ ++ ++#ifndef _H_CIFS_DEBUG ++#define _H_CIFS_DEBUG ++ ++void cifs_dump_mem(char *label, void *data, int length); ++extern int traceSMB; /* flag which enables the function below */ ++void dump_smb(struct smb_hdr *, int); ++ ++/* ++ * debug ON ++ * -------- ++ */ ++#ifdef CIFS_DEBUG ++ ++ ++/* information message: e.g., configuration, major event */ ++extern int cifsFYI; ++#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) ++ ++#define cFYI(button,prspec) if (button) cifsfyi prspec ++ ++#define cifswarn(format, arg...) printk(KERN_WARNING ": " format "\n" , ## arg) ++ ++/* debug event message: */ ++extern int cifsERROR; ++ ++#define cEVENT(format,arg...) if (cifsERROR) printk(KERN_EVENT __FILE__ ": " format "\n" , ## arg) ++ ++/* error event message: e.g., i/o error */ ++#define cifserror(format,arg...) if (cifsERROR) printk(KERN_ERR " CIFS VFS: " format "\n" "" , ## arg) ++ ++#define cERROR(button, prspec) if (button) cifserror prspec ++ ++/* ++ * debug OFF ++ * --------- ++ */ ++#else /* _CIFS_DEBUG */ ++#define cERROR(button,prspec) ++#define cEVENT(format,arg...) ++#define cFYI(button, prspec) ++#define cifserror(format,arg...) ++#endif /* _CIFS_DEBUG */ ++ ++#endif /* _H_CIFS_DEBUG */ +diff -urN linux-2.4.29.old/fs/cifs/cifsencrypt.c linux-2.4.29/fs/cifs/cifsencrypt.c +--- linux-2.4.29.old/fs/cifs/cifsencrypt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifsencrypt.c 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,204 @@ ++/* ++ * fs/cifs/cifsencrypt.c ++ * ++ * Copyright (C) International Business Machines Corp., 2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/fs.h> ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifs_debug.h" ++#include "md5.h" ++#include "cifs_unicode.h" ++ ++/* Calculate and return the CIFS signature based on the mac key and the smb pdu */ ++/* the 16 byte signature must be allocated by the caller */ ++/* Note we only use the 1st eight bytes */ ++/* Note that the smb header signature field on input contains the ++ sequence number before this function is called */ ++ ++extern void mdfour(unsigned char *out, unsigned char *in, int n); ++extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); ++ ++static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) ++{ ++ struct MD5Context context; ++ ++ if((cifs_pdu == NULL) || (signature == NULL)) ++ return -EINVAL; ++ ++ MD5Init(&context); ++ MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); ++ MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); ++ MD5Final(signature,&context); ++ return 0; ++} ++ ++int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses, ++ __u32 * pexpected_response_sequence_number) ++{ ++ int rc = 0; ++ char smb_signature[20]; ++ ++ /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */ ++ /* BB remember to add code to save expected sequence number in midQ entry BB */ ++ ++ if((cifs_pdu == NULL) || (ses == NULL)) ++ return -EINVAL; ++ ++ if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0) ++ return rc; ++ ++ spin_lock(&GlobalMid_Lock); ++ cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number); ++ cifs_pdu->Signature.Sequence.Reserved = 0; ++ ++ *pexpected_response_sequence_number = ses->sequence_number++; ++ ses->sequence_number++; ++ spin_unlock(&GlobalMid_Lock); ++ ++ rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature); ++ if(rc) ++ memset(cifs_pdu->Signature.SecuritySignature, 0, 8); ++ else ++ memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); ++ ++ return rc; ++} ++ ++int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, ++ __u32 expected_sequence_number) ++{ ++ unsigned int rc; ++ char server_response_sig[8]; ++ char what_we_think_sig_should_be[20]; ++ ++ if((cifs_pdu == NULL) || (mac_key == NULL)) ++ return -EINVAL; ++ ++ if (cifs_pdu->Command == SMB_COM_NEGOTIATE) ++ return 0; ++ ++ if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) { ++ struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu; ++ if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE) ++ return 0; ++ } ++ ++ /* BB what if signatures are supposed to be on for session but server does not ++ send one? BB */ ++ ++ /* Do not need to verify session setups with signature "BSRSPYL " */ ++ if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0) ++ cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command)); ++ ++ expected_sequence_number = cpu_to_le32(expected_sequence_number); ++ ++ /* save off the origiginal signature so we can modify the smb and check ++ its signature against what the server sent */ ++ memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8); ++ ++ cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number; ++ cifs_pdu->Signature.Sequence.Reserved = 0; ++ ++ rc = cifs_calculate_signature(cifs_pdu, mac_key, ++ what_we_think_sig_should_be); ++ ++ if(rc) ++ return rc; ++ ++ ++/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */ ++ ++ if(memcmp(server_response_sig, what_we_think_sig_should_be, 8)) ++ return -EACCES; ++ else ++ return 0; ++ ++} ++ ++/* We fill in key by putting in 40 byte array which was allocated by caller */ ++int cifs_calculate_mac_key(char * key, const char * rn, const char * password) ++{ ++ char temp_key[16]; ++ if ((key == NULL) || (rn == NULL)) ++ return -EINVAL; ++ ++ E_md4hash(password, temp_key); ++ mdfour(key,temp_key,16); ++ memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE); ++ return 0; ++} ++ ++int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) ++{ ++ char temp_hash[16]; ++ struct HMACMD5Context ctx; ++ char * ucase_buf; ++ wchar_t * unicode_buf; ++ unsigned int i,user_name_len,dom_name_len; ++ ++ if(ses) ++ return -EINVAL; ++ ++ E_md4hash(ses->password, temp_hash); ++ ++ hmac_md5_init_limK_to_64(temp_hash, 16, &ctx); ++ user_name_len = strlen(ses->userName); ++ if(user_name_len > MAX_USERNAME_SIZE) ++ return -EINVAL; ++ dom_name_len = strlen(ses->domainName); ++ if(dom_name_len > MAX_USERNAME_SIZE) ++ return -EINVAL; ++ ++ ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL); ++ unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL); ++ ++ for(i=0;i<user_name_len;i++) ++ ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]]; ++ ucase_buf[i] = 0; ++ user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); ++ unicode_buf[user_name_len] = 0; ++ user_name_len++; ++ ++ for(i=0;i<dom_name_len;i++) ++ ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]]; ++ ucase_buf[i] = 0; ++ dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info); ++ ++ unicode_buf[user_name_len + dom_name_len] = 0; ++ hmac_md5_update((const unsigned char *) unicode_buf, ++ (user_name_len+dom_name_len)*2,&ctx); ++ ++ hmac_md5_final(ses->mac_signing_key,&ctx); ++ kfree(ucase_buf); ++ kfree(unicode_buf); ++ return 0; ++} ++void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) ++{ ++ struct HMACMD5Context context; ++ memcpy(v2_session_response + 8, ses->server->cryptKey,8); ++ /* gen_blob(v2_session_response + 16); */ ++ hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context); ++ ++ hmac_md5_update(ses->server->cryptKey,8,&context); ++/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ ++ ++ hmac_md5_final(v2_session_response,&context); ++} +diff -urN linux-2.4.29.old/fs/cifs/cifserr.c linux-2.4.29/fs/cifs/cifserr.c +--- linux-2.4.29.old/fs/cifs/cifserr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifserr.c 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,70 @@ ++/* ++ * fs/cifserr.c ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/errno.h> ++#include <linux/fs.h> ++#include <linux/smbno.h> ++#include "cifsfs.h" ++ ++int map_cifs_error(int error_class, int error_code, ++ int status_codes_negotiated) ++{ ++ ++ ++ if (status_codes_negotiated) { ++ switch (error_code) { ++ default: ++ return EIO; ++ } ++ } else ++ switch (error_class) { ++ case SUCCESS: ++ return 0; ++ ++ case ERRDOS: ++ switch (error_code) { ++ case ERRbadfunc: ++ return EINVAL; ++ default: ++ return EIO; ++ } ++ ++ case ERRSRV: ++ switch (error_code) { ++ default: ++ return EIO; ++ } ++ ++ case ERRHRD: ++ switch (error_code) { ++ default: ++ return EIO; ++ } ++ default: ++ return EIO; ++ } ++ return 0; ++} ++ ++int map_smb_error(int error_class, int error_code) ++{ ++ return map_cifs_error(error_class, error_code, FALSE); ++} +diff -urN linux-2.4.29.old/fs/cifs/cifsfs.c linux-2.4.29/fs/cifs/cifsfs.c +--- linux-2.4.29.old/fs/cifs/cifsfs.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifsfs.c 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,769 @@ ++/* ++ * fs/cifs/cifsfs.c ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2004 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * Common Internet FileSystem (CIFS) client ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++/* Note that BB means BUGBUG (ie something to fix eventually) */ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/mount.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/version.h> ++#include <linux/list.h> ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) ++#include <linux/seq_file.h> ++#endif ++#include <linux/vfs.h> ++#include "cifsfs.h" ++#include "cifspdu.h" ++#define DECLARE_GLOBALS_HERE ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_debug.h" ++#include "cifs_fs_sb.h" ++#include <linux/mm.h> ++#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */ ++/* BB when mempool_resize is added back in, we will resize pool on new mount */ ++#define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */ ++ ++#ifdef CONFIG_CIFS_QUOTA ++static struct quotactl_ops cifs_quotactl_ops; ++#endif ++ ++extern struct file_system_type cifs_fs_type; ++ ++int cifsFYI = 0; ++int cifsERROR = 1; ++int traceSMB = 0; ++unsigned int oplockEnabled = 1; ++unsigned int quotaEnabled = 0; ++unsigned int linuxExtEnabled = 1; ++unsigned int lookupCacheEnabled = 1; ++unsigned int multiuser_mount = 0; ++unsigned int extended_security = 0; ++unsigned int ntlmv2_support = 0; ++unsigned int sign_CIFS_PDUs = 1; ++unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE; ++struct task_struct * oplockThread = NULL; ++ ++extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, ++ const char *); ++extern int cifs_umount(struct super_block *, struct cifs_sb_info *); ++void cifs_proc_init(void); ++void cifs_proc_clean(void); ++ ++static DECLARE_COMPLETION(cifs_oplock_exited); ++ ++ ++struct super_block * ++cifs_read_super(struct super_block *sb, void *data, int silent) ++{ ++ struct inode *inode; ++ struct cifs_sb_info *cifs_sb; ++ int rc = 0; ++ ++ sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */ ++ cifs_sb = CIFS_SB(sb); ++ if(cifs_sb == NULL) ++ return 0; ++ else ++ memset(cifs_sb,0,sizeof(struct cifs_sb_info)); ++ ++ ++ rc = cifs_mount(sb, cifs_sb, data, NULL); ++ ++ if (rc) { ++ if (!silent) ++ cERROR(1, ++ ("cifs_mount failed w/return code = %d", rc)); ++ goto out_mount_failed; ++ } ++ ++ sb->s_magic = CIFS_MAGIC_NUMBER; ++ sb->s_op = &cifs_super_ops; ++/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512) ++ sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */ ++#ifdef CONFIG_CIFS_QUOTA ++ sb->s_qcop = &cifs_quotactl_ops; ++#endif ++ sb->s_blocksize = CIFS_MAX_MSGSIZE; ++ sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ ++ inode = iget(sb, ROOT_I); ++ ++ if (!inode) { ++ goto out_no_root; ++ } ++ ++ sb->s_root = d_alloc_root(inode); ++ ++ if (!sb->s_root) { ++ goto out_no_root; ++ } ++ ++ return sb; ++ ++out_no_root: ++ cERROR(1, ("cifs_read_super: get root inode failed")); ++ if (inode) ++ iput(inode); ++ ++out_mount_failed: ++ if(cifs_sb->local_nls) ++ unload_nls(cifs_sb->local_nls); ++ sb->s_dev = 0; ++ return 0; ++} ++ ++static void ++cifs_put_super(struct super_block *sb) ++{ ++ int rc = 0; ++ struct cifs_sb_info *cifs_sb; ++ ++ cFYI(1, ("In cifs_put_super")); ++ cifs_sb = CIFS_SB(sb); ++ if(cifs_sb == NULL) { ++ cFYI(1,("Empty cifs superblock info passed to unmount")); ++ return; ++ } ++ rc = cifs_umount(sb, cifs_sb); ++ if (rc) { ++ cERROR(1, ("cifs_umount failed with return code %d", rc)); ++ } ++ unload_nls(cifs_sb->local_nls); ++ return; ++} ++ ++static int ++cifs_statfs(struct super_block *sb, struct statfs *buf) ++{ ++ int xid, rc; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(sb); ++ pTcon = cifs_sb->tcon; ++ ++ buf->f_type = CIFS_MAGIC_NUMBER; ++ ++ /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */ ++ buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably ++ be length of total path, note that some servers may be ++ able to support more than this, but best to be safe ++ since Win2k and others can not handle very long filenames */ ++ buf->f_files = 0; /* undefined */ ++ buf->f_ffree = 0; /* unlimited */ ++ ++ rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls); ++ ++ /* ++ int f_type; ++ __fsid_t f_fsid; ++ int f_namelen; */ ++ /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */ ++ FreeXid(xid); ++ return 0; /* always return success? what if volume is no longer available? */ ++} ++ ++static int cifs_permission(struct inode * inode, int mask) ++{ ++ /* the server does permission checks, we do not need to do it here */ ++ return 0; ++} ++ ++kmem_cache_t *cifs_req_cachep; ++kmem_cache_t *cifs_mid_cachep; ++kmem_cache_t *cifs_oplock_cachep; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++static struct inode * ++cifs_alloc_inode(struct super_block *sb) ++{ ++ struct cifsInodeInfo *cifs_inode; ++ cifs_inode = ++ (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep, ++ SLAB_KERNEL); ++ if (!cifs_inode) ++ return NULL; ++ cifs_inode->cifsAttrs = 0x20; /* default */ ++ atomic_set(&cifs_inode->inUse, 0); ++ cifs_inode->time = 0; ++ /* Until the file is open and we have gotten oplock ++ info back from the server, can not assume caching of ++ file data or metadata */ ++ cifs_inode->clientCanCacheRead = FALSE; ++ cifs_inode->clientCanCacheAll = FALSE; ++ INIT_LIST_HEAD(&cifs_inode->openFileList); ++ return &cifs_inode->vfs_inode; ++} ++ ++static void ++cifs_destroy_inode(struct inode *inode) ++{ ++ kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); ++} ++#endif ++ ++/* ++ * cifs_show_options() is for displaying mount options in /proc/mounts. ++ * Not all settable options are displayed but most of the important ++ * ones are. ++ */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) ++static int ++cifs_show_options(struct seq_file *s, struct vfsmount *m) ++{ ++ struct cifs_sb_info *cifs_sb; ++ ++ cifs_sb = CIFS_SB(m->mnt_sb); ++ ++ if (cifs_sb) { ++ if (cifs_sb->tcon) { ++ seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); ++ if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName)) ++ seq_printf(s, ",username=%s", ++ cifs_sb->tcon->ses->userName); ++ if(cifs_sb->tcon->ses->domainName) ++ seq_printf(s, ",domain=%s", ++ cifs_sb->tcon->ses->domainName); ++ } ++ seq_printf(s, ",rsize=%d",cifs_sb->rsize); ++ seq_printf(s, ",wsize=%d",cifs_sb->wsize); ++ } ++ return 0; ++} ++#endif ++ ++#ifdef CONFIG_CIFS_QUOTA ++int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid, ++ struct fs_disk_quota * pdquota) ++{ ++ int xid; ++ int rc = 0; ++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ++ struct cifsTconInfo *pTcon; ++ ++ if(cifs_sb) ++ pTcon = cifs_sb->tcon; ++ else ++ return -EIO; ++ ++ ++ xid = GetXid(); ++ if(pTcon) { ++ cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); ++ } else { ++ return -EIO; ++ } ++ ++ FreeXid(xid); ++ return rc; ++} ++ ++int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid, ++ struct fs_disk_quota * pdquota) ++{ ++ int xid; ++ int rc = 0; ++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ++ struct cifsTconInfo *pTcon; ++ ++ if(cifs_sb) ++ pTcon = cifs_sb->tcon; ++ else ++ return -EIO; ++ ++ xid = GetXid(); ++ if(pTcon) { ++ cFYI(1,("set type: 0x%x id: %d",quota_type,qid)); ++ } else { ++ rc = -EIO; ++ } ++ ++ FreeXid(xid); ++ return rc; ++} ++ ++int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation) ++{ ++ int xid; ++ int rc = 0; ++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ++ struct cifsTconInfo *pTcon; ++ ++ if(cifs_sb) ++ pTcon = cifs_sb->tcon; ++ else ++ return -EIO; ++ ++ xid = GetXid(); ++ if(pTcon) { ++ cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation)); ++ } else { ++ rc = -EIO; ++ } ++ ++ FreeXid(xid); ++ return rc; ++} ++ ++int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats) ++{ ++ int xid; ++ int rc = 0; ++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ++ struct cifsTconInfo *pTcon; ++ ++ if(cifs_sb) { ++ pTcon = cifs_sb->tcon; ++ } else { ++ return -EIO; ++ } ++ xid = GetXid(); ++ if(pTcon) { ++ cFYI(1,("pqstats %p",qstats)); ++ } else { ++ rc = -EIO; ++ } ++ ++ FreeXid(xid); ++ return rc; ++} ++ ++static struct quotactl_ops cifs_quotactl_ops = { ++ .set_xquota = cifs_xquota_set, ++ .get_xquota = cifs_xquota_set, ++ .set_xstate = cifs_xstate_set, ++ .get_xstate = cifs_xstate_get, ++}; ++#endif ++ ++static int cifs_remount(struct super_block *sb, int *flags, char *data) ++{ ++ *flags |= MS_NODIRATIME; ++ return 0; ++} ++ ++struct super_operations cifs_super_ops = { ++ .read_inode = cifs_read_inode, ++ .put_super = cifs_put_super, ++ .statfs = cifs_statfs, ++/* .alloc_inode = cifs_alloc_inode, ++ .destroy_inode = cifs_destroy_inode, */ ++/* .drop_inode = generic_delete_inode, ++ .delete_inode = cifs_delete_inode, *//* Do not need the above two functions ++ unless later we add lazy close of inodes or unless the kernel forgets to call ++ us with the same number of releases (closes) as opens */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) ++ .show_options = cifs_show_options, ++#endif ++/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ ++}; ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++static struct super_block * ++cifs_get_sb(struct file_system_type *fs_type, ++ int flags, const char *dev_name, void *data) ++{ ++ int rc; ++ struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); ++ ++ cFYI(1, ("Devname: %s flags: %d ", dev_name, flags)); ++ ++ if (IS_ERR(sb)) ++ return sb; ++ ++ sb->s_flags = flags; ++ ++ rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0); ++ if (rc) { ++ up_write(&sb->s_umount); ++ deactivate_super(sb); ++ return ERR_PTR(rc); ++ } ++ sb->s_flags |= MS_ACTIVE; ++ return sb; ++} ++#endif ++ ++static ssize_t ++cifs_read_wrapper(struct file * file, char *read_data, size_t read_size, ++ loff_t * poffset) ++{ ++ if(file == NULL) ++ return -EIO; ++ else if(file->f_dentry == NULL) ++ return -EIO; ++ else if(file->f_dentry->d_inode == NULL) ++ return -EIO; ++ ++ if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { ++ return generic_file_read(file,read_data,read_size,poffset); ++ } else { ++ /* BB do we need to lock inode from here until after invalidate? */ ++/* if(file->f_dentry->d_inode->i_mapping) { ++ filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); ++ filemap_fdatawait(file->f_dentry->d_inode->i_mapping); ++ }*/ ++/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ ++ ++ /* BB we should make timer configurable - perhaps ++ by simply calling cifs_revalidate here */ ++ /* invalidate_remote_inode(file->f_dentry->d_inode);*/ ++ return generic_file_read(file,read_data,read_size,poffset); ++ } ++} ++ ++static ssize_t ++cifs_write_wrapper(struct file * file, const char *write_data, ++ size_t write_size, loff_t * poffset) ++{ ++ ssize_t written; ++ ++ if(file == NULL) ++ return -EIO; ++ else if(file->f_dentry == NULL) ++ return -EIO; ++ else if(file->f_dentry->d_inode == NULL) ++ return -EIO; ++ ++ /* check whether we can cache writes locally */ ++ written = generic_file_write(file,write_data,write_size,poffset); ++ if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { ++ if(file->f_dentry->d_inode->i_mapping) { ++ filemap_fdatasync(file->f_dentry->d_inode->i_mapping); ++ } ++ } ++ return written; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++static struct file_system_type cifs_fs_type = { ++ .owner = THIS_MODULE, ++ .name = "cifs", ++ .get_sb = cifs_get_sb, ++ .kill_sb = kill_anon_super, ++ /* .fs_flags */ ++}; ++#endif ++ ++static DECLARE_FSTYPE(cifs_fs_type, "cifs", cifs_read_super,0); ++ ++ ++struct inode_operations cifs_dir_inode_ops = { ++ .create = cifs_create, ++ .lookup = cifs_lookup, ++ .unlink = cifs_unlink, ++ .link = cifs_hardlink, ++ .mkdir = cifs_mkdir, ++ .rmdir = cifs_rmdir, ++ .rename = cifs_rename, ++ .permission = cifs_permission, ++ .revalidate = cifs_revalidate, ++ .setattr = cifs_setattr, ++ .symlink = cifs_symlink, ++ .mknod = cifs_mknod, ++}; ++ ++struct inode_operations cifs_file_inode_ops = { ++ .revalidate = cifs_revalidate, ++ .setattr = cifs_setattr, ++/* .getattr = cifs_getattr,*/ ++ .rename = cifs_rename, ++ .permission = cifs_permission, ++#ifdef CONFIG_CIFS_XATTR ++ .setxattr = cifs_setxattr, ++ .getxattr = cifs_getxattr, ++ .listxattr = cifs_listxattr, ++ .removexattr = cifs_removexattr, ++#endif ++}; ++ ++struct inode_operations cifs_symlink_inode_ops = { ++ .readlink = cifs_readlink, ++ .follow_link = cifs_follow_link, ++ .permission = cifs_permission, ++ /* BB add the following two eventually */ ++ /* revalidate: cifs_revalidate, ++ setattr: cifs_notify_change, *//* BB do we need notify change */ ++#ifdef CONFIG_CIFS_XATTR ++ .setxattr = cifs_setxattr, ++ .getxattr = cifs_getxattr, ++ .listxattr = cifs_listxattr, ++ .removexattr = cifs_removexattr, ++#endif ++}; ++ ++struct file_operations cifs_file_ops = { ++ .read = cifs_read_wrapper, ++ .write = cifs_write_wrapper, ++ .open = cifs_open, ++ .release = cifs_close, ++ .lock = cifs_lock, ++ .fsync = cifs_fsync, ++ .flush = cifs_flush, ++ .mmap = cifs_file_mmap, ++/* .sendfile = generic_file_sendfile,*/ ++#ifdef CONFIG_CIFS_FCNTL ++ .fcntl = cifs_fcntl, ++#endif ++}; ++ ++struct file_operations cifs_dir_ops = { ++ .readdir = cifs_readdir, ++ .release = cifs_closedir, ++ .read = generic_read_dir, ++#ifdef CONFIG_CIFS_FCNTL ++ .fcntl = cifs_fcntl, ++#endif ++}; ++/* ++static void ++cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags) ++{ ++ struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode; ++ ++ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) == ++ SLAB_CTOR_CONSTRUCTOR) { ++ inode_init_once(&cifsi->vfs_inode); ++ INIT_LIST_HEAD(&cifsi->lockList); ++ } ++} ++ ++static int ++cifs_init_inodecache(void) ++{ ++ cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", ++ sizeof (struct cifsInodeInfo), ++ 0, SLAB_HWCACHE_ALIGN, ++ cifs_init_once, NULL); ++ if (cifs_inode_cachep == NULL) ++ return -ENOMEM; ++ ++ ++ return 0; ++} ++ ++static void ++cifs_destroy_inodecache(void) ++{ ++ if (kmem_cache_destroy(cifs_inode_cachep)) ++ printk(KERN_WARNING "cifs_inode_cache: error freeing\n"); ++} */ ++ ++static int ++cifs_init_request_bufs(void) ++{ ++ cifs_req_cachep = kmem_cache_create("cifs_request", ++ CIFS_MAX_MSGSIZE + ++ MAX_CIFS_HDR_SIZE, 0, ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++ if (cifs_req_cachep == NULL) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++static void ++cifs_destroy_request_bufs(void) ++{ ++ if (kmem_cache_destroy(cifs_req_cachep)) ++ printk(KERN_WARNING ++ "cifs_destroy_request_cache: error not all structures were freed\n"); ++} ++ ++static int ++cifs_init_mids(void) ++{ ++ cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", ++ sizeof (struct mid_q_entry), 0, ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++ if (cifs_mid_cachep == NULL) ++ return -ENOMEM; ++ cifs_oplock_cachep = kmem_cache_create("cifs_oplock_struct", ++ sizeof (struct oplock_q_entry), 0, ++ SLAB_HWCACHE_ALIGN, NULL, NULL); ++ if (cifs_oplock_cachep == NULL) { ++ kmem_cache_destroy(cifs_mid_cachep); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void ++cifs_destroy_mids(void) ++{ ++ if (kmem_cache_destroy(cifs_mid_cachep)) ++ printk(KERN_WARNING ++ "cifs_destroy_mids: error not all structures were freed\n"); ++ if (kmem_cache_destroy(cifs_oplock_cachep)) ++ printk(KERN_WARNING ++ "error not all oplock structures were freed\n"); ++} ++ ++static int cifs_oplock_thread(void * dummyarg) ++{ ++ struct oplock_q_entry * oplock_item; ++ struct cifsTconInfo *pTcon; ++ struct inode * inode; ++ __u16 netfid; ++ int rc = 0; ++ ++ daemonize(); ++ sprintf(current->comm,"cifsoplockd"); ++ ++ oplockThread = current; ++ do { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ schedule_timeout(1*HZ); ++ spin_lock(&GlobalMid_Lock); ++ if(list_empty(&GlobalOplock_Q)) { ++ spin_unlock(&GlobalMid_Lock); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(39*HZ); ++ } else { ++ oplock_item = list_entry(GlobalOplock_Q.next, ++ struct oplock_q_entry, qhead); ++ if(oplock_item) { ++ cFYI(1,("found oplock item to write out")); ++ pTcon = oplock_item->tcon; ++ inode = oplock_item->pinode; ++ netfid = oplock_item->netfid; ++ spin_unlock(&GlobalMid_Lock); ++ DeleteOplockQEntry(oplock_item); ++ /* can not grab inode sem here since it would ++ deadlock when oplock received on delete ++ since vfs_unlink holds the i_sem across ++ the call */ ++ /* down(&inode->i_sem);*/ ++ if (S_ISREG(inode->i_mode)) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) ++ rc = filemap_fdatasync(inode->i_mapping); ++ if(rc) ++ CIFS_I(inode)->write_behind_rc = rc; ++#else ++ filemap_fdatasync(inode->i_mapping); ++#endif ++ if(CIFS_I(inode)->clientCanCacheRead == 0) ++ invalidate_inode_pages(inode); ++ } else ++ rc = 0; ++ /* releasing a stale oplock after recent reconnection ++ of smb session using a now incorrect file ++ handle is not a data integrity issue but do ++ not bother sending an oplock release if session ++ to server still is disconnected since oplock ++ already released by the server in that case */ ++ if(pTcon->tidStatus != CifsNeedReconnect) { ++ rc = CIFSSMBLock(0, pTcon, ++ netfid, ++ 0 /* len */ , 0 /* offset */, 0, ++ 0, LOCKING_ANDX_OPLOCK_RELEASE, ++ 0 /* wait flag */); ++ cFYI(1,("Oplock release rc = %d ",rc)); ++ } ++ } else ++ spin_unlock(&GlobalMid_Lock); ++ } ++ } while(!signal_pending(current)); ++ complete_and_exit (&cifs_oplock_exited, 0); ++} ++ ++static int __init ++init_cifs(void) ++{ ++ int rc = 0; ++#if CONFIG_PROC_FS ++ cifs_proc_init(); ++#endif ++ INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ ++ INIT_LIST_HEAD(&GlobalSMBSessionList); ++ INIT_LIST_HEAD(&GlobalTreeConnectionList); ++ INIT_LIST_HEAD(&GlobalOplock_Q); ++/* ++ * Initialize Global counters ++ */ ++ atomic_set(&sesInfoAllocCount, 0); ++ atomic_set(&tconInfoAllocCount, 0); ++ atomic_set(&tcpSesReconnectCount, 0); ++ atomic_set(&tconInfoReconnectCount, 0); ++ ++ atomic_set(&bufAllocCount, 0); ++ atomic_set(&midCount, 0); ++ GlobalCurrentXid = 0; ++ GlobalTotalActiveXid = 0; ++ GlobalMaxActiveXid = 0; ++ GlobalSMBSeslock = RW_LOCK_UNLOCKED; ++ GlobalMid_Lock = SPIN_LOCK_UNLOCKED; ++ ++/* rc = cifs_init_inodecache();*/ ++ if (!rc) { ++ rc = cifs_init_mids(); ++ if (!rc) { ++ rc = cifs_init_request_bufs(); ++ if (!rc) { ++ rc = register_filesystem(&cifs_fs_type); ++ if (!rc) { ++ kernel_thread(cifs_oplock_thread, NULL, ++ CLONE_FS | CLONE_FILES | CLONE_VM); ++ return rc; /* Success */ ++ } else ++ cifs_destroy_request_bufs(); ++ } ++ cifs_destroy_mids(); ++ } ++/* cifs_destroy_inodecache(); */ ++ } ++#if CONFIG_PROC_FS ++ cifs_proc_clean(); ++#endif ++ return rc; ++} ++ ++static void __exit ++exit_cifs(void) ++{ ++ cFYI(0, ("In unregister ie exit_cifs")); ++#if CONFIG_PROC_FS ++ cifs_proc_clean(); ++#endif ++ unregister_filesystem(&cifs_fs_type); ++/* cifs_destroy_inodecache();*/ ++ cifs_destroy_mids(); ++ cifs_destroy_request_bufs(); ++ if(oplockThread) { ++ send_sig(SIGTERM, oplockThread, 1); ++ wait_for_completion(&cifs_oplock_exited); ++ } ++} ++ ++MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); ++MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */ ++MODULE_DESCRIPTION ++ ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows"); ++module_init(init_cifs) ++module_exit(exit_cifs) +diff -urN linux-2.4.29.old/fs/cifs/cifsfs.h linux-2.4.29/fs/cifs/cifsfs.h +--- linux-2.4.29.old/fs/cifs/cifsfs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifsfs.h 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,97 @@ ++/* ++ * fs/cifs/cifsfs.h ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _CIFSFS_H ++#define _CIFSFS_H ++ ++#define ROOT_I 2 ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++extern int map_cifs_error(int error_class, int error_code, ++ int status_codes_negotiated); ++ ++extern struct address_space_operations cifs_addr_ops; ++ ++/* Functions related to super block operations */ ++extern struct super_operations cifs_super_ops; ++extern void cifs_put_inode(struct inode *); ++extern void cifs_read_inode(struct inode *); ++extern void cifs_delete_inode(struct inode *); ++/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ ++ ++/* Functions related to inodes */ ++extern struct inode_operations cifs_dir_inode_ops; ++extern int cifs_create(struct inode *, struct dentry *, int); ++extern struct dentry *cifs_lookup(struct inode *, struct dentry *); ++extern int cifs_unlink(struct inode *, struct dentry *); ++extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); ++extern int cifs_mknod(struct inode *, struct dentry *, int, int); ++extern int cifs_mkdir(struct inode *, struct dentry *, int); ++extern int cifs_rmdir(struct inode *, struct dentry *); ++extern int cifs_rename(struct inode *, struct dentry *, struct inode *, ++ struct dentry *); ++extern int cifs_revalidate(struct dentry *); ++extern int cifs_setattr(struct dentry *, struct iattr *); ++ ++extern struct inode_operations cifs_file_inode_ops; ++extern void cifs_truncate_file(struct inode *); ++extern struct inode_operations cifs_symlink_inode_ops; ++ ++/* Functions related to files and directories */ ++extern struct file_operations cifs_file_ops; ++extern int cifs_open(struct inode *inode, struct file *file); ++extern int cifs_close(struct inode *inode, struct file *file); ++extern int cifs_closedir(struct inode *inode, struct file *file); ++extern ssize_t cifs_read(struct file *file, char *read_data, ++ size_t read_size, loff_t * poffset); ++extern ssize_t cifs_write(struct file *file, const char *write_data, ++ size_t write_size, loff_t * poffset); ++extern int cifs_lock(struct file *, int, struct file_lock *); ++extern int cifs_fsync(struct file *, struct dentry *, int); ++extern int cifs_flush(struct file *); ++extern int cifs_file_mmap(struct file * , struct vm_area_struct *); ++extern struct file_operations cifs_dir_ops; ++extern int cifs_dir_open(struct inode *inode, struct file *file); ++extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir); ++extern long cifs_fcntl(int, unsigned int, unsigned long, struct file *); ++ ++/* Functions related to dir entries */ ++extern struct dentry_operations cifs_dentry_ops; ++ ++/* Functions related to symlinks */ ++extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd); ++extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen); ++extern int cifs_symlink(struct inode *inode, struct dentry *direntry, ++ const char *symname); ++extern int cifs_removexattr(struct dentry *, const char *); ++extern int cifs_setxattr(struct dentry *, const char *, const void *, ++ size_t, int); ++extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); ++extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); ++#define CIFS_VERSION "1.20" ++#endif /* _CIFSFS_H */ +diff -urN linux-2.4.29.old/fs/cifs/cifs_fs_sb.h linux-2.4.29/fs/cifs/cifs_fs_sb.h +--- linux-2.4.29.old/fs/cifs/cifs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifs_fs_sb.h 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,32 @@ ++/* ++ * fs/cifs/cifs_fs_sb.h ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ */ ++#ifndef _CIFS_FS_SB_H ++#define _CIFS_FS_SB_H ++ ++struct cifs_sb_info { ++ struct cifsTconInfo *tcon; /* primary mount */ ++ struct list_head nested_tcon_q; ++ struct nls_table *local_nls; ++ unsigned int rsize; ++ unsigned int wsize; ++ uid_t mnt_uid; ++ gid_t mnt_gid; ++ mode_t mnt_file_mode; ++ mode_t mnt_dir_mode; ++}; ++#endif /* _CIFS_FS_SB_H */ +diff -urN linux-2.4.29.old/fs/cifs/cifsglob.h linux-2.4.29/fs/cifs/cifsglob.h +--- linux-2.4.29.old/fs/cifs/cifsglob.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifsglob.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,413 @@ ++/* ++ * fs/cifs/cifsglob.h ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ */ ++#include <linux/in.h> ++#include <linux/in6.h> ++#include "cifs_fs_sb.h" ++/* ++ * The sizes of various internal tables and strings ++ */ ++#define MAX_UID_INFO 16 ++#define MAX_SES_INFO 2 ++#define MAX_TCON_INFO 4 ++ ++#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1 ++#define MAX_SERVER_SIZE 15 ++#define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */ ++#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null ++ termination then *2 for unicode versions */ ++#define MAX_PASSWORD_SIZE 16 ++ ++/* ++ * MAX_REQ is the maximum number of requests that WE will send ++ * on one socket concurently. It also matches the most common ++ * value of max multiplex returned by servers. We may ++ * eventually want to use the negotiated value (in case ++ * future servers can handle more) when we are more confident that ++ * we will not have problems oveloading the socket with pending ++ * write data. ++ */ ++#define CIFS_MAX_REQ 50 ++ ++#define SERVER_NAME_LENGTH 15 ++#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) ++ ++/* used to define string lengths for reversing unicode strings */ ++/* (256+1)*2 = 514 */ ++/* (max path length + 1 for null) * 2 for unicode */ ++#define MAX_NAME 514 ++ ++#include "cifspdu.h" ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++#ifndef XATTR_DOS_ATTRIB ++#define XATTR_DOS_ATTRIB "user.DOSATTRIB" ++#endif ++ ++/* ++ * This information is kept on every Server we know about. ++ * ++ * Some things to note: ++ * ++ */ ++#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1) ++ ++/* ++ * CIFS vfs client Status information (based on what we know.) ++ */ ++ ++ /* associated with each tcp and smb session */ ++enum statusEnum { ++ CifsNew = 0, ++ CifsGood, ++ CifsExiting, ++ CifsNeedReconnect ++}; ++ ++enum securityEnum { ++ NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */ ++ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ ++ RawNTLMSSP, /* NTLMSSP without SPNEGO */ ++ NTLMSSP, /* NTLMSSP via SPNEGO */ ++ Kerberos /* Kerberos via SPNEGO */ ++}; ++ ++enum protocolEnum { ++ IPV4 = 0, ++ IPV6, ++ SCTP ++ /* Netbios frames protocol not supported at this time */ ++}; ++ ++/* ++ ***************************************************************** ++ * Except the CIFS PDUs themselves all the ++ * globally interesting structs should go here ++ ***************************************************************** ++ */ ++ ++struct TCP_Server_Info { ++ char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ ++ char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ ++ struct socket *ssocket; ++ union { ++ struct sockaddr_in sockAddr; ++ struct sockaddr_in6 sockAddr6; ++ } addr; ++ wait_queue_head_t response_q; ++ wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ ++ struct list_head pending_mid_q; ++ void *Server_NlsInfo; /* BB - placeholder for future NLS info */ ++ unsigned short server_codepage; /* codepage for the server */ ++ unsigned long ip_address; /* IP addr for the server if known */ ++ enum protocolEnum protocolType; ++ char versionMajor; ++ char versionMinor; ++ int svlocal:1; /* local server or remote */ ++ atomic_t socketUseCount; /* number of open cifs sessions on socket */ ++ atomic_t inFlight; /* number of requests on the wire to server */ ++ enum statusEnum tcpStatus; /* what we think the status is */ ++ struct semaphore tcpSem; ++ struct task_struct *tsk; ++ char server_GUID[16]; ++ char secMode; ++ enum securityEnum secType; ++ unsigned int maxReq; /* Clients should submit no more */ ++ /* than maxReq distinct unanswered SMBs to the server when using */ ++ /* multiplexed reads or writes */ ++ unsigned int maxBuf; /* maxBuf specifies the maximum */ ++ /* message size the server can send or receive for non-raw SMBs */ ++ unsigned int maxRw; /* maxRw specifies the maximum */ ++ /* message size the server can send or receive for */ ++ /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */ ++ char sessid[4]; /* unique token id for this session */ ++ /* (returned on Negotiate */ ++ int capabilities; /* allow selective disabling of caps by smb sess */ ++ __u16 timeZone; ++ char cryptKey[CIFS_CRYPTO_KEY_SIZE]; ++ char workstation_RFC1001_name[16]; /* 16th byte is always zero */ ++}; ++ ++/* ++ * The following is our shortcut to user information. We surface the uid, ++ * and name. We always get the password on the fly in case it ++ * has changed. We also hang a list of sessions owned by this user off here. ++ */ ++struct cifsUidInfo { ++ struct list_head userList; ++ struct list_head sessionList; /* SMB sessions for this user */ ++ uid_t linux_uid; ++ char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */ ++ /* BB may need ptr or callback for PAM or WinBind info */ ++}; ++ ++/* ++ * Session structure. One of these for each uid session with a particular host ++ */ ++struct cifsSesInfo { ++ struct list_head cifsSessionList; ++ struct semaphore sesSem; ++ struct cifsUidInfo *uidInfo; /* pointer to user info */ ++ struct TCP_Server_Info *server; /* pointer to server info */ ++ atomic_t inUse; /* # of mounts (tree connections) on this ses */ ++ enum statusEnum status; ++ __u32 sequence_number; /* needed for CIFS PDU signature */ ++ __u16 ipc_tid; /* special tid for connection to IPC share */ ++ char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; ++ char *serverOS; /* name of operating system underlying the server */ ++ char *serverNOS; /* name of network operating system that the server is running */ ++ char *serverDomain; /* security realm of server */ ++ int Suid; /* remote smb uid */ ++ uid_t linux_uid; /* local Linux uid */ ++ int capabilities; ++ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ ++ char userName[MAX_USERNAME_SIZE + 1]; ++ char domainName[MAX_USERNAME_SIZE + 1]; ++ char * password; ++}; ++ ++/* ++ * there is one of these for each connection to a resource on a particular ++ * session ++ */ ++struct cifsTconInfo { ++ struct list_head cifsConnectionList; ++ struct list_head openFileList; ++ struct semaphore tconSem; ++ struct cifsSesInfo *ses; /* pointer to session associated with */ ++ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ ++ char *nativeFileSystem; ++ __u16 tid; /* The 2 byte tree id */ ++ __u16 Flags; /* optional support bits */ ++ enum statusEnum tidStatus; ++ atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ ++#ifdef CONFIG_CIFS_STATS ++ atomic_t num_smbs_sent; ++ atomic_t num_writes; ++ atomic_t num_reads; ++ atomic_t num_oplock_brks; ++ atomic_t num_opens; ++ atomic_t num_deletes; ++ atomic_t num_mkdirs; ++ atomic_t num_rmdirs; ++ atomic_t num_renames; ++ atomic_t num_t2renames; ++ __u64 bytes_read; ++ __u64 bytes_written; ++ spinlock_t stat_lock; ++#endif ++ FILE_SYSTEM_DEVICE_INFO fsDevInfo; ++ FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ ++ FILE_SYSTEM_UNIX_INFO fsUnixInfo; ++ int retry:1; ++ /* BB add field for back pointer to sb struct? */ ++}; ++ ++/* ++ * This info hangs off the cifsFileInfo structure. This is used to track ++ * byte stream locks on the file ++ */ ++struct cifsLockInfo { ++ struct cifsLockInfo *next; ++ int start; ++ int length; ++ int type; ++}; ++ ++/* ++ * One of these for each open instance of a file ++ */ ++struct cifsFileInfo { ++ struct list_head tlist; /* pointer to next fid owned by tcon */ ++ struct list_head flist; /* next fid (file instance) for this inode */ ++ unsigned int uid; /* allows finding which FileInfo structure */ ++ __u32 pid; /* process id who opened file */ ++ __u16 netfid; /* file id from remote */ ++ /* BB add lock scope info here if needed */ ; ++ /* lock scope id (0 if none) */ ++ struct file * pfile; /* needed for writepage */ ++ struct inode * pInode; /* needed for oplock break */ ++ int endOfSearch:1; /* we have reached end of search */ ++ int closePend:1; /* file is marked to close */ ++ int emptyDir:1; ++ int invalidHandle:1; /* file closed via session abend */ ++ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ ++ char * search_resume_name; ++ unsigned int resume_name_length; ++ __u32 resume_key; ++}; ++ ++/* ++ * One of these for each file inode ++ */ ++ ++struct cifsInodeInfo { ++ struct list_head lockList; ++ /* BB add in lists for dirty pages - i.e. write caching info for oplock */ ++ struct list_head openFileList; ++ int write_behind_rc; ++ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ ++ atomic_t inUse; /* num concurrent users (local openers cifs) of file*/ ++ unsigned long time; /* jiffies of last update/check of inode */ ++ int clientCanCacheRead:1; /* read oplock */ ++ int clientCanCacheAll:1; /* read and writebehind oplock */ ++ int oplockPending:1; ++ struct inode vfs_inode; ++}; ++ ++static inline struct cifsInodeInfo * CIFS_I(struct inode *inode) ++{ ++ return (struct cifsInodeInfo *)&(inode->u); ++} ++ ++static inline struct cifs_sb_info * CIFS_SB(struct super_block *sb) ++{ ++ return (struct cifs_sb_info *) &(sb->u); ++} ++ ++ ++/* one of these for every pending CIFS request to the server */ ++struct mid_q_entry { ++ struct list_head qhead; /* mids waiting on reply from this server */ ++ __u16 mid; /* multiplex id */ ++ __u16 pid; /* process id */ ++ __u32 sequence_number; /* for CIFS signing */ ++ __u16 command; /* smb command code */ ++ struct timeval when_sent; /* time when smb sent */ ++ struct cifsSesInfo *ses; /* smb was sent to this server */ ++ struct task_struct *tsk; /* task waiting for response */ ++ struct smb_hdr *resp_buf; /* response buffer */ ++ int midState; /* wish this were enum but can not pass to wait_event */ ++}; ++ ++struct oplock_q_entry { ++ struct list_head qhead; ++ struct inode * pinode; ++ struct cifsTconInfo * tcon; ++ __u16 netfid; ++}; ++ ++#define MID_FREE 0 ++#define MID_REQUEST_ALLOCATED 1 ++#define MID_REQUEST_SUBMITTED 2 ++#define MID_RESPONSE_RECEIVED 4 ++#define MID_RETRY_NEEDED 8 /* session closed while this request out */ ++ ++/* ++ ***************************************************************** ++ * All constants go here ++ ***************************************************************** ++ */ ++ ++#define UID_HASH (16) ++ ++/* ++ * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the ++ * following to be declared. ++ */ ++ ++/**************************************************************************** ++ * Locking notes. All updates to global variables and lists should be ++ * protected by spinlocks or semaphores. ++ * ++ * Spinlocks ++ * --------- ++ * GlobalMid_Lock protects: ++ * list operations on pending_mid_q and oplockQ ++ * updates to XID counters, multiplex id and SMB sequence numbers ++ * GlobalSMBSesLock protects: ++ * list operations on tcp and SMB session lists and tCon lists ++ * f_owner.lock protects certain per file struct operations ++ * mapping->page_lock protects certain per page operations ++ * ++ * Semaphores ++ * ---------- ++ * sesSem operations on smb session ++ * tconSem operations on tree connection ++ * fh_sem file handle reconnection operations ++ * ++ ****************************************************************************/ ++ ++#ifdef DECLARE_GLOBALS_HERE ++#define GLOBAL_EXTERN ++#else ++#define GLOBAL_EXTERN extern ++#endif ++ ++/* ++ * The list of servers that did not respond with NT LM 0.12. ++ * This list helps improve performance and eliminate the messages indicating ++ * that we had a communications error talking to the server in this list. ++ */ ++GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ ++ ++/* ++ * The following is a hash table of all the users we know about. ++ */ ++GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; ++ ++GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */ ++GLOBAL_EXTERN struct list_head GlobalSMBSessionList; ++GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; ++GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ ++ ++GLOBAL_EXTERN struct list_head GlobalOplock_Q; ++ ++/* ++ * Global transaction id (XID) information ++ */ ++GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ ++GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ ++GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ ++GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ ++ /* on midQ entries */ ++GLOBAL_EXTERN char Local_System_Name[15]; ++ ++/* ++ * Global counters, updated atomically ++ */ ++GLOBAL_EXTERN atomic_t sesInfoAllocCount; ++GLOBAL_EXTERN atomic_t tconInfoAllocCount; ++ ++GLOBAL_EXTERN atomic_t tcpSesReconnectCount; ++GLOBAL_EXTERN atomic_t tconInfoReconnectCount; ++ ++/* Various Debug counters to remove someday (BB) */ ++GLOBAL_EXTERN atomic_t bufAllocCount; ++GLOBAL_EXTERN atomic_t midCount; ++ ++/* Misc globals */ ++GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions ++ to be established on existing mount if we ++ have the uid/password or Kerberos credential ++ or equivalent for current user */ ++GLOBAL_EXTERN unsigned int oplockEnabled; ++GLOBAL_EXTERN unsigned int quotaEnabled; ++GLOBAL_EXTERN unsigned int lookupCacheEnabled; ++GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent ++ with more secure ntlmssp2 challenge/resp */ ++GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */ ++GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ ++GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */ ++ +diff -urN linux-2.4.29.old/fs/cifs/cifspdu.h linux-2.4.29/fs/cifs/cifspdu.h +--- linux-2.4.29.old/fs/cifs/cifspdu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifspdu.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,1793 @@ ++/* ++ * fs/cifs/cifspdu.h ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _CIFSPDU_H ++#define _CIFSPDU_H ++ ++#include <net/sock.h> ++ ++#define CIFS_PROT 0 ++#define BAD_PROT CIFS_PROT+1 ++ ++/* SMB command codes */ ++#define SMB_COM_CREATE_DIRECTORY 0x00 ++#define SMB_COM_DELETE_DIRECTORY 0x01 ++#define SMB_COM_CLOSE 0x04 ++#define SMB_COM_DELETE 0x06 ++#define SMB_COM_RENAME 0x07 ++#define SMB_COM_LOCKING_ANDX 0x24 ++#define SMB_COM_COPY 0x29 ++#define SMB_COM_READ_ANDX 0x2E ++#define SMB_COM_WRITE_ANDX 0x2F ++#define SMB_COM_TRANSACTION2 0x32 ++#define SMB_COM_TRANSACTION2_SECONDARY 0x33 ++#define SMB_COM_FIND_CLOSE2 0x34 ++#define SMB_COM_TREE_DISCONNECT 0x71 ++#define SMB_COM_NEGOTIATE 0x72 ++#define SMB_COM_SESSION_SETUP_ANDX 0x73 ++#define SMB_COM_LOGOFF_ANDX 0x74 ++#define SMB_COM_TREE_CONNECT_ANDX 0x75 ++#define SMB_COM_NT_TRANSACT 0xA0 ++#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 ++#define SMB_COM_NT_CREATE_ANDX 0xA2 ++#define SMB_COM_NT_RENAME 0xA5 ++ ++/* Transact2 subcommand codes */ ++#define TRANS2_OPEN 0x00 ++#define TRANS2_FIND_FIRST 0x01 ++#define TRANS2_FIND_NEXT 0x02 ++#define TRANS2_QUERY_FS_INFORMATION 0x03 ++#define TRANS2_QUERY_PATH_INFORMATION 0x05 ++#define TRANS2_SET_PATH_INFORMATION 0x06 ++#define TRANS2_QUERY_FILE_INFORMATION 0x07 ++#define TRANS2_SET_FILE_INFORMATION 0x08 ++#define TRANS2_GET_DFS_REFERRAL 0x10 ++#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11 ++ ++/* NT Transact subcommand codes */ ++#define NT_TRANSACT_CREATE 0x01 ++#define NT_TRANSACT_IOCTL 0x02 ++#define NT_TRANSACT_SET_SECURITY_DESC 0x03 ++#define NT_TRANSACT_NOTIFY_CHANGE 0x04 ++#define NT_TRANSACT_RENAME 0x05 ++#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06 ++#define NT_TRANSACT_GET_USER_QUOTA 0x07 ++#define NT_TRANSACT_SET_USER_QUOTA 0x08 ++ ++#define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */ ++ ++/* internal cifs vfs structures */ ++/***************************************************************** ++ * All constants go here ++ ***************************************************************** ++ */ ++ ++/* ++ * Starting value for maximum SMB size negotiation ++ */ ++#define CIFS_MAX_MSGSIZE (4*4096) ++ ++/* ++ * Size of encrypted user password in bytes ++ */ ++#define CIFS_ENCPWD_SIZE (16) ++ ++/* ++ * Size of the crypto key returned on the negotiate SMB in bytes ++ */ ++#define CIFS_CRYPTO_KEY_SIZE (8) ++ ++/* ++ * Size of the session key (crypto key encrypted with the password ++ */ ++#define CIFS_SESSION_KEY_SIZE (24) ++ ++/* ++ * Maximum user name length ++ */ ++#define CIFS_UNLEN (20) ++ ++/* ++ * Flags on SMB open ++ */ ++#define SMBOPEN_WRITE_THROUGH 0x4000 ++#define SMBOPEN_DENY_ALL 0x0010 ++#define SMBOPEN_DENY_WRITE 0x0020 ++#define SMBOPEN_DENY_READ 0x0030 ++#define SMBOPEN_DENY_NONE 0x0040 ++#define SMBOPEN_READ 0x0000 ++#define SMBOPEN_WRITE 0x0001 ++#define SMBOPEN_READWRITE 0x0002 ++#define SMBOPEN_EXECUTE 0x0003 ++ ++#define SMBOPEN_OCREATE 0x0010 ++#define SMBOPEN_OTRUNC 0x0002 ++#define SMBOPEN_OAPPEND 0x0001 ++ ++/* ++ * SMB flag definitions ++ */ ++#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */ ++#define SMBFLG_RCV_POSTED 0x02 /* obsolete */ ++#define SMBFLG_RSVD 0x04 ++#define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */ ++#define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ ++#define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ ++#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ ++#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */ ++ ++/* ++ * SMB flag2 definitions ++ */ ++#define SMBFLG2_KNOWS_LONG_NAMES 0x0001 /* can send long (non-8.3) path names in response */ ++#define SMBFLG2_KNOWS_EAS 0x0002 ++#define SMBFLG2_SECURITY_SIGNATURE 0x0004 ++#define SMBFLG2_IS_LONG_NAME 0x0040 ++#define SMBFLG2_EXT_SEC 0x0800 ++#define SMBFLG2_DFS 0x1000 ++#define SMBFLG2_PAGING_IO 0x2000 ++#define SMBFLG2_ERR_STATUS 0x4000 ++#define SMBFLG2_UNICODE 0x8000 ++ ++/* ++ * These are the file access permission bits defined in CIFS for the ++ * NTCreateAndX as well as the level 0x107 ++ * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO ++ * responds with the AccessFlags. ++ * The AccessFlags specifies the access permissions a caller has to the ++ * file and can have any suitable combination of the following values: ++ */ ++ ++#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ ++#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ ++#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ ++#define FILE_READ_EA 0x00000008 /* Extended attributes associated */ ++ /* with the file can be read */ ++#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ ++ /* with the file can be written */ ++#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ ++ /* the file using system paging I/O */ ++#define FILE_DELETE_CHILD 0x00000040 ++#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ ++ /* file can be read */ ++#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ ++ /* file can be written */ ++#define DELETE 0x00010000 /* The file can be deleted */ ++#define READ_CONTROL 0x00020000 /* The access control list and */ ++ /* ownership associated with the */ ++ /* file can be read */ ++#define WRITE_DAC 0x00040000 /* The access control list and */ ++ /* ownership associated with the */ ++ /* file can be written. */ ++#define WRITE_OWNER 0x00080000 /* Ownership information associated */ ++ /* with the file can be written */ ++#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ ++ /* synchronize with the completion */ ++ /* of an input/output request */ ++#define GENERIC_ALL 0x10000000 ++#define GENERIC_EXECUTE 0x20000000 ++#define GENERIC_WRITE 0x40000000 ++#define GENERIC_READ 0x80000000 ++ /* In summary - Relevant file */ ++ /* access flags from CIFS are */ ++ /* file_read_data, file_write_data */ ++ /* file_execute, file_read_attributes */ ++ /* write_dac, and delete. */ ++ ++/* ++ * Invalid readdir handle ++ */ ++#define CIFS_NO_HANDLE 0xFFFF ++ ++/* IPC$ in ASCII */ ++#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" ++ ++/* IPC$ in Unicode */ ++#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00" ++ ++/* Unicode Null terminate 2 bytes of 0 */ ++#define UNICODE_NULL "\x00\x00" ++#define ASCII_NULL 0x00 ++ ++/* ++ * Server type values (returned on EnumServer API ++ */ ++#define CIFS_SV_TYPE_DC 0x00000008 ++#define CIFS_SV_TYPE_BACKDC 0x00000010 ++ ++/* ++ * Alias type flags (From EnumAlias API call ++ */ ++#define CIFS_ALIAS_TYPE_FILE 0x0001 ++#define CIFS_SHARE_TYPE_FILE 0x0000 ++ ++/* ++ * File Attribute flags ++ */ ++#define ATTR_READONLY 0x0001 ++#define ATTR_HIDDEN 0x0002 ++#define ATTR_SYSTEM 0x0004 ++#define ATTR_VOLUME 0x0008 ++#define ATTR_DIRECTORY 0x0010 ++#define ATTR_ARCHIVE 0x0020 ++#define ATTR_DEVICE 0x0040 ++#define ATTR_NORMAL 0x0080 ++#define ATTR_TEMPORARY 0x0100 ++#define ATTR_SPARSE 0x0200 ++#define ATTR_REPARSE 0x0400 ++#define ATTR_COMPRESSED 0x0800 ++#define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */ ++#define ATTR_NOT_CONTENT_INDEXED 0x2000 ++#define ATTR_ENCRYPTED 0x4000 ++#define ATTR_POSIX_SEMANTICS 0x01000000 ++#define ATTR_BACKUP_SEMANTICS 0x02000000 ++#define ATTR_DELETE_ON_CLOSE 0x04000000 ++#define ATTR_SEQUENTIAL_SCAN 0x08000000 ++#define ATTR_RANDOM_ACCESS 0x10000000 ++#define ATTR_NO_BUFFERING 0x20000000 ++#define ATTR_WRITE_THROUGH 0x80000000 ++ ++/* ShareAccess flags */ ++#define FILE_NO_SHARE 0x00000000 ++#define FILE_SHARE_READ 0x00000001 ++#define FILE_SHARE_WRITE 0x00000002 ++#define FILE_SHARE_DELETE 0x00000004 ++#define FILE_SHARE_ALL 0x00000007 ++ ++/* CreateDisposition flags */ ++#define FILE_SUPERSEDE 0x00000000 ++#define FILE_OPEN 0x00000001 ++#define FILE_CREATE 0x00000002 ++#define FILE_OPEN_IF 0x00000003 ++#define FILE_OVERWRITE 0x00000004 ++#define FILE_OVERWRITE_IF 0x00000005 ++ ++/* CreateOptions */ ++#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ ++#define CREATE_WRITE_THROUGH 0x00000002 ++#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ ++#define CREATE_RANDOM_ACCESS 0x00000800 ++#define CREATE_DELETE_ON_CLOSE 0x00001000 ++#define OPEN_REPARSE_POINT 0x00200000 ++ ++/* ImpersonationLevel flags */ ++#define SECURITY_ANONYMOUS 0 ++#define SECURITY_IDENTIFICATION 1 ++#define SECURITY_IMPERSONATION 2 ++#define SECURITY_DELEGATION 3 ++ ++/* SecurityFlags */ ++#define SECURITY_CONTEXT_TRACKING 0x01 ++#define SECURITY_EFFECTIVE_ONLY 0x02 ++ ++/* ++ * Default PID value, used in all SMBs where the PID is not important ++ */ ++#define CIFS_DFT_PID 0x1234 ++ ++/* ++ * We use the same routine for Copy and Move SMBs. This flag is used to ++ * distinguish ++ */ ++#define CIFS_COPY_OP 1 ++#define CIFS_RENAME_OP 2 ++ ++#define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ ++#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ ++ ++#pragma pack(1) ++ ++struct smb_hdr { ++ __u32 smb_buf_length; /* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */ ++ __u8 Protocol[4]; ++ __u8 Command; ++ union { ++ struct { ++ __u8 ErrorClass; ++ __u8 Reserved; ++ __u16 Error; /* note: treated as little endian (le) on wire */ ++ } DosError; ++ __u32 CifsError; /* note: le */ ++ } Status; ++ __u8 Flags; ++ __u16 Flags2; /* note: le */ ++ __u16 PidHigh; /* note: le */ ++ union { ++ struct { ++ __u32 SequenceNumber; /* le */ ++ __u32 Reserved; /* zero */ ++ } Sequence; ++ __u8 SecuritySignature[8]; /* le */ ++ } Signature; ++ __u8 pad[2]; ++ __u16 Tid; ++ __u16 Pid; /* note: le */ ++ __u16 Uid; ++ __u16 Mid; ++ __u8 WordCount; ++}; ++/* given a pointer to an smb_hdr retrieve the value of byte count */ ++#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) ++ ++/* given a pointer to an smb_hdr retrieve the pointer to the byte area */ ++#define pByteArea(smb_var) ((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) ++ ++/* ++ * Computer Name Length ++ */ ++#define CNLEN 15 ++ ++/* ++ * Share Name Length @S8A ++ * Note: This length is limited by the SMB used to get @S8A ++ * the Share info. NetShareEnum only returns 13 @S8A ++ * chars, including the null termination. @S8A ++ */ ++#define SNLEN 12 /*@S8A */ ++ ++/* ++ * Comment Length ++ */ ++#define MAXCOMMENTLEN 40 ++ ++/* ++ * The OS/2 maximum path name ++ */ ++#define MAX_PATHCONF 256 ++ ++/* ++ * SMB frame definitions (following must be packed structs) ++ * See the SNIA CIFS Specification for details. ++ * ++ * The Naming convention is the lower case version of the ++ * smb command code name for the struct and this is typedef to the ++ * uppercase version of the same name with the prefix SMB_ removed ++ * for brevity. Although typedefs are not commonly used for ++ * structure definitions in the Linux kernel, their use in the ++ * CIFS standards document, which this code is based on, may ++ * make this one of the cases where typedefs for structures make ++ * sense to improve readability for readers of the standards doc. ++ * Typedefs can always be removed later if they are too distracting ++ * and they are only used for the CIFSs PDUs themselves, not ++ * internal cifs vfs structures ++ * ++ */ ++ ++typedef struct negotiate_req { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; ++ unsigned char DialectsArray[1]; ++} NEGOTIATE_REQ; ++ ++typedef struct negotiate_rsp { ++ struct smb_hdr hdr; /* wct = 17 */ ++ __u16 DialectIndex; ++ __u8 SecurityMode; ++ __u16 MaxMpxCount; ++ __u16 MaxNumberVcs; ++ __u32 MaxBufferSize; ++ __u32 MaxRawSize; ++ __u32 SessionKey; ++ __u32 Capabilities; /* see below */ ++ __u32 SystemTimeLow; ++ __u32 SystemTimeHigh; ++ __u16 ServerTimeZone; ++ __u8 EncryptionKeyLength; ++ __u16 ByteCount; ++ union { ++ unsigned char EncryptionKey[1]; /* if cap extended security is off */ ++ /* followed by Domain name - if extended security is off */ ++ /* followed by 16 bytes of server GUID */ ++ /* followed by security blob if cap_extended_security negotiated */ ++ struct { ++ unsigned char GUID[16]; ++ unsigned char SecurityBlob[1]; ++ } extended_response; ++ } u; ++} NEGOTIATE_RSP; ++ ++/* SecurityMode bits */ ++#define SECMODE_USER 0x01 /* off indicates share level security */ ++#define SECMODE_PW_ENCRYPT 0x02 ++#define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */ ++#define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */ ++ ++/* Negotiate response Capabilities */ ++#define CAP_RAW_MODE 0x00000001 ++#define CAP_MPX_MODE 0x00000002 ++#define CAP_UNICODE 0x00000004 ++#define CAP_LARGE_FILES 0x00000008 ++#define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */ ++#define CAP_RPC_REMOTE_APIS 0x00000020 ++#define CAP_STATUS32 0x00000040 ++#define CAP_LEVEL_II_OPLOCKS 0x00000080 ++#define CAP_LOCK_AND_READ 0x00000100 ++#define CAP_NT_FIND 0x00000200 ++#define CAP_DFS 0x00001000 ++#define CAP_INFOLEVEL_PASSTHRU 0x00002000 ++#define CAP_LARGE_READ_X 0x00004000 ++#define CAP_LARGE_WRITE_X 0x00008000 ++#define CAP_UNIX 0x00800000 ++#define CAP_RESERVED 0x02000000 ++#define CAP_BULK_TRANSFER 0x20000000 ++#define CAP_COMPRESSED_DATA 0x40000000 ++#define CAP_EXTENDED_SECURITY 0x80000000 ++ ++typedef union smb_com_session_setup_andx { ++ struct { /* request format */ ++ struct smb_hdr hdr; /* wct = 12 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 MaxBufferSize; ++ __u16 MaxMpxCount; ++ __u16 VcNumber; ++ __u32 SessionKey; ++ __u16 SecurityBlobLength; ++ __u32 Reserved; ++ __u32 Capabilities; /* see below */ ++ __u16 ByteCount; ++ unsigned char SecurityBlob[1]; /* followed by */ ++ /* STRING NativeOS */ ++ /* STRING NativeLanMan */ ++ } req; /* NTLM request format (with extended security */ ++ ++ struct { /* request format */ ++ struct smb_hdr hdr; /* wct = 13 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 MaxBufferSize; ++ __u16 MaxMpxCount; ++ __u16 VcNumber; ++ __u32 SessionKey; ++ __u16 CaseInsensitivePasswordLength; /* ASCII password length */ ++ __u16 CaseSensitivePasswordLength; /* Unicode password length */ ++ __u32 Reserved; /* see below */ ++ __u32 Capabilities; ++ __u16 ByteCount; ++ unsigned char CaseInsensitivePassword[1]; /* followed by: */ ++ /* unsigned char * CaseSensitivePassword; */ ++ /* STRING AccountName */ ++ /* STRING PrimaryDomain */ ++ /* STRING NativeOS */ ++ /* STRING NativeLanMan */ ++ } req_no_secext; /* NTLM request format (without extended security */ ++ ++ struct { /* default (NTLM) response format */ ++ struct smb_hdr hdr; /* wct = 4 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Action; /* see below */ ++ __u16 SecurityBlobLength; ++ __u16 ByteCount; ++ unsigned char SecurityBlob[1]; /* followed by */ ++/* unsigned char * NativeOS; */ ++/* unsigned char * NativeLanMan; */ ++/* unsigned char * PrimaryDomain; */ ++ } resp; /* NTLM response format (with or without extended security */ ++ ++ struct { /* request format */ ++ struct smb_hdr hdr; /* wct = 10 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 MaxBufferSize; ++ __u16 MaxMpxCount; ++ __u16 VcNumber; ++ __u32 SessionKey; ++ __u16 PassswordLength; ++ __u32 Reserved; ++ __u16 ByteCount; ++ unsigned char AccountPassword[1]; /* followed by */ ++ /* STRING AccountName */ ++ /* STRING PrimaryDomain */ ++ /* STRING NativeOS */ ++ /* STRING NativeLanMan */ ++ } old_req; /* pre-NTLM (LANMAN2.1) request format */ ++ ++ struct { /* default (NTLM) response format */ ++ struct smb_hdr hdr; /* wct = 3 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Action; /* see below */ ++ __u16 ByteCount; ++ unsigned char NativeOS[1]; /* followed by */ ++/* unsigned char * NativeLanMan; */ ++/* unsigned char * PrimaryDomain; */ ++ } old_resp; /* pre-NTLM (LANMAN2.1) response format */ ++} SESSION_SETUP_ANDX; ++ ++#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" ++ ++/* Capabilities bits (for NTLM SessSetup request) */ ++#define CAP_UNICODE 0x00000004 ++#define CAP_LARGE_FILES 0x00000008 ++#define CAP_NT_SMBS 0x00000010 ++#define CAP_STATUS32 0x00000040 ++#define CAP_LEVEL_II_OPLOCKS 0x00000080 ++#define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */ ++#define CAP_BULK_TRANSFER 0x20000000 ++#define CAP_EXTENDED_SECURITY 0x80000000 ++ ++/* Action bits */ ++#define GUEST_LOGIN 1 ++ ++typedef struct smb_com_tconx_req { ++ struct smb_hdr hdr; /* wct = 4 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Flags; /* see below */ ++ __u16 PasswordLength; ++ __u16 ByteCount; ++ unsigned char Password[1]; /* followed by */ ++/* STRING Path *//* \\server\share name */ ++ /* STRING Service */ ++} TCONX_REQ; ++ ++typedef struct smb_com_tconx_rsp { ++ struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 OptionalSupport; /* see below */ ++ __u16 ByteCount; ++ unsigned char Service[1]; /* always ASCII, not Unicode */ ++ /* STRING NativeFileSystem */ ++} TCONX_RSP; ++ ++/* tree connect Flags */ ++#define DISCONNECT_TID 0x0001 ++#define TCON_EXTENDED_SECINFO 0x0008 ++/* OptionalSupport bits */ ++#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */ ++#define SMB_SHARE_IS_IN_DFS 0x0002 ++ ++typedef struct smb_com_logoff_andx_req { ++ ++ struct smb_hdr hdr; /* wct = 2 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 ByteCount; ++} LOGOFF_ANDX_REQ; ++ ++typedef struct smb_com_logoff_andx_rsp { ++ struct smb_hdr hdr; /* wct = 2 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 ByteCount; ++} LOGOFF_ANDX_RSP; ++ ++typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ ++ struct { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; /* bcc = 0 */ ++ } req; ++ struct { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; /* bcc = 0 */ ++ } resp; ++} TREE_DISCONNECT; ++ ++typedef struct smb_com_close_req { ++ struct smb_hdr hdr; /* wct = 3 */ ++ __u16 FileID; ++ __u32 LastWriteTime; /* should be zero */ ++ __u16 ByteCount; /* 0 */ ++} CLOSE_REQ; ++ ++typedef struct smb_com_close_rsp { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; /* bct = 0 */ ++} CLOSE_RSP; ++ ++typedef struct smb_com_findclose_req { ++ struct smb_hdr hdr; /* wct = 1 */ ++ __u16 FileID; ++ __u16 ByteCount; /* 0 */ ++} FINDCLOSE_REQ; ++ ++/* OpenFlags */ ++#define REQ_OPLOCK 0x00000002 ++#define REQ_BATCHOPLOCK 0x00000004 ++#define REQ_OPENDIRONLY 0x00000008 ++ ++typedef struct smb_com_open_req { /* also handles create */ ++ struct smb_hdr hdr; /* wct = 24 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u8 Reserved; /* Must Be Zero */ ++ __u16 NameLength; ++ __u32 OpenFlags; ++ __u32 RootDirectoryFid; ++ __u32 DesiredAccess; ++ __u64 AllocationSize; ++ __u32 FileAttributes; ++ __u32 ShareAccess; ++ __u32 CreateDisposition; ++ __u32 CreateOptions; ++ __u32 ImpersonationLevel; ++ __u8 SecurityFlags; ++ __u16 ByteCount; ++ char fileName[1]; ++} OPEN_REQ; ++ ++/* open response: oplock levels */ ++#define OPLOCK_NONE 0 ++#define OPLOCK_EXCLUSIVE 1 ++#define OPLOCK_BATCH 2 ++#define OPLOCK_READ 3 /* level 2 oplock */ ++ ++/* open response for CreateAction shifted left */ ++#define CIFS_CREATE_ACTION 0x20000 /* file created */ ++ ++typedef struct smb_com_open_rsp { ++ struct smb_hdr hdr; /* wct = 34 BB */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u8 OplockLevel; ++ __u16 Fid; ++ __u32 CreateAction; ++ __u64 CreationTime; ++ __u64 LastAccessTime; ++ __u64 LastWriteTime; ++ __u64 ChangeTime; ++ __u32 FileAttributes; ++ __u64 AllocationSize; ++ __u64 EndOfFile; ++ __u16 FileType; ++ __u16 DeviceState; ++ __u8 DirectoryFlag; ++ __u16 ByteCount; /* bct = 0 */ ++} OPEN_RSP; ++ ++typedef struct smb_com_write_req { ++ struct smb_hdr hdr; /* wct = 14 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Fid; ++ __u32 OffsetLow; ++ __u32 Reserved; ++ __u16 WriteMode; ++ __u16 Remaining; ++ __u16 DataLengthHigh; ++ __u16 DataLengthLow; ++ __u16 DataOffset; ++ __u32 OffsetHigh; ++ __u16 ByteCount; ++ __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ ++ char Data[1]; ++} WRITE_REQ; ++ ++typedef struct smb_com_write_rsp { ++ struct smb_hdr hdr; /* wct = 6 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Count; ++ __u16 Remaining; ++ __u32 Reserved; ++ __u16 ByteCount; ++} WRITE_RSP; ++ ++typedef struct smb_com_read_req { ++ struct smb_hdr hdr; /* wct = 12 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Fid; ++ __u32 OffsetLow; ++ __u16 MaxCount; ++ __u16 MinCount; /* obsolete */ ++ __u32 MaxCountHigh; ++ __u16 Remaining; ++ __u32 OffsetHigh; ++ __u16 ByteCount; ++} READ_REQ; ++ ++typedef struct smb_com_read_rsp { ++ struct smb_hdr hdr; /* wct = 12 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Remaining; ++ __u16 DataCompactionMode; ++ __u16 Reserved; ++ __u16 DataLength; ++ __u16 DataOffset; ++ __u16 DataLengthHigh; ++ __u64 Reserved2; ++ __u16 ByteCount; ++ __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ ++ char Data[1]; ++} READ_RSP; ++ ++typedef struct locking_andx_range { ++ __u16 Pid; ++ __u16 Pad; ++ __u32 OffsetHigh; ++ __u32 OffsetLow; ++ __u32 LengthHigh; ++ __u32 LengthLow; ++} LOCKING_ANDX_RANGE; ++ ++#define LOCKING_ANDX_SHARED_LOCK 0x01 ++#define LOCKING_ANDX_OPLOCK_RELEASE 0x02 ++#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 ++#define LOCKING_ANDX_CANCEL_LOCK 0x08 ++#define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */ ++ ++typedef struct smb_com_lock_req { ++ struct smb_hdr hdr; /* wct = 8 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 Fid; ++ __u8 LockType; ++ __u8 OplockLevel; ++ __u32 Timeout; ++ __u16 NumberOfUnlocks; ++ __u16 NumberOfLocks; ++ __u16 ByteCount; ++ LOCKING_ANDX_RANGE Locks[1]; ++} LOCK_REQ; ++ ++typedef struct smb_com_lock_rsp { ++ struct smb_hdr hdr; /* wct = 2 */ ++ __u8 AndXCommand; ++ __u8 AndXReserved; ++ __u16 AndXOffset; ++ __u16 ByteCount; ++} LOCK_RSP; ++ ++typedef struct smb_com_rename_req { ++ struct smb_hdr hdr; /* wct = 1 */ ++ __u16 SearchAttributes; /* target file attributes */ ++ __u16 ByteCount; ++ __u8 BufferFormat; /* 4 = ASCII or Unicode */ ++ unsigned char OldFileName[1]; ++ /* followed by __u8 BufferFormat2 */ ++ /* followed by NewFileName */ ++} RENAME_REQ; ++ ++ /* copy request flags */ ++#define COPY_MUST_BE_FILE 0x0001 ++#define COPY_MUST_BE_DIR 0x0002 ++#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */ ++#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */ ++#define COPY_VERIFY_WRITES 0x0010 ++#define COPY_TREE 0x0020 ++ ++typedef struct smb_com_copy_req { ++ struct smb_hdr hdr; /* wct = 3 */ ++ __u16 Tid2; ++ __u16 OpenFunction; ++ __u16 Flags; ++ __u16 ByteCount; ++ __u8 BufferFormat; /* 4 = ASCII or Unicode */ ++ unsigned char OldFileName[1]; ++ /* followed by __u8 BufferFormat2 */ ++ /* followed by NewFileName string */ ++} COPY_REQ; ++ ++typedef struct smb_com_copy_rsp { ++ struct smb_hdr hdr; /* wct = 1 */ ++ __u16 CopyCount; /* number of files copied */ ++ __u16 ByteCount; /* may be zero */ ++ __u8 BufferFormat; /* 0x04 - only present if errored file follows */ ++ unsigned char ErrorFileName[1]; /* only present if error in copy */ ++} COPY_RSP; ++ ++#define CREATE_HARD_LINK 0x103 ++#define MOVEFILE_COPY_ALLOWED 0x0002 ++#define MOVEFILE_REPLACE_EXISTING 0x0001 ++ ++typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ ++ struct smb_hdr hdr; /* wct = 4 */ ++ __u16 SearchAttributes; /* target file attributes */ ++ __u16 Flags; /* spec says Information Level */ ++ __u32 ClusterCount; ++ __u16 ByteCount; ++ __u8 BufferFormat; /* 4 = ASCII or Unicode */ ++ unsigned char OldFileName[1]; ++ /* followed by __u8 BufferFormat2 */ ++ /* followed by NewFileName */ ++} NT_RENAME_REQ; ++ ++typedef struct smb_com_rename_rsp { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; /* bct = 0 */ ++} RENAME_RSP; ++ ++typedef struct smb_com_delete_file_req { ++ struct smb_hdr hdr; /* wct = 1 */ ++ __u16 SearchAttributes; ++ __u16 ByteCount; ++ __u8 BufferFormat; /* 4 = ASCII */ ++ unsigned char fileName[1]; ++} DELETE_FILE_REQ; ++ ++typedef struct smb_com_delete_file_rsp { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; /* bct = 0 */ ++} DELETE_FILE_RSP; ++ ++typedef struct smb_com_delete_directory_req { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; ++ __u8 BufferFormat; /* 4 = ASCII */ ++ unsigned char DirName[1]; ++} DELETE_DIRECTORY_REQ; ++ ++typedef struct smb_com_delete_directory_rsp { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; /* bct = 0 */ ++} DELETE_DIRECTORY_RSP; ++ ++typedef struct smb_com_create_directory_req { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; ++ __u8 BufferFormat; /* 4 = ASCII */ ++ unsigned char DirName[1]; ++} CREATE_DIRECTORY_REQ; ++ ++typedef struct smb_com_create_directory_rsp { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 ByteCount; /* bct = 0 */ ++} CREATE_DIRECTORY_RSP; ++ ++/***************************************************/ ++/* NT Transact structure defintions follow */ ++/* Currently only ioctl and notify are implemented */ ++/***************************************************/ ++typedef struct smb_com_transaction_ioctl_req { ++ struct smb_hdr hdr; /* wct = 23 */ ++ __u8 MaxSetupCount; ++ __u16 Reserved; ++ __u32 TotalParameterCount; ++ __u32 TotalDataCount; ++ __u32 MaxParameterCount; ++ __u32 MaxDataCount; ++ __u32 ParameterCount; ++ __u32 ParameterOffset; ++ __u32 DataCount; ++ __u32 DataOffset; ++ __u8 SetupCount; /* four setup words follow subcommand */ ++ /* SNIA spec incorrectly included spurious pad here */ ++ __u16 SubCommand;/* 2 = IOCTL/FSCTL */ ++ __u32 FunctionCode; ++ __u16 Fid; ++ __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/ ++ __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/ ++ __u16 ByteCount; ++ __u8 Pad[3]; ++ __u8 Data[1]; ++} TRANSACT_IOCTL_REQ; ++ ++typedef struct smb_com_transaction_ioctl_rsp { ++ struct smb_hdr hdr; /* wct = 19 */ ++ __u8 Reserved[3]; ++ __u32 TotalParameterCount; ++ __u32 TotalDataCount; ++ __u32 ParameterCount; ++ __u32 ParameterOffset; ++ __u32 ParameterDisplacement; ++ __u32 DataCount; ++ __u32 DataOffset; ++ __u32 DataDisplacement; ++ __u8 SetupCount; /* 1 */ ++ __u16 ReturnedDataLen; ++ __u16 ByteCount; ++ __u8 Pad[3]; ++} TRANSACT_IOCTL_RSP; ++ ++typedef struct smb_com_transaction_change_notify_req { ++ struct smb_hdr hdr; /* wct = 23 */ ++ __u8 MaxSetupCount; ++ __u16 Reserved; ++ __u32 TotalParameterCount; ++ __u32 TotalDataCount; ++ __u32 MaxParameterCount; ++ __u32 MaxDataCount; ++ __u32 ParameterCount; ++ __u32 ParameterOffset; ++ __u32 DataCount; ++ __u32 DataOffset; ++ __u8 SetupCount; /* four setup words follow subcommand */ ++ /* SNIA spec incorrectly included spurious pad here */ ++ __u16 SubCommand;/* 4 = Change Notify */ ++ __u32 CompletionFilter; /* operation to monitor */ ++ __u16 Fid; ++ __u8 WatchTree; /* 1 = Monitor subdirectories */ ++ __u8 Reserved2; ++ __u16 ByteCount; ++/* __u8 Pad[3];*/ ++/* __u8 Data[1];*/ ++} TRANSACT_CHANGE_NOTIFY_REQ; ++ ++typedef struct smb_com_transaction_change_notify_rsp { ++ struct smb_hdr hdr; /* wct = 18 */ ++ __u8 Reserved[3]; ++ __u32 TotalParameterCount; ++ __u32 TotalDataCount; ++ __u32 ParameterCount; ++ __u32 ParameterOffset; ++ __u32 ParameterDisplacement; ++ __u32 DataCount; ++ __u32 DataOffset; ++ __u32 DataDisplacement; ++ __u8 SetupCount; /* 0 */ ++ __u16 ByteCount; ++ /* __u8 Pad[3]; */ ++} TRANSACT_CHANGE_NOTIFY_RSP; ++/* Completion Filter flags for Notify */ ++#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 ++#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 ++#define FILE_NOTIFY_CHANGE_NAME 0x00000003 ++#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 ++#define FILE_NOTIFY_CHANGE_SIZE 0x00000008 ++#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 ++#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 ++#define FILE_NOTIFY_CHANGE_CREATION 0x00000040 ++#define FILE_NOTIFY_CHANGE_EA 0x00000080 ++#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100 ++#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 ++#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 ++#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 ++ ++#define FILE_ACTION_ADDED 0x00000001 ++#define FILE_ACTION_REMOVED 0x00000002 ++#define FILE_ACTION_MODIFIED 0x00000003 ++#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004 ++#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005 ++#define FILE_ACTION_ADDED_STREAM 0x00000006 ++#define FILE_ACTION_REMOVED_STREAM 0x00000007 ++#define FILE_ACTION_MODIFIED_STREAM 0x00000008 ++ ++/* response contains array of the following structures */ ++struct file_notify_information { ++ __u32 NextEntryOffset; ++ __u32 Action; ++ __u32 FileNameLength; ++ __u8 FileName[1]; ++}; ++ ++struct reparse_data { ++ __u32 ReparseTag; ++ __u16 ReparseDataLength; ++ __u16 Reserved; ++ __u16 AltNameOffset; ++ __u16 AltNameLen; ++ __u16 TargetNameOffset; ++ __u16 TargetNameLen; ++ char LinkNamesBuf[1]; ++}; ++ ++struct cifs_quota_data { ++ __u32 rsrvd1; /* 0 */ ++ __u32 sid_size; ++ __u64 rsrvd2; /* 0 */ ++ __u64 space_used; ++ __u64 soft_limit; ++ __u64 hard_limit; ++ char sid[1]; /* variable size? */ ++}; ++ ++/* quota sub commands */ ++#define QUOTA_LIST_CONTINUE 0 ++#define QUOTA_LIST_START 0x100 ++#define QUOTA_FOR_SID 0x101 ++ ++typedef union smb_com_transaction2 { ++ struct { ++ struct smb_hdr hdr; /* wct = 14+ */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; ++ __u8 Reserved3; ++ __u16 SubCommand; /* 1st setup word - can be followed by SetupCount words */ ++ __u16 ByteCount; /* careful - setupcount is not always one */ ++ } req; ++ struct { ++ struct smb_hdr hdr; /* wct = 0 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParamterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* should be zero setup words following */ ++ __u16 ByteCount; ++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ ++ /* data area follows */ ++ } resp; ++} TRANSACTION2; ++ ++/* PathInfo/FileInfo infolevels */ ++#define SMB_INFO_STANDARD 1 ++#define SMB_INFO_QUERY_EAS_FROM_LIST 3 ++#define SMB_INFO_QUERY_ALL_EAS 4 ++#define SMB_INFO_IS_NAME_VALID 6 ++#define SMB_QUERY_FILE_BASIC_INFO 0x101 ++#define SMB_QUERY_FILE_STANDARD_INFO 0x102 ++#define SMB_QUERY_FILE_EA_INFO 0x103 ++#define SMB_QUERY_FILE_NAME_INFO 0x104 ++#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105 ++#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106 ++#define SMB_QUERY_FILE_ALL_INFO 0x107 ++#define SMB_QUERY_ALT_NAME_INFO 0x108 ++#define SMB_QUERY_FILE_STREAM_INFO 0x109 ++#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B ++#define SMB_QUERY_FILE_UNIX_BASIC 0x200 ++#define SMB_QUERY_FILE_UNIX_LINK 0x201 ++ ++#define SMB_SET_FILE_BASIC_INFO 0x101 ++#define SMB_SET_FILE_DISPOSITION_INFO 0x102 ++#define SMB_SET_FILE_ALLOCATION_INFO 0x103 ++#define SMB_SET_FILE_END_OF_FILE_INFO 0x104 ++#define SMB_SET_FILE_UNIX_BASIC 0x200 ++#define SMB_SET_FILE_UNIX_LINK 0x201 ++#define SMB_SET_FILE_UNIX_HLINK 0x203 ++#define SMB_SET_FILE_BASIC_INFO2 0x3ec ++#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 ++#define SMB_FILE_ALL_INFO2 0x3fa ++#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb ++#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc ++#define SMB_FILE_MOVE_CLUSTER_INFO 0x407 ++#define SMB_FILE_QUOTA_INFO 0x408 ++#define SMB_FILE_REPARSEPOINT_INFO 0x409 ++#define SMB_FILE_MAXIMUM_INFO 0x40d ++ ++/* Find File infolevels */ ++#define SMB_FIND_FILE_DIRECTORY_INFO 0x101 ++#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 ++#define SMB_FIND_FILE_NAMES_INFO 0x103 ++#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104 ++#define SMB_FIND_FILE_UNIX 0x202 ++ ++typedef struct smb_com_transaction2_qpi_req { ++ struct smb_hdr hdr; /* wct = 14+ */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; ++ __u8 Reserved3; ++ __u16 SubCommand; /* one setup word */ ++ __u16 ByteCount; ++ __u8 Pad; ++ __u16 InformationLevel; ++ __u32 Reserved4; ++ char FileName[1]; ++} TRANSACTION2_QPI_REQ; ++ ++typedef struct smb_com_transaction2_qpi_rsp { ++ struct smb_hdr hdr; /* wct = 10 + SetupCount */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* should be zero setup words following */ ++ __u16 ByteCount; ++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ ++} TRANSACTION2_QPI_RSP; ++ ++typedef struct smb_com_transaction2_spi_req { ++ struct smb_hdr hdr; /* wct = 15 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; ++ __u8 Reserved3; ++ __u16 SubCommand; /* one setup word */ ++ __u16 ByteCount; ++ __u8 Pad; ++ __u16 Pad1; ++ __u16 InformationLevel; ++ __u32 Reserved4; ++ char FileName[1]; ++} TRANSACTION2_SPI_REQ; ++ ++typedef struct smb_com_transaction2_spi_rsp { ++ struct smb_hdr hdr; /* wct = 10 + SetupCount */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* should be zero setup words following */ ++ __u16 ByteCount; ++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ ++} TRANSACTION2_SPI_RSP; ++ ++struct set_file_rename { ++ __u32 overwrite; /* 1 = overwrite dest */ ++ __u32 root_fid; /* zero */ ++ __u32 target_name_len; ++ char target_name[0]; /* Must be unicode */ ++}; ++ ++struct smb_com_transaction2_sfi_req { ++ struct smb_hdr hdr; /* wct = 15 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; ++ __u8 Reserved3; ++ __u16 SubCommand; /* one setup word */ ++ __u16 ByteCount; ++ __u8 Pad; ++ __u16 Pad1; ++ __u16 Fid; ++ __u16 InformationLevel; ++ __u16 Reserved4; ++}; ++ ++struct smb_com_transaction2_sfi_rsp { ++ struct smb_hdr hdr; /* wct = 10 + SetupCount */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* should be zero setup words following */ ++ __u16 ByteCount; ++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ ++}; ++ ++ ++/* ++ * Flags on T2 FINDFIRST and FINDNEXT ++ */ ++#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001 ++#define CIFS_SEARCH_CLOSE_AT_END 0x0002 ++#define CIFS_SEARCH_RETURN_RESUME 0x0004 ++#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008 ++#define CIFS_SEARCH_BACKUP_SEARCH 0x0010 ++ ++/* ++ * Size of the resume key on FINDFIRST and FINDNEXT calls ++ */ ++#define CIFS_SMB_RESUME_KEY_SIZE 4 ++ ++typedef struct smb_com_transaction2_ffirst_req { ++ struct smb_hdr hdr; /* wct = 15 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; /* one */ ++ __u8 Reserved3; ++ __u16 SubCommand; /* TRANS2_FIND_FIRST */ ++ __u16 ByteCount; ++ __u8 Pad; ++ __u16 SearchAttributes; ++ __u16 SearchCount; ++ __u16 SearchFlags; ++ __u16 InformationLevel; ++ __u32 SearchStorageType; ++ char FileName[1]; ++} TRANSACTION2_FFIRST_REQ; ++ ++typedef struct smb_com_transaction2_ffirst_rsp { ++ struct smb_hdr hdr; /* wct = 10 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* should be zero setup words following */ ++ __u16 ByteCount; ++} TRANSACTION2_FFIRST_RSP; ++ ++typedef struct smb_com_transaction2_ffirst_rsp_parms { ++ __u16 SearchHandle; ++ __u16 SearchCount; ++ __u16 EndofSearch; ++ __u16 EAErrorOffset; ++ __u16 LastNameOffset; ++} T2_FFIRST_RSP_PARMS; ++ ++typedef struct smb_com_transaction2_fnext_req { ++ struct smb_hdr hdr; /* wct = 15 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; /* one */ ++ __u8 Reserved3; ++ __u16 SubCommand; /* TRANS2_FIND_NEXT */ ++ __u16 ByteCount; ++ __u8 Pad; ++ __u16 SearchHandle; ++ __u16 SearchCount; ++ __u16 InformationLevel; ++ __u32 ResumeKey; ++ __u16 SearchFlags; ++ char ResumeFileName[1]; ++} TRANSACTION2_FNEXT_REQ; ++ ++typedef struct smb_com_transaction2_fnext_rsp { ++ struct smb_hdr hdr; /* wct = 10 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* should be zero setup words following */ ++ __u16 ByteCount; ++} TRANSACTION2_FNEXT_RSP; ++ ++typedef struct smb_com_transaction2_fnext_rsp_parms { ++ __u16 SearchCount; ++ __u16 EndofSearch; ++ __u16 EAErrorOffset; ++ __u16 LastNameOffset; ++} T2_FNEXT_RSP_PARMS; ++ ++/* QFSInfo Levels */ ++#define SMB_INFO_ALLOCATION 1 ++#define SMB_INFO_VOLUME 2 ++#define SMB_QUERY_FS_VOLUME_INFO 0x102 ++#define SMB_QUERY_FS_SIZE_INFO 0x103 ++#define SMB_QUERY_FS_DEVICE_INFO 0x104 ++#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105 ++#define SMB_QUERY_CIFS_UNIX_INFO 0x200 ++#define SMB_QUERY_LABEL_INFO 0x3ea ++#define SMB_QUERY_FS_QUOTA_INFO 0x3ee ++ ++typedef struct smb_com_transaction2_qfsi_req { ++ struct smb_hdr hdr; /* wct = 14+ */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; ++ __u8 Reserved3; ++ __u16 SubCommand; /* one setup word */ ++ __u16 ByteCount; ++ __u8 Pad; ++ __u16 InformationLevel; ++} TRANSACTION2_QFSI_REQ; ++ ++typedef struct smb_com_transaction_qfsi_rsp { ++ struct smb_hdr hdr; /* wct = 10 + SetupCount */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* should be zero setup words following */ ++ __u16 ByteCount; ++ __u8 Pad; /* may be three bytes *//* followed by data area */ ++} TRANSACTION2_QFSI_RSP; ++ ++typedef struct smb_com_transaction2_get_dfs_refer_req { ++ struct smb_hdr hdr; /* wct = 15 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 MaxParameterCount; ++ __u16 MaxDataCount; ++ __u8 MaxSetupCount; ++ __u8 Reserved; ++ __u16 Flags; ++ __u32 Timeout; ++ __u16 Reserved2; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u8 SetupCount; ++ __u8 Reserved3; ++ __u16 SubCommand; /* one setup word */ ++ __u16 ByteCount; ++ __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ ++ __u16 MaxReferralLevel; ++ char RequestFileName[1]; ++} TRANSACTION2_GET_DFS_REFER_REQ; ++ ++typedef struct dfs_referral_level_3 { ++ __u16 VersionNumber; ++ __u16 ReferralSize; ++ __u16 ServerType; /* 0x0001 = CIFS server */ ++ __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */ ++ __u16 TimeToLive; ++ __u16 Proximity; ++ __u16 DfsPathOffset; ++ __u16 DfsAlternatePathOffset; ++ __u16 NetworkAddressOffset; ++} REFERRAL3; ++ ++typedef struct smb_com_transaction_get_dfs_refer_rsp { ++ struct smb_hdr hdr; /* wct = 10 */ ++ __u16 TotalParameterCount; ++ __u16 TotalDataCount; ++ __u16 Reserved; ++ __u16 ParameterCount; ++ __u16 ParameterOffset; ++ __u16 ParameterDisplacement; ++ __u16 DataCount; ++ __u16 DataOffset; ++ __u16 DataDisplacement; ++ __u8 SetupCount; ++ __u8 Reserved1; /* zero setup words following */ ++ __u16 ByteCount; ++ __u8 Pad; ++ __u16 PathConsumed; ++ __u16 NumberOfReferrals; ++ __u16 DFSFlags; ++ __u16 Pad2; ++ REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ ++ /* followed by the strings pointed to by the referral structures */ ++} TRANSACTION2_GET_DFS_REFER_RSP; ++ ++/* DFS Flags */ ++#define DFSREF_REFERRAL_SERVER 0x0001 ++#define DFSREF_STORAGE_SERVER 0x0002 ++ ++/* IOCTL information */ ++/* List of ioctl function codes that look to be of interest to remote clients like this. */ ++/* Need to do some experimentation to make sure they all work remotely. */ ++/* Some of the following such as the encryption/compression ones would be */ ++/* invoked from tools via a specialized hook into the VFS rather than via the */ ++/* standard vfs entry points */ ++#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000 ++#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004 ++#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008 ++#define FSCTL_LOCK_VOLUME 0x00090018 ++#define FSCTL_UNLOCK_VOLUME 0x0009001C ++#define FSCTL_GET_COMPRESSION 0x0009003C ++#define FSCTL_SET_COMPRESSION 0x0009C040 ++#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C ++#define FSCTL_FILESYS_GET_STATISTICS 0x00090090 ++#define FSCTL_SET_REPARSE_POINT 0x000900A4 ++#define FSCTL_GET_REPARSE_POINT 0x000900A8 ++#define FSCTL_DELETE_REPARSE_POINT 0x000900AC ++#define FSCTL_SET_SPARSE 0x000900C4 ++#define FSCTL_SET_ZERO_DATA 0x000900C8 ++#define FSCTL_SET_ENCRYPTION 0x000900D7 ++#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB ++#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF ++#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3 ++#define FSCTL_SIS_COPYFILE 0x00090100 ++#define FSCTL_SIS_LINK_FILES 0x0009C104 ++ ++#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 ++#define IO_REPARSE_TAG_HSM 0xC0000004 ++#define IO_REPARSE_TAG_SIS 0x80000007 ++ ++/* ++ ************************************************************************ ++ * All structs for everything above the SMB PDUs themselves ++ * (such as the T2 level specific data) go here ++ ************************************************************************ ++ */ ++ ++/* ++ * Information on a server ++ */ ++ ++struct serverInfo { ++ char name[16]; ++ unsigned char versionMajor; ++ unsigned char versionMinor; ++ unsigned long type; ++ unsigned int commentOffset; ++}; ++ ++/* ++ * The following structure is the format of the data returned on a NetShareEnum ++ * with level "90" (x5A) ++ */ ++ ++struct shareInfo { ++ char shareName[13]; ++ char pad; ++ unsigned short type; ++ unsigned int commentOffset; ++}; ++ ++struct aliasInfo { ++ char aliasName[9]; ++ char pad; ++ unsigned int commentOffset; ++ unsigned char type[2]; ++}; ++ ++struct aliasInfo92 { ++ int aliasNameOffset; ++ int serverNameOffset; ++ int shareNameOffset; ++}; ++ ++typedef struct { ++ __u64 TotalAllocationUnits; ++ __u64 FreeAllocationUnits; ++ __u32 SectorsPerAllocationUnit; ++ __u32 BytesPerSector; ++} FILE_SYSTEM_INFO; /* size info, level 0x103 */ ++ ++typedef struct { ++ __u16 MajorVersionNumber; ++ __u16 MinorVersionNumber; ++ __u64 Capability; ++} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ ++/* Linux/Unix extensions capability flags */ ++#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ ++#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 ++ ++/* DeviceType Flags */ ++#define FILE_DEVICE_CD_ROM 0x00000002 ++#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 ++#define FILE_DEVICE_DFS 0x00000006 ++#define FILE_DEVICE_DISK 0x00000007 ++#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 ++#define FILE_DEVICE_FILE_SYSTEM 0x00000009 ++#define FILE_DEVICE_NAMED_PIPE 0x00000011 ++#define FILE_DEVICE_NETWORK 0x00000012 ++#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 ++#define FILE_DEVICE_NULL 0x00000015 ++#define FILE_DEVICE_PARALLEL_PORT 0x00000016 ++#define FILE_DEVICE_PRINTER 0x00000018 ++#define FILE_DEVICE_SERIAL_PORT 0x0000001b ++#define FILE_DEVICE_STREAMS 0x0000001e ++#define FILE_DEVICE_TAPE 0x0000001f ++#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 ++#define FILE_DEVICE_VIRTUAL_DISK 0x00000024 ++#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 ++ ++typedef struct { ++ __u32 DeviceType; ++ __u32 DeviceCharacteristics; ++} FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ ++ ++typedef struct { ++ __u32 Attributes; ++ __u32 MaxPathNameComponentLength; ++ __u32 FileSystemNameLen; ++ char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ ++} FILE_SYSTEM_ATTRIBUTE_INFO; ++ ++typedef struct { /* data block encoding of response to level 263 QPathInfo */ ++ __u64 CreationTime; ++ __u64 LastAccessTime; ++ __u64 LastWriteTime; ++ __u64 ChangeTime; ++ __u32 Attributes; ++ __u32 Pad1; ++ __u64 AllocationSize; ++ __u64 EndOfFile; /* size ie offset to first free byte in file */ ++ __u32 NumberOfLinks; /* hard links */ ++ __u8 DeletePending; ++ __u8 Directory; ++ __u16 Pad2; ++ __u64 IndexNumber; ++ __u32 EASize; ++ __u32 AccessFlags; ++ __u64 IndexNumber1; ++ __u64 CurrentByteOffset; ++ __u32 Mode; ++ __u32 AlignmentRequirement; ++ __u32 FileNameLength; ++ char FileName[1]; ++} FILE_ALL_INFO; /* level 263 QPathInfo */ ++ ++typedef struct { ++ __u64 EndOfFile; ++ __u64 NumOfBytes; ++ __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ ++ __u64 LastAccessTime; ++ __u64 LastModificationTime; ++ __u64 Uid; ++ __u64 Gid; ++ __u32 Type; ++ __u64 DevMajor; ++ __u64 DevMinor; ++ __u64 UniqueId; ++ __u64 Permissions; ++ __u64 Nlinks; ++} FILE_UNIX_BASIC_INFO; /* level 512 QPathInfo */ ++ ++typedef struct { ++ char LinkDest[1]; ++} FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */ ++ ++/* defines for enumerating possible values of the Unix type field below */ ++#define UNIX_FILE 0 ++#define UNIX_DIR 1 ++#define UNIX_SYMLINK 2 ++#define UNIX_CHARDEV 3 ++#define UNIX_BLOCKDEV 4 ++#define UNIX_FIFO 5 ++#define UNIX_SOCKET 6 ++ ++typedef struct { ++ __u32 NextEntryOffset; ++ __u32 ResumeKey; ++ __u64 EndOfFile; ++ __u64 NumOfBytes; ++ __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */ ++ __u64 LastAccessTime; ++ __u64 LastModificationTime; ++ __u64 Uid; ++ __u64 Gid; ++ __u32 Type; ++ __u64 DevMajor; ++ __u64 DevMinor; ++ __u64 UniqueId; ++ __u64 Permissions; ++ __u64 Nlinks; ++ char FileName[1]; ++} FILE_UNIX_INFO; ++ ++typedef struct { ++ __u64 CreationTime; ++ __u64 LastAccessTime; ++ __u64 LastWriteTime; ++ __u64 ChangeTime; ++ __u32 Attributes; ++ __u32 Pad; ++} FILE_BASIC_INFO; /* size info, level 0x101 */ ++ ++struct file_allocation_info { ++ __u64 AllocationSize; ++}; /* size info, level 0x103 */ ++ ++struct file_end_of_file_info { ++ __u64 FileSize; /* offset to end of file */ ++}; /* size info, level 0x104 */ ++ ++typedef struct { ++ __u32 NextEntryOffset; ++ __u32 FileIndex; ++ __u64 CreationTime; ++ __u64 LastAccessTime; ++ __u64 LastWriteTime; ++ __u64 ChangeTime; ++ __u64 EndOfFile; ++ __u64 AllocationSize; ++ __u32 ExtFileAttributes; ++ __u32 FileNameLength; ++ char FileName[1]; ++} FILE_DIRECTORY_INFO; /* level 257 FF response data area */ ++ ++struct gea { ++ unsigned char cbName; ++ char szName[1]; ++}; ++ ++struct gealist { ++ unsigned long cbList; ++ struct gea list[1]; ++}; ++ ++struct fea { ++ unsigned char EA_flags; ++ __u8 name_len; ++ __u16 value_len; ++ char szName[1]; ++ /* optionally followed by value */ ++}; ++/* flags for _FEA.fEA */ ++#define FEA_NEEDEA 0x80 /* need EA bit */ ++ ++struct fealist { ++ __u32 list_len; ++ struct fea list[1]; ++}; ++ ++/* used to hold an arbitrary blob of data */ ++struct data_blob { ++ __u8 *data; ++ size_t length; ++ void (*free) (struct data_blob * data_blob); ++}; ++ ++#ifdef CONFIG_CIFS_POSIX ++/* ++ For better POSIX semantics from Linux client, (even better ++ than the existing CIFS Unix Extensions) we need updated PDUs for: ++ ++ 1) PosixCreateX - to set and return the mode, inode#, device info and ++ perhaps add a CreateDevice - to create Pipes and other special .inodes ++ Also note POSIX open flags ++ 2) Close - to return the last write time to do cache across close more safely ++ 3) PosixQFSInfo - to return statfs info ++ 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) ++ 5) Mkdir - set mode ++ ++ And under consideration: ++ 6) FindClose2 (return nanosecond timestamp ??) ++ 7) Use nanosecond timestamps throughout all time fields if ++ corresponding attribute flag is set ++ 8) sendfile - handle based copy ++ 9) Direct i/o ++ 10) "POSIX ACL" support ++ 11) Misc fcntls? ++ ++ what about fixing 64 bit alignment ++ ++ There are also various legacy SMB/CIFS requests used as is ++ ++ From existing Lanman and NTLM dialects: ++ -------------------------------------- ++ NEGOTIATE ++ SESSION_SETUP_ANDX (BB which?) ++ TREE_CONNECT_ANDX (BB which wct?) ++ TREE_DISCONNECT (BB add volume timestamp on response) ++ LOGOFF_ANDX ++ DELETE (note delete open file behavior) ++ DELETE_DIRECTORY ++ READ_AND_X ++ WRITE_AND_X ++ LOCKING_AND_X (note posix lock semantics) ++ RENAME (note rename across dirs and open file rename posix behaviors) ++ NT_RENAME (for hardlinks) Is this good enough for all features? ++ FIND_CLOSE2 ++ TRANSACTION2 (18 cases) ++ SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2 ++ (BB verify that never need to set allocation size) ++ SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?) ++ ++ COPY (note support for copy across directories) - FUTURE, OPTIONAL ++ setting/getting OS/2 EAs - FUTURE (BB can this handle ++ setting Linux xattrs perfectly) - OPTIONAL ++ dnotify - FUTURE, OPTIONAL ++ quota - FUTURE, OPTIONAL ++ ++ Note that various requests implemented for NT interop such as ++ NT_TRANSACT (IOCTL) QueryReparseInfo ++ are unneeded to servers compliant with the CIFS POSIX extensions ++ ++ From CIFS Unix Extensions: ++ ------------------------- ++ T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks ++ T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2) ++ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK) ++ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields ++ Actually need QUERY_FILE_UNIX_INFO since has inode num ++ BB what about a) blksize/blkbits/blocks ++ b) i_version ++ c) i_rdev ++ d) notify mask? ++ e) generation ++ f) size_seqcount ++ T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX ++ TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended ++ T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL ++ ++ ++ */ ++#endif ++ ++#pragma pack() /* resume default structure packing */ ++ ++#endif /* _CIFSPDU_H */ +diff -urN linux-2.4.29.old/fs/cifs/cifsproto.h linux-2.4.29/fs/cifs/cifsproto.h +--- linux-2.4.29.old/fs/cifs/cifsproto.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifsproto.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,254 @@ ++/* ++ * fs/cifs/cifsproto.h ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#ifndef _CIFSPROTO_H ++#define _CIFSPROTO_H ++#include <linux/nls.h> ++ ++struct statfs; ++ ++/* ++ ***************************************************************** ++ * All Prototypes ++ ***************************************************************** ++ */ ++ ++extern struct smb_hdr *cifs_buf_get(void); ++extern void cifs_buf_release(void *); ++extern int smb_send(struct socket *, struct smb_hdr *, ++ unsigned int /* length */ , struct sockaddr *); ++extern unsigned int _GetXid(void); ++extern void _FreeXid(unsigned int); ++#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid)); ++#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,rc));} ++extern char *build_path_from_dentry(struct dentry *); ++extern char *build_wildcard_path_from_dentry(struct dentry *direntry); ++extern void renew_parental_timestamps(struct dentry *direntry); ++extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, ++ struct smb_hdr * /* input */ , ++ struct smb_hdr * /* out */ , ++ int * /* bytes returned */ , const int long_op); ++extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); ++extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); ++extern int is_valid_oplock_break(struct smb_hdr *smb); ++extern unsigned int smbCalcSize(struct smb_hdr *ptr); ++extern int decode_negTokenInit(unsigned char *security_blob, int length, ++ enum securityEnum *secType); ++extern int map_smb_to_linux_error(struct smb_hdr *smb); ++extern void header_assemble(struct smb_hdr *, char /* command */ , ++ const struct cifsTconInfo *, int ++ /* length of fixed section (word count) in two byte units */ ++ ); ++struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); ++void DeleteOplockQEntry(struct oplock_q_entry *); ++extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); ++extern u64 cifs_UnixTimeToNT(time_t); ++extern int cifs_get_inode_info(struct inode **pinode, ++ const unsigned char *search_path, ++ FILE_ALL_INFO * pfile_info, ++ struct super_block *sb, int xid); ++extern int cifs_get_inode_info_unix(struct inode **pinode, ++ const unsigned char *search_path, ++ struct super_block *sb,int xid); ++ ++extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ++ struct nls_table * nls_info); ++extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses); ++ ++extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ++ const char *tree, struct cifsTconInfo *tcon, ++ const struct nls_table *); ++ ++extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, ++ const char *searchName, ++ FILE_DIRECTORY_INFO * findData, ++ T2_FFIRST_RSP_PARMS * findParms, ++ const struct nls_table *nls_codepage, ++ int *pUnicodeFlag, ++ int *pUnixFlag /* if Unix extensions used */ ); ++extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ++ FILE_DIRECTORY_INFO * findData, ++ T2_FNEXT_RSP_PARMS * findParms, ++ const __u16 searchHandle, char * resume_name, ++ int name_length, __u32 resume_key, ++ int *UnicodeFlag, int *pUnixFlag); ++ ++extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, ++ const __u16 search_handle); ++ ++extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ FILE_ALL_INFO * findData, ++ const struct nls_table *nls_codepage); ++ ++extern int CIFSSMBUnixQPathInfo(const int xid, ++ struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ FILE_UNIX_BASIC_INFO * pFindData, ++ const struct nls_table *nls_codepage); ++ ++extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, ++ const unsigned char *searchName, ++ unsigned char **targetUNCs, ++ unsigned int *number_of_UNC_in_array, ++ const struct nls_table *nls_codepage); ++ ++extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ++ const char *old_path, ++ const struct nls_table *nls_codepage); ++extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ++ const char *old_path, const struct nls_table *nls_codepage, ++ unsigned int *pnum_referrals, unsigned char ** preferrals); ++extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, ++ struct statfs *FSData, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBQFSAttributeInfo(const int xid, ++ struct cifsTconInfo *tcon, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon, ++ const struct nls_table *nls_codepage); ++ ++extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, ++ char *fileName, FILE_BASIC_INFO * data, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, ++ char *fileName, __u64 size,int setAllocationSizeFlag, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, ++ __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag); ++extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon, ++ char *full_path, __u64 mode, __u64 uid, ++ __u64 gid, dev_t dev, const struct nls_table *nls_codepage); ++ ++extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, ++ const char *newName, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, ++ const char *name, const struct nls_table *nls_codepage); ++ ++extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, ++ const char *name, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, ++ int netfid, char * target_name, const struct nls_table *nls_codepage); ++extern int CIFSCreateHardLink(const int xid, ++ struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage); ++extern int CIFSUnixCreateHardLink(const int xid, ++ struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage); ++extern int CIFSUnixCreateSymLink(const int xid, ++ struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBUnixQuerySymLink(const int xid, ++ struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ char *syminfo, const int buflen, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBQueryReparseLinkInfo(const int xid, ++ struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ char *symlinkinfo, const int buflen, __u16 fid, ++ const struct nls_table *nls_codepage); ++ ++extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ++ const char *fileName, const int disposition, ++ const int access_flags, const int omode, ++ __u16 * netfid, int *pOplock, FILE_ALL_INFO *, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, ++ const int smb_file_id); ++ ++extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, ++ const int netfid, unsigned int count, ++ const __u64 lseek, unsigned int *nbytes, char **buf); ++extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, ++ const int netfid, const unsigned int count, ++ const __u64 lseek, unsigned int *nbytes, ++ const char *buf, const int long_op); ++extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ++ const __u16 netfid, const __u64 len, ++ const __u64 offset, const __u32 numUnlock, ++ const __u32 numLock, const __u8 lockType, ++ const int waitFlag); ++ ++extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon); ++extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses); ++ ++extern struct cifsSesInfo *sesInfoAlloc(void); ++extern void sesInfoFree(struct cifsSesInfo *); ++extern struct cifsTconInfo *tconInfoAlloc(void); ++extern void tconInfoFree(struct cifsTconInfo *); ++ ++extern int cifs_reconnect(struct TCP_Server_Info *server); ++ ++extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *); ++extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key, ++ __u32 expected_sequence_number); ++extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); ++extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); ++extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); ++ ++extern int CIFSBuildServerList(int xid, char *serverBufferList, ++ int recordlength, int *entries, ++ int *totalEntries, int *topoChangedFlag); ++extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon, ++ struct shareInfo *shareList, int bufferLen, ++ int *entries, int *totalEntries); ++extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon, ++ struct aliasInfo *aliasList, int bufferLen, ++ int *entries, int *totalEntries); ++extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon, ++ char *aliasName, char *serverName, ++ char *shareName, char *comment); ++extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon, ++ char *share, char *comment); ++extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon, ++ char *userName, char *searchName, int *perms); ++extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid); ++ ++extern int CIFSSMBSeek(int xid, ++ struct cifsTconInfo *tcon, ++ int netfid, ++ int pid, ++ int whence, unsigned long offset, long long *newoffset); ++ ++extern int CIFSSMBCopy(int xid, ++ struct cifsTconInfo *source_tcon, ++ const char *fromName, ++ const __u16 target_tid, ++ const char *toName, const int flags, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, ++ const int notify_subdirs,const __u16 netfid,__u32 filter, ++ const struct nls_table *nls_codepage); ++extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ char * EAData, size_t size, ++ const struct nls_table *nls_codepage); ++#endif /* _CIFSPROTO_H */ +diff -urN linux-2.4.29.old/fs/cifs/cifssmb.c linux-2.4.29/fs/cifs/cifssmb.c +--- linux-2.4.29.old/fs/cifs/cifssmb.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifssmb.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,3016 @@ ++/* ++ * fs/cifs/cifssmb.c ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * Contains the routines for constructing the SMB PDUs themselves ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++ /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */ ++ /* These are mostly routines that operate on a pathname, or on a tree id */ ++ /* (mounted volume), but there are eight handle based routines which must be */ ++ /* treated slightly different for reconnection purposes since we never want */ ++ /* to reuse a stale file handle and the caller knows the file handle */ ++ ++#include <linux/fs.h> ++#include <linux/kernel.h> ++#include <linux/vfs.h> ++#include <asm/uaccess.h> ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_unicode.h" ++#include "cifs_debug.h" ++ ++#ifdef CONFIG_CIFS_POSIX ++static struct { ++ int index; ++ char *name; ++} protocols[] = { ++ {CIFS_PROT, "\2NT LM 0.12"}, ++ {CIFS_PROT, "\2POSIX 2"}, ++ {BAD_PROT, "\2"} ++}; ++#else ++static struct { ++ int index; ++ char *name; ++} protocols[] = { ++ {CIFS_PROT, "\2NT LM 0.12"}, ++ {BAD_PROT, "\2"} ++}; ++#endif ++ ++ ++/* Mark as invalid, all open files on tree connections since they ++ were closed when session to server was lost */ ++static void mark_open_files_invalid(struct cifsTconInfo * pTcon) ++{ ++ struct cifsFileInfo *open_file = NULL; ++ struct list_head * tmp; ++ struct list_head * tmp1; ++ ++/* list all files open on tree connection and mark them invalid */ ++ write_lock(&GlobalSMBSeslock); ++ list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { ++ open_file = list_entry(tmp,struct cifsFileInfo, tlist); ++ if(open_file) { ++ open_file->invalidHandle = TRUE; ++ } ++ } ++ write_unlock(&GlobalSMBSeslock); ++ /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */ ++} ++ ++static int ++smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, ++ void **request_buf /* returned */ , ++ void **response_buf /* returned */ ) ++{ ++ int rc = 0; ++ int timeout = 10 * HZ; ++ ++ /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so ++ check for tcp and smb session status done differently ++ for those three - in the calling routine */ ++ if(tcon) { ++ if((tcon->ses) && (tcon->ses->server)){ ++ struct nls_table *nls_codepage; ++ /* Give Demultiplex thread up to 10 seconds to ++ reconnect, should be greater than cifs socket ++ timeout which is 7 seconds */ ++ while(tcon->ses->server->tcpStatus == CifsNeedReconnect) { ++ while ((tcon->ses->server->tcpStatus != CifsGood) && (timeout > 0)){ ++ timeout = interruptible_sleep_on_timeout(&tcon->ses->server->response_q,timeout); ++ } ++ if(tcon->ses->server->tcpStatus == CifsNeedReconnect) { ++ /* on "soft" mounts we wait once */ ++ if((tcon->retry == FALSE) || ++ (tcon->ses->status == CifsExiting)) { ++ cFYI(1,("gave up waiting on reconnect in smb_init")); ++ return -EHOSTDOWN; ++ } /* else "hard" mount - keep retrying until ++ process is killed or server comes back up */ ++ } else /* TCP session is reestablished now */ ++ break; ++ ++ } ++ ++ nls_codepage = load_nls_default(); ++ /* need to prevent multiple threads trying to ++ simultaneously reconnect the same SMB session */ ++ down(&tcon->ses->sesSem); ++ if(tcon->ses->status == CifsNeedReconnect) ++ rc = cifs_setup_session(0, tcon->ses, nls_codepage); ++ if(!rc && (tcon->tidStatus == CifsNeedReconnect)) { ++ mark_open_files_invalid(tcon); ++ rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon, ++ nls_codepage); ++ up(&tcon->ses->sesSem); ++ if(rc == 0) ++ atomic_inc(&tconInfoReconnectCount); ++ ++ cFYI(1, ("reconnect tcon rc = %d", rc)); ++ /* Removed call to reopen open files here - ++ it is safer (and faster) to reopen files ++ one at a time as needed in read and write */ ++ ++ /* Check if handle based operation so we ++ know whether we can continue or not without ++ returning to caller to reset file handle */ ++ switch(smb_command) { ++ case SMB_COM_READ_ANDX: ++ case SMB_COM_WRITE_ANDX: ++ case SMB_COM_CLOSE: ++ case SMB_COM_FIND_CLOSE2: ++ case SMB_COM_LOCKING_ANDX: { ++ unload_nls(nls_codepage); ++ return -EAGAIN; ++ } ++ } ++ } else { ++ up(&tcon->ses->sesSem); ++ } ++ unload_nls(nls_codepage); ++ ++ } else { ++ return -EIO; ++ } ++ } ++ if(rc) ++ return rc; ++ ++ *request_buf = cifs_buf_get(); ++ if (*request_buf == 0) { ++ /* BB should we add a retry in here if not a writepage? */ ++ return -ENOMEM; ++ } ++ /* Although the original thought was we needed the response buf for */ ++ /* potential retries of smb operations it turns out we can determine */ ++ /* from the mid flags when the request buffer can be resent without */ ++ /* having to use a second distinct buffer for the response */ ++ *response_buf = *request_buf; ++ ++ header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, ++ wct /*wct */ ); ++ ++#ifdef CONFIG_CIFS_STATS ++ if(tcon != NULL) { ++ atomic_inc(&tcon->num_smbs_sent); ++ } ++#endif ++ return rc; ++} ++ ++int ++CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) ++{ ++ NEGOTIATE_REQ *pSMB; ++ NEGOTIATE_RSP *pSMBr; ++ int rc = 0; ++ int bytes_returned; ++ struct TCP_Server_Info * server; ++ ++ if(ses->server) ++ server = ses->server; ++ else { ++ rc = -EIO; ++ return rc; ++ } ++ rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , ++ (void **) &pSMB, (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; ++ if (extended_security) ++ pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; ++ ++ pSMB->ByteCount = strlen(protocols[0].name) + 1; ++ strncpy(pSMB->DialectsArray, protocols[0].name, 30); ++ /* null guaranteed to be at end of source and target buffers anyway */ ++ ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc == 0) { ++ server->secMode = pSMBr->SecurityMode; ++ server->secType = NTLM; /* BB override default for NTLMv2 or krb*/ ++ /* one byte - no need to convert this or EncryptionKeyLen from le,*/ ++ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); ++ /* probably no need to store and check maxvcs */ ++ server->maxBuf = ++ min(le32_to_cpu(pSMBr->MaxBufferSize), ++ (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE); ++ server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); ++ cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); ++ GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); ++ server->capabilities = le32_to_cpu(pSMBr->Capabilities); ++ server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); ++ /* BB with UTC do we ever need to be using srvr timezone? */ ++ if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { ++ memcpy(server->cryptKey, pSMBr->u.EncryptionKey, ++ CIFS_CRYPTO_KEY_SIZE); ++ } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) ++ && (pSMBr->EncryptionKeyLength == 0)) { ++ /* decode security blob */ ++ } else ++ rc = -EIO; ++ ++ /* BB might be helpful to save off the domain of server here */ ++ ++ if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) { ++ if (pSMBr->ByteCount < 16) ++ rc = -EIO; ++ else if (pSMBr->ByteCount == 16) { ++ server->secType = RawNTLMSSP; ++ if (server->socketUseCount.counter > 1) { ++ if (memcmp ++ (server->server_GUID, ++ pSMBr->u.extended_response. ++ GUID, 16) != 0) { ++ cFYI(1, ++ ("UID of server does not match previous connection to same ip address")); ++ memcpy(server-> ++ server_GUID, ++ pSMBr->u. ++ extended_response. ++ GUID, 16); ++ } ++ } else ++ memcpy(server->server_GUID, ++ pSMBr->u.extended_response. ++ GUID, 16); ++ } else { ++ rc = decode_negTokenInit(pSMBr->u. ++ extended_response. ++ SecurityBlob, ++ pSMBr->ByteCount - ++ 16, &server->secType); ++ } ++ } else ++ server->capabilities &= ~CAP_EXTENDED_SECURITY; ++ if(sign_CIFS_PDUs == FALSE) { ++ if(server->secMode & SECMODE_SIGN_REQUIRED) ++ cERROR(1, ++ ("Server requires /proc/fs/cifs/PacketSigningEnabled")); ++ server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); ++ } else if(sign_CIFS_PDUs == 1) { ++ if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) ++ server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); ++ } ++ ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ return rc; ++} ++ ++int ++CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) ++{ ++ struct smb_hdr *smb_buffer; ++ struct smb_hdr *smb_buffer_response; ++ int rc = 0; ++ int length; ++ ++ cFYI(1, ("In tree disconnect")); ++ /* ++ * If last user of the connection and ++ * connection alive - disconnect it ++ * If this is the last connection on the server session disconnect it ++ * (and inside session disconnect we should check if tcp socket needs ++ * to be freed and kernel thread woken up). ++ */ ++ if (tcon) ++ down(&tcon->tconSem); ++ else ++ return -EIO; ++ ++ atomic_dec(&tcon->useCount); ++ if (atomic_read(&tcon->useCount) > 0) { ++ up(&tcon->tconSem); ++ return -EBUSY; ++ } ++ ++ /* No need to return error on this operation if tid invalidated and ++ closed on server already e.g. due to tcp session crashing */ ++ if(tcon->tidStatus == CifsNeedReconnect) { ++ up(&tcon->tconSem); ++ return 0; ++ } ++ ++ if((tcon->ses == 0) || (tcon->ses->server == 0)) { ++ up(&tcon->tconSem); ++ return -EIO; ++ } ++ ++ rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, ++ (void **) &smb_buffer, (void **) &smb_buffer_response); ++ if (rc) { ++ up(&tcon->tconSem); ++ return rc; ++ } ++ rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response, ++ &length, 0); ++ if (rc) ++ cFYI(1, (" Tree disconnect failed %d", rc)); ++ ++ if (smb_buffer) ++ cifs_buf_release(smb_buffer); ++ up(&tcon->tconSem); ++ ++ /* No need to return error on this operation if tid invalidated and ++ closed on server already e.g. due to tcp session crashing */ ++ if (rc == -EAGAIN) ++ rc = 0; ++ ++ return rc; ++} ++ ++int ++CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) ++{ ++ struct smb_hdr *smb_buffer_response; ++ LOGOFF_ANDX_REQ *pSMB; ++ int rc = 0; ++ int length; ++ ++ cFYI(1, ("In SMBLogoff for session disconnect")); ++ if (ses) ++ down(&ses->sesSem); ++ else ++ return -EIO; ++ ++ atomic_dec(&ses->inUse); ++ if (atomic_read(&ses->inUse) > 0) { ++ up(&ses->sesSem); ++ return -EBUSY; ++ } ++ ++ rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */, ++ (void **) &pSMB, (void **) &smb_buffer_response); ++ ++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) ++ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; ++ ++ if (rc) { ++ up(&ses->sesSem); ++ return rc; ++ } ++ ++ pSMB->hdr.Uid = ses->Suid; ++ ++ pSMB->AndXCommand = 0xFF; ++ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, ++ smb_buffer_response, &length, 0); ++ if (ses->server) { ++ atomic_dec(&ses->server->socketUseCount); ++ if (atomic_read(&ses->server->socketUseCount) == 0) { ++ spin_lock(&GlobalMid_Lock); ++ ses->server->tcpStatus = CifsExiting; ++ spin_unlock(&GlobalMid_Lock); ++ rc = -ESHUTDOWN; ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ up(&ses->sesSem); ++ ++ /* if session dead then we do not need to do ulogoff, ++ since server closed smb session, no sense reporting ++ error */ ++ if (rc == -EAGAIN) ++ rc = 0; ++ return rc; ++} ++ ++int ++CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, ++ const char *fileName, const struct nls_table *nls_codepage) ++{ ++ DELETE_FILE_REQ *pSMB = NULL; ++ DELETE_FILE_RSP *pSMBr = NULL; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ ++DelFileRetry: ++ rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fileName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->fileName, fileName, name_len); ++ } ++ pSMB->SearchAttributes = ++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM); ++ pSMB->ByteCount = name_len + 1; ++ pSMB->BufferFormat = 0x04; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Error in RMFile = %d", rc)); ++ } ++#ifdef CONFIG_CIFS_STATS ++ else { ++ atomic_inc(&tcon->num_deletes); ++ } ++#endif ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto DelFileRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, ++ const char *dirName, const struct nls_table *nls_codepage) ++{ ++ DELETE_DIRECTORY_REQ *pSMB = NULL; ++ DELETE_DIRECTORY_RSP *pSMBr = NULL; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ ++ cFYI(1, ("In CIFSSMBRmDir")); ++RmDirRetry: ++ rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(dirName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->DirName, dirName, name_len); ++ } ++ ++ pSMB->ByteCount = name_len + 1; ++ pSMB->BufferFormat = 0x04; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Error in RMDir = %d", rc)); ++ } ++#ifdef CONFIG_CIFS_STATS ++ else { ++ atomic_inc(&tcon->num_rmdirs); ++ } ++#endif ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto RmDirRetry; ++ return rc; ++} ++ ++int ++CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon, ++ const char *name, const struct nls_table *nls_codepage) ++{ ++ int rc = 0; ++ CREATE_DIRECTORY_REQ *pSMB = NULL; ++ CREATE_DIRECTORY_RSP *pSMBr = NULL; ++ int bytes_returned; ++ int name_len; ++ ++ cFYI(1, ("In CIFSSMBMkDir")); ++MkDirRetry: ++ rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(name, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->DirName, name, name_len); ++ } ++ ++ pSMB->ByteCount = name_len + 1 /* for buf format */ ; ++ pSMB->BufferFormat = 0x04; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Error in Mkdir = %d", rc)); ++ } ++#ifdef CONFIG_CIFS_STATS ++ else { ++ atomic_inc(&tcon->num_mkdirs); ++ } ++#endif ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto MkDirRetry; ++ return rc; ++} ++ ++int ++CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, ++ const char *fileName, const int openDisposition, ++ const int access_flags, const int create_options, __u16 * netfid, ++ int *pOplock, FILE_ALL_INFO * pfile_info, ++ const struct nls_table *nls_codepage) ++{ ++ int rc = -EACCES; ++ OPEN_REQ *pSMB = NULL; ++ OPEN_RSP *pSMBr = NULL; ++ int bytes_returned; ++ int name_len; ++ ++openRetry: ++ rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->AndXCommand = 0xFF; /* none */ ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ pSMB->ByteCount = 1; /* account for one byte pad to word boundary */ ++ name_len = ++ cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1), ++ fileName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ pSMB->NameLength = cpu_to_le16(name_len); ++ } else { /* BB improve the check for buffer overruns BB */ ++ pSMB->ByteCount = 0; /* no pad */ ++ name_len = strnlen(fileName, 530); ++ name_len++; /* trailing null */ ++ pSMB->NameLength = cpu_to_le16(name_len); ++ strncpy(pSMB->fileName, fileName, name_len); ++ } ++ if (*pOplock & REQ_OPLOCK) ++ pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); ++ else if (*pOplock & REQ_BATCHOPLOCK) { ++ pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); ++ } ++ pSMB->DesiredAccess = cpu_to_le32(access_flags); ++ pSMB->AllocationSize = 0; ++ pSMB->FileAttributes = ATTR_NORMAL; ++ /* XP does not handle ATTR_POSIX_SEMANTICS */ ++ /* but it helps speed up case sensitive checks for other ++ servers such as Samba */ ++ if (tcon->ses->capabilities & CAP_UNIX) ++ pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS; ++ ++ /* if ((omode & S_IWUGO) == 0) ++ pSMB->FileAttributes |= ATTR_READONLY;*/ ++ /* Above line causes problems due to vfs splitting create into two ++ pieces - need to set mode after file created not while it is ++ being created */ ++ pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes); ++ pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); ++ pSMB->CreateDisposition = cpu_to_le32(openDisposition); ++ pSMB->CreateOptions = cpu_to_le32(create_options); ++ pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/ ++ pSMB->SecurityFlags = ++ cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY); ++ ++ pSMB->ByteCount += name_len; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ /* long_op set to 1 to allow for oplock break timeouts */ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 1); ++ if (rc) { ++ cFYI(1, ("Error in Open = %d", rc)); ++ } else { ++ *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */ ++ *netfid = pSMBr->Fid; /* cifs fid stays in le */ ++ /* Let caller know file was created so we can set the mode. */ ++ /* Do we care about the CreateAction in any other cases? */ ++ if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) ++ *pOplock |= CIFS_CREATE_ACTION; ++ if(pfile_info) { ++ memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime, ++ 36 /* CreationTime to Attributes */); ++ /* the file_info buf is endian converted by caller */ ++ pfile_info->AllocationSize = pSMBr->AllocationSize; ++ pfile_info->EndOfFile = pSMBr->EndOfFile; ++ pfile_info->NumberOfLinks = cpu_to_le32(1); ++ } ++ ++#ifdef CONFIG_CIFS_STATS ++ atomic_inc(&tcon->num_opens); ++#endif ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto openRetry; ++ return rc; ++} ++ ++/* If no buffer passed in, then caller wants to do the copy ++ as in the case of readpages so the SMB buffer must be ++ freed by the caller */ ++ ++int ++CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, ++ const int netfid, const unsigned int count, ++ const __u64 lseek, unsigned int *nbytes, char **buf) ++{ ++ int rc = -EACCES; ++ READ_REQ *pSMB = NULL; ++ READ_RSP *pSMBr = NULL; ++ char *pReadData = NULL; ++ int bytes_returned; ++ ++ *nbytes = 0; ++ rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ /* tcon and ses pointer are checked in smb_init */ ++ if (tcon->ses->server == NULL) ++ return -ECONNABORTED; ++ ++ pSMB->AndXCommand = 0xFF; /* none */ ++ pSMB->Fid = netfid; ++ pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); ++ pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); ++ pSMB->Remaining = 0; ++ pSMB->MaxCount = cpu_to_le16(count); ++ pSMB->MaxCountHigh = 0; ++ pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cERROR(1, ("Send error in read = %d", rc)); ++ } else { ++ pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength); ++ *nbytes = pSMBr->DataLength; ++ /*check that DataLength would not go beyond end of SMB */ ++ if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE) ++ || (pSMBr->DataLength > count)) { ++ cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count)); ++ rc = -EIO; ++ *nbytes = 0; ++ } else { ++ pReadData = ++ (char *) (&pSMBr->hdr.Protocol) + ++ le16_to_cpu(pSMBr->DataOffset); ++/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) { ++ cERROR(1,("Faulting on read rc = %d",rc)); ++ rc = -EFAULT; ++ }*/ /* can not use copy_to_user when using page cache*/ ++ if(*buf) ++ memcpy(*buf,pReadData,pSMBr->DataLength); ++ } ++ } ++ if (pSMB) { ++ if(*buf) ++ cifs_buf_release(pSMB); ++ else ++ *buf = (char *)pSMB; ++ } ++ ++ /* Note: On -EAGAIN error only caller can retry on handle based calls ++ since file handle passed in no longer valid */ ++ return rc; ++} ++ ++int ++CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, ++ const int netfid, const unsigned int count, ++ const __u64 offset, unsigned int *nbytes, const char *buf, ++ const int long_op) ++{ ++ int rc = -EACCES; ++ WRITE_REQ *pSMB = NULL; ++ WRITE_RSP *pSMBr = NULL; ++ int bytes_returned; ++ ++ rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ /* tcon and ses pointer are checked in smb_init */ ++ if (tcon->ses->server == NULL) ++ return -ECONNABORTED; ++ ++ pSMB->AndXCommand = 0xFF; /* none */ ++ pSMB->Fid = netfid; ++ pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); ++ pSMB->OffsetHigh = cpu_to_le32(offset >> 32); ++ pSMB->Remaining = 0; ++ if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00)) ++ pSMB->DataLengthLow = ++ (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00; ++ else ++ pSMB->DataLengthLow = count; ++ pSMB->DataLengthHigh = 0; ++ pSMB->DataOffset = ++ cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); ++ ++ memcpy(pSMB->Data,buf,pSMB->DataLengthLow); ++ ++ pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ; ++ pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow); ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, long_op); ++ if (rc) { ++ cFYI(1, ("Send error in write = %d", rc)); ++ *nbytes = 0; ++ } else ++ *nbytes = le16_to_cpu(pSMBr->Count); ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Note: On -EAGAIN error only caller can retry on handle based calls ++ since file handle passed in no longer valid */ ++ ++ return rc; ++} ++ ++int ++CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, ++ const __u16 smb_file_id, const __u64 len, ++ const __u64 offset, const __u32 numUnlock, ++ const __u32 numLock, const __u8 lockType, const int waitFlag) ++{ ++ int rc = 0; ++ LOCK_REQ *pSMB = NULL; ++ LOCK_RSP *pSMBr = NULL; ++ int bytes_returned; ++ int timeout = 0; ++ __u64 temp; ++ ++ cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock)); ++ rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) { ++ timeout = -1; /* no response expected */ ++ pSMB->Timeout = 0; ++ } else if (waitFlag == TRUE) { ++ timeout = 3; /* blocking operation, no timeout */ ++ pSMB->Timeout = -1; /* blocking - do not time out */ ++ } else { ++ pSMB->Timeout = 0; ++ } ++ ++ pSMB->NumberOfLocks = cpu_to_le32(numLock); ++ pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock); ++ pSMB->LockType = lockType; ++ pSMB->AndXCommand = 0xFF; /* none */ ++ pSMB->Fid = smb_file_id; /* netfid stays le */ ++ ++ if(numLock != 0) { ++ pSMB->Locks[0].Pid = cpu_to_le16(current->tgid); ++ /* BB where to store pid high? */ ++ temp = cpu_to_le64(len); ++ pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF); ++ pSMB->Locks[0].LengthHigh = (__u32)(temp>>32); ++ temp = cpu_to_le64(offset); ++ pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF); ++ pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32); ++ pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE); ++ } else { ++ /* oplock break */ ++ pSMB->ByteCount = 0; ++ } ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, timeout); ++ ++ if (rc) { ++ cFYI(1, ("Send error in Lock = %d", rc)); ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Note: On -EAGAIN error only caller can retry on handle based calls ++ since file handle passed in no longer valid */ ++ return rc; ++} ++ ++int ++CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) ++{ ++ int rc = 0; ++ CLOSE_REQ *pSMB = NULL; ++ CLOSE_RSP *pSMBr = NULL; ++ int bytes_returned; ++ cFYI(1, ("In CIFSSMBClose")); ++ ++/* do not retry on dead session on close */ ++ rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if(rc == -EAGAIN) ++ return 0; ++ if (rc) ++ return rc; ++ ++ pSMB->FileID = (__u16) smb_file_id; ++ pSMB->LastWriteTime = 0; ++ pSMB->ByteCount = 0; ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ if(rc!=-EINTR) { ++ /* EINTR is expected when user ctl-c to kill app */ ++ cERROR(1, ("Send error in Close = %d", rc)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Since session is dead, file will be closed on server already */ ++ if(rc == -EAGAIN) ++ rc = 0; ++ ++ return rc; ++} ++ ++int ++CIFSSMBRename(const int xid, struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage) ++{ ++ int rc = 0; ++ RENAME_REQ *pSMB = NULL; ++ RENAME_RSP *pSMBr = NULL; ++ int bytes_returned; ++ int name_len, name_len2; ++ ++ cFYI(1, ("In CIFSSMBRename")); ++renameRetry: ++ rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->BufferFormat = 0x04; ++ pSMB->SearchAttributes = ++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ++ ATTR_DIRECTORY); ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ pSMB->OldFileName[name_len] = 0x04; /* pad */ ++ /* protocol requires ASCII signature byte on Unicode string */ ++ pSMB->OldFileName[name_len + 1] = 0x00; ++ name_len2 = ++ cifs_strtoUCS((wchar_t *) & pSMB-> ++ OldFileName[name_len + 2], toName, 530, ++ nls_codepage); ++ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; ++ name_len2 *= 2; /* convert to bytes */ ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fromName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->OldFileName, fromName, name_len); ++ name_len2 = strnlen(toName, 530); ++ name_len2++; /* trailing null */ ++ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ ++ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); ++ name_len2++; /* trailing null */ ++ name_len2++; /* signature byte */ ++ } ++ ++ pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in rename = %d", rc)); ++ } ++ ++#ifdef CONFIG_CIFS_STATS ++ else { ++ atomic_inc(&tcon->num_renames); ++ } ++#endif ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto renameRetry; ++ ++ return rc; ++} ++ ++int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, ++ int netfid, char * target_name, const struct nls_table * nls_codepage) ++{ ++ struct smb_com_transaction2_sfi_req *pSMB = NULL; ++ struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; ++ struct set_file_rename * rename_info; ++ char *data_offset; ++ char dummy_string[30]; ++ int rc = 0; ++ int bytes_returned = 0; ++ int len_of_str; ++ ++ cFYI(1, ("Rename to File by handle")); ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->ParameterCount = 6; ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, ++ Fid) - 4; ++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; ++ ++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; ++ rename_info = (struct set_file_rename *) data_offset; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); ++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount; ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); ++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); ++ /* construct random name ".cifs_tmp<inodenum><mid>" */ ++ rename_info->overwrite = cpu_to_le32(1); ++ rename_info->root_fid = 0; ++ /* unicode only call */ ++ if(target_name == NULL) { ++ sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); ++ len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage); ++ } else { ++ len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage); ++ } ++ rename_info->target_name_len = cpu_to_le32(2 * len_of_str); ++ pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2; ++ pSMB->ByteCount += pSMB->DataCount; ++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount); ++ pSMB->TotalDataCount = pSMB->DataCount; ++ pSMB->Fid = netfid; ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1,("Send error in Rename (by file handle) = %d", rc)); ++ } ++#ifdef CONFIG_CIFS_STATS ++ else { ++ atomic_inc(&pTcon->num_t2renames); ++ } ++#endif ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Note: On -EAGAIN error only caller can retry on handle based calls ++ since file handle passed in no longer valid */ ++ ++ return rc; ++} ++ ++int ++CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, ++ const __u16 target_tid, const char *toName, const int flags, ++ const struct nls_table *nls_codepage) ++{ ++ int rc = 0; ++ COPY_REQ *pSMB = NULL; ++ COPY_RSP *pSMBr = NULL; ++ int bytes_returned; ++ int name_len, name_len2; ++ ++ cFYI(1, ("In CIFSSMBCopy")); ++copyRetry: ++ rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->BufferFormat = 0x04; ++ pSMB->Tid2 = target_tid; ++ ++ if(flags & COPY_TREE) ++ pSMB->Flags |= COPY_TREE; ++ pSMB->Flags = cpu_to_le16(pSMB->Flags); ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, ++ fromName, ++ 530 /* find define for this maxpathcomponent */, ++ nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ pSMB->OldFileName[name_len] = 0x04; /* pad */ ++ /* protocol requires ASCII signature byte on Unicode string */ ++ pSMB->OldFileName[name_len + 1] = 0x00; ++ name_len2 = cifs_strtoUCS((wchar_t *) & pSMB-> ++ OldFileName[name_len + 2], toName, 530, ++ nls_codepage); ++ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; ++ name_len2 *= 2; /* convert to bytes */ ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fromName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->OldFileName, fromName, name_len); ++ name_len2 = strnlen(toName, 530); ++ name_len2++; /* trailing null */ ++ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ ++ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); ++ name_len2++; /* trailing null */ ++ name_len2++; /* signature byte */ ++ } ++ ++ pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in copy = %d with %d files copied", ++ rc, pSMBr->CopyCount)); ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto copyRetry; ++ ++ return rc; ++} ++ ++int ++CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage) ++{ ++ TRANSACTION2_SPI_REQ *pSMB = NULL; ++ TRANSACTION2_SPI_RSP *pSMBr = NULL; ++ char *data_offset; ++ int name_len; ++ int name_len_target; ++ int rc = 0; ++ int bytes_returned = 0; ++ ++ cFYI(1, ("In Symlink Unix style")); ++createSymLinkRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fromName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, fromName, name_len); ++ } ++ pSMB->ParameterCount = 6 + name_len; ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, ++ InformationLevel) - 4; ++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; ++ ++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len_target = ++ cifs_strtoUCS((wchar_t *) data_offset, toName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len_target++; /* trailing null */ ++ name_len_target *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len_target = strnlen(toName, 530); ++ name_len_target++; /* trailing null */ ++ strncpy(data_offset, toName, name_len_target); ++ } ++ ++ pSMB->DataCount = name_len_target; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ /* BB find exact max on data count below from sess */ ++ pSMB->MaxDataCount = cpu_to_le16(1000); ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); ++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; ++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount); ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalDataCount = pSMB->DataCount; ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); ++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); ++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ++ ("Send error in SetPathInfo (create symlink) = %d", ++ rc)); ++ } ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto createSymLinkRetry; ++ ++ return rc; ++} ++ ++int ++CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage) ++{ ++ TRANSACTION2_SPI_REQ *pSMB = NULL; ++ TRANSACTION2_SPI_RSP *pSMBr = NULL; ++ char *data_offset; ++ int name_len; ++ int name_len_target; ++ int rc = 0; ++ int bytes_returned = 0; ++ ++ cFYI(1, ("In Create Hard link Unix style")); ++createHardLinkRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(toName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, toName, name_len); ++ } ++ pSMB->ParameterCount = 6 + name_len; ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, ++ InformationLevel) - 4; ++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; ++ ++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len_target = ++ cifs_strtoUCS((wchar_t *) data_offset, fromName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len_target++; /* trailing null */ ++ name_len_target *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len_target = strnlen(fromName, 530); ++ name_len_target++; /* trailing null */ ++ strncpy(data_offset, fromName, name_len_target); ++ } ++ ++ pSMB->DataCount = name_len_target; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ /* BB find exact max on data count below from sess*/ ++ pSMB->MaxDataCount = cpu_to_le16(1000); ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); ++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount); ++ pSMB->TotalDataCount = pSMB->DataCount; ++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); ++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); ++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); ++ } ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto createHardLinkRetry; ++ ++ return rc; ++} ++ ++int ++CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon, ++ const char *fromName, const char *toName, ++ const struct nls_table *nls_codepage) ++{ ++ int rc = 0; ++ NT_RENAME_REQ *pSMB = NULL; ++ RENAME_RSP *pSMBr = NULL; ++ int bytes_returned; ++ int name_len, name_len2; ++ ++ cFYI(1, ("In CIFSCreateHardLink")); ++winCreateHardLinkRetry: ++ ++ rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->SearchAttributes = ++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ++ ATTR_DIRECTORY); ++ pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK); ++ pSMB->ClusterCount = 0; ++ ++ pSMB->BufferFormat = 0x04; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ pSMB->OldFileName[name_len] = 0; /* pad */ ++ pSMB->OldFileName[name_len + 1] = 0x04; ++ name_len2 = ++ cifs_strtoUCS((wchar_t *) & pSMB-> ++ OldFileName[name_len + 2], toName, 530, ++ nls_codepage); ++ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; ++ name_len2 *= 2; /* convert to bytes */ ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fromName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->OldFileName, fromName, name_len); ++ name_len2 = strnlen(toName, 530); ++ name_len2++; /* trailing null */ ++ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */ ++ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2); ++ name_len2++; /* trailing null */ ++ name_len2++; /* signature byte */ ++ } ++ ++ pSMB->ByteCount = 1 /* string type byte */ + name_len + name_len2; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto winCreateHardLinkRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ char *symlinkinfo, const int buflen, ++ const struct nls_table *nls_codepage) ++{ ++/* SMB_QUERY_FILE_UNIX_LINK */ ++ TRANSACTION2_QPI_REQ *pSMB = NULL; ++ TRANSACTION2_QPI_RSP *pSMBr = NULL; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ ++ cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName)); ++ ++querySymLinkRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(searchName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, searchName, name_len); ++ } ++ ++ pSMB->TotalParameterCount = ++ 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ; ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ /* BB find exact max data count below from sess structure BB */ ++ pSMB->MaxDataCount = cpu_to_le16(4000); ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); ++ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) ++ /* BB also check enough total bytes returned */ ++ rc = -EIO; /* bad smb */ ++ else { ++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = UniStrnlen((wchar_t *) ((char *) ++ &pSMBr->hdr.Protocol +pSMBr->DataOffset), ++ min_t(const int, buflen,pSMBr->DataCount) / 2); ++ cifs_strfromUCS_le(symlinkinfo, ++ (wchar_t *) ((char *)&pSMBr->hdr.Protocol + ++ pSMBr->DataOffset), ++ name_len, nls_codepage); ++ } else { ++ strncpy(symlinkinfo, ++ (char *) &pSMBr->hdr.Protocol + ++ pSMBr->DataOffset, ++ min_t(const int, buflen, pSMBr->DataCount)); ++ } ++ symlinkinfo[buflen] = 0; ++ /* just in case so calling code does not go off the end of buffer */ ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto querySymLinkRetry; ++ return rc; ++} ++ ++ ++ ++int ++CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ char *symlinkinfo, const int buflen,__u16 fid, ++ const struct nls_table *nls_codepage) ++{ ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ struct smb_com_transaction_ioctl_req * pSMB; ++ struct smb_com_transaction_ioctl_rsp * pSMBr; ++ ++ cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName)); ++ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->TotalParameterCount = 0 ; ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le32(2); ++ /* BB find exact data count max from sess structure BB */ ++ pSMB->MaxDataCount = cpu_to_le32(4000); ++ pSMB->MaxSetupCount = 4; ++ pSMB->Reserved = 0; ++ pSMB->ParameterOffset = 0; ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 4; ++ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT); ++ pSMB->IsFsctl = 1; /* FSCTL */ ++ pSMB->IsRootFlag = 0; ++ pSMB->Fid = fid; /* file handle always le */ ++ pSMB->ByteCount = 0; ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); ++ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) ++ /* BB also check enough total bytes returned */ ++ rc = -EIO; /* bad smb */ ++ else { ++ if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) { ++ /* could also validate reparse tag && better check name length */ ++ struct reparse_data * reparse_buf = (struct reparse_data *) ++ ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset); ++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = UniStrnlen((wchar_t *) ++ (reparse_buf->LinkNamesBuf + ++ reparse_buf->TargetNameOffset), ++ min(buflen/2, reparse_buf->TargetNameLen / 2)); ++ cifs_strfromUCS_le(symlinkinfo, ++ (wchar_t *) (reparse_buf->LinkNamesBuf + ++ reparse_buf->TargetNameOffset), ++ name_len, nls_codepage); ++ } else { /* ASCII names */ ++ strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + ++ reparse_buf->TargetNameOffset, ++ min_t(const int, buflen, reparse_buf->TargetNameLen)); ++ } ++ } else { ++ rc = -EIO; ++ cFYI(1,("Invalid return data count on get reparse info ioctl")); ++ } ++ symlinkinfo[buflen] = 0; /* just in case so the caller ++ does not go off the end of the buffer */ ++ cFYI(1,("readlink result - %s ",symlinkinfo)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Note: On -EAGAIN error only caller can retry on handle based calls ++ since file handle passed in no longer valid */ ++ ++ return rc; ++} ++ ++int ++CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ FILE_ALL_INFO * pFindData, ++ const struct nls_table *nls_codepage) ++{ ++/* level 263 SMB_QUERY_FILE_ALL_INFO */ ++ TRANSACTION2_QPI_REQ *pSMB = NULL; ++ TRANSACTION2_QPI_RSP *pSMBr = NULL; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ ++ cFYI(1, ("In QPathInfo path %s", searchName)); ++QPathInfoRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(searchName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, searchName, name_len); ++ } ++ ++ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + ++ name_len /* includes null */ ; ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in QPathInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ /* BB also check enough total bytes returned */ ++ /* BB we need to improve the validity checking ++ of these trans2 responses */ ++ if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) ++ rc = -EIO; /* bad smb */ ++ else if (pFindData){ ++ memcpy((char *) pFindData, ++ (char *) &pSMBr->hdr.Protocol + ++ pSMBr->DataOffset, sizeof (FILE_ALL_INFO)); ++ } else ++ rc = -ENOMEM; ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto QPathInfoRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ FILE_UNIX_BASIC_INFO * pFindData, ++ const struct nls_table *nls_codepage) ++{ ++/* SMB_QUERY_FILE_UNIX_BASIC */ ++ TRANSACTION2_QPI_REQ *pSMB = NULL; ++ TRANSACTION2_QPI_RSP *pSMBr = NULL; ++ int rc = 0; ++ int bytes_returned = 0; ++ int name_len; ++ ++ cFYI(1, ("In QPathInfo (Unix) the path %s", searchName)); ++UnixQPathInfoRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(searchName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, searchName, name_len); ++ } ++ ++ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + ++ name_len /* includes null */ ; ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxDataCount = cpu_to_le16(4000); ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in QPathInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ /* BB also check if enough total bytes returned */ ++ if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) || ++ (pSMBr->DataOffset > 512) || ++ (pSMBr->DataOffset < sizeof(struct smb_hdr))) { ++ cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d", ++ (int)pSMBr->DataOffset,bytes_returned)); ++ rc = -EIO; /* bad smb */ ++ } else { ++ memcpy((char *) pFindData, ++ (char *) &pSMBr->hdr.Protocol + ++ pSMBr->DataOffset, ++ sizeof (FILE_UNIX_BASIC_INFO)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto UnixQPathInfoRetry; ++ ++ return rc; ++} ++ ++int ++CIFSFindSingle(const int xid, struct cifsTconInfo *tcon, ++ const char *searchName, FILE_ALL_INFO * findData, ++ const struct nls_table *nls_codepage) ++{ ++/* level 257 SMB_ */ ++ TRANSACTION2_FFIRST_REQ *pSMB = NULL; ++ TRANSACTION2_FFIRST_RSP *pSMBr = NULL; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ ++ cFYI(1, ("In FindUnique")); ++findUniqueRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(searchName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, searchName, name_len); ++ } ++ ++ pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; ++ pSMB->TotalDataCount = 0; /* no EAs */ ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = cpu_to_le16( ++ offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; /* one byte, no need to le convert */ ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->SearchAttributes = ++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ++ ATTR_DIRECTORY); ++ pSMB->SearchCount = cpu_to_le16(16); /* BB increase */ ++ pSMB->SearchFlags = cpu_to_le16(1); ++ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); ++ pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */ ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ ++ if (rc) { ++ cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); ++ } else { /* decode response */ ++ ++ /* BB fill in */ ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto findUniqueRetry; ++ ++ return rc; ++} ++ ++int ++CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, ++ const char *searchName, FILE_DIRECTORY_INFO * findData, ++ T2_FFIRST_RSP_PARMS * findParms, ++ const struct nls_table *nls_codepage, int *pUnicodeFlag, ++ int *pUnixFlag) ++{ ++/* level 257 SMB_ */ ++ TRANSACTION2_FFIRST_REQ *pSMB = NULL; ++ TRANSACTION2_FFIRST_RSP *pSMBr = NULL; ++ char *response_data; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ ++ cFYI(1, ("In FindFirst")); ++findFirstRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(searchName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, searchName, name_len); ++ } ++ ++ pSMB->TotalParameterCount = 12 + name_len /* includes null */ ; ++ pSMB->TotalDataCount = 0; /* no EAs */ ++ pSMB->MaxParameterCount = cpu_to_le16(10); ++ pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf - ++ MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct ++ smb_com_transaction2_ffirst_req, SearchAttributes) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; /* one byte no need to make endian neutral */ ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); ++ pSMB->SearchAttributes = ++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ++ ATTR_DIRECTORY); ++ pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */ ++ pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); ++ ++ /* test for Unix extensions */ ++ if (tcon->ses->capabilities & CAP_UNIX) { ++ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); ++ *pUnixFlag = TRUE; ++ } else { ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); ++ *pUnixFlag = FALSE; ++ } ++ pSMB->SearchStorageType = 0; /* BB what should we set this to? It is not clear if it matters BB */ ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ ++ if (rc) { /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ ++ cFYI(1, ("Error in FindFirst = %d", rc)); ++ } else { /* decode response */ ++ /* BB add safety checks for these memcpys */ ++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) ++ *pUnicodeFlag = TRUE; ++ else ++ *pUnicodeFlag = FALSE; ++ memcpy(findParms, ++ (char *) &pSMBr->hdr.Protocol + ++ le16_to_cpu(pSMBr->ParameterOffset), ++ sizeof (T2_FFIRST_RSP_PARMS)); ++ /* search handle can stay LE and EAoffset not needed so not converted */ ++ findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); ++ findParms->LastNameOffset = ++ le16_to_cpu(findParms->LastNameOffset); ++ findParms->SearchCount = le16_to_cpu(findParms->SearchCount); ++ response_data = ++ (char *) &pSMBr->hdr.Protocol + ++ le16_to_cpu(pSMBr->DataOffset); ++ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto findFirstRetry; ++ ++ return rc; ++} ++ ++int ++CIFSFindNext(const int xid, struct cifsTconInfo *tcon, ++ FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms, ++ const __u16 searchHandle, char * resume_file_name, int name_len, ++ __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag) ++{ ++/* level 257 SMB_ */ ++ TRANSACTION2_FNEXT_REQ *pSMB = NULL; ++ TRANSACTION2_FNEXT_RSP *pSMBr = NULL; ++ char *response_data; ++ int rc = 0; ++ int bytes_returned; ++ ++ cFYI(1, ("In FindNext")); ++ ++ if(resume_file_name == NULL) { ++ return -EIO; ++ } ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */ ++ pSMB->TotalDataCount = 0; /* no EAs */ ++ pSMB->MaxParameterCount = cpu_to_le16(8); ++ pSMB->MaxDataCount = ++ cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_fnext_req,SearchHandle) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT); ++ pSMB->SearchHandle = searchHandle; /* always kept as le */ ++ findParms->SearchCount = 0; /* set to zero in case of error */ ++ pSMB->SearchCount = ++ cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); ++ /* test for Unix extensions */ ++ if (tcon->ses->capabilities & CAP_UNIX) { ++ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX); ++ *pUnixFlag = TRUE; ++ } else { ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO); ++ *pUnixFlag = FALSE; ++ } ++ pSMB->ResumeKey = resume_key; ++ pSMB->SearchFlags = ++ cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME); ++ /* BB add check to make sure we do not cross end of smb */ ++ if(name_len < CIFS_MAX_MSGSIZE) { ++ memcpy(pSMB->ResumeFileName, resume_file_name, name_len); ++ pSMB->ByteCount += name_len; ++ } ++ pSMB->TotalParameterCount += name_len; ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ /* BB improve error handling here */ ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ ++ if (rc) { ++ if (rc == -EBADF) ++ rc = 0; /* search probably was closed at end of search above */ ++ else ++ cFYI(1, ("FindNext returned = %d", rc)); ++ } else { /* decode response */ ++ /* BB add safety checks for these memcpys */ ++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) ++ *pUnicodeFlag = TRUE; ++ else ++ *pUnicodeFlag = FALSE; ++ memcpy(findParms, ++ (char *) &pSMBr->hdr.Protocol + ++ le16_to_cpu(pSMBr->ParameterOffset), ++ sizeof (T2_FNEXT_RSP_PARMS)); ++ findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch); ++ findParms->LastNameOffset = ++ le16_to_cpu(findParms->LastNameOffset); ++ findParms->SearchCount = le16_to_cpu(findParms->SearchCount); ++ response_data = ++ (char *) &pSMBr->hdr.Protocol + ++ le16_to_cpu(pSMBr->DataOffset); ++ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount)); ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Note: On -EAGAIN error only caller can retry on handle based calls ++ since file handle passed in no longer valid */ ++ ++ return rc; ++} ++ ++int ++CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle) ++{ ++ int rc = 0; ++ FINDCLOSE_REQ *pSMB = NULL; ++ CLOSE_RSP *pSMBr = NULL; ++ int bytes_returned; ++ ++ cFYI(1, ("In CIFSSMBFindClose")); ++ rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ /* no sense returning error if session restarted ++ file handle has been closed */ ++ if(rc == -EAGAIN) ++ return 0; ++ if (rc) ++ return rc; ++ ++ pSMB->FileID = searchHandle; ++ pSMB->ByteCount = 0; ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cERROR(1, ("Send error in FindClose = %d", rc)); ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Since session is dead, search handle closed on server already */ ++ if (rc == -EAGAIN) ++ rc = 0; ++ ++ return rc; ++} ++ ++int ++CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses, ++ const unsigned char *searchName, ++ unsigned char **targetUNCs, ++ unsigned int *number_of_UNC_in_array, ++ const struct nls_table *nls_codepage) ++{ ++/* TRANS2_GET_DFS_REFERRAL */ ++ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL; ++ TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL; ++ struct dfs_referral_level_3 * referrals = NULL; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ unsigned int i; ++ char * temp; ++ *number_of_UNC_in_array = 0; ++ *targetUNCs = NULL; ++ ++ cFYI(1, ("In GetDFSRefer the path %s", searchName)); ++ if (ses == NULL) ++ return -ENODEV; ++getDFSRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->hdr.Tid = ses->ipc_tid; ++ pSMB->hdr.Uid = ses->Suid; ++ if (ses->capabilities & CAP_STATUS32) { ++ pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; ++ } ++ if (ses->capabilities & CAP_DFS) { ++ pSMB->hdr.Flags2 |= SMBFLG2_DFS; ++ } ++ ++ if (ses->capabilities & CAP_UNICODE) { ++ pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->RequestFileName, ++ searchName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(searchName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->RequestFileName, searchName, name_len); ++ } ++ ++ pSMB->ParameterCount = 2 /* level */ + name_len /*includes null */ ; ++ pSMB->TotalDataCount = 0; ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->MaxParameterCount = 0; ++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4); ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL); ++ pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ; ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->MaxReferralLevel = cpu_to_le16(3); ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in GetDFSRefer = %d", rc)); ++ } else { /* decode response */ ++/* BB Add logic to parse referrals here */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount); ++ cFYI(1, ++ ("Decoding GetDFSRefer response. BCC: %d Offset %d", ++ pSMBr->ByteCount, pSMBr->DataOffset)); ++ if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ ++ rc = -EIO; /* bad smb */ ++ else { ++ referrals = ++ (struct dfs_referral_level_3 *) ++ (8 /* sizeof start of data block */ + ++ pSMBr->DataOffset + ++ (char *) &pSMBr->hdr.Protocol); ++ 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",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive)); ++ /* BB This field is actually two bytes in from start of ++ data block so we could do safety check that DataBlock ++ begins at address of pSMBr->NumberOfReferrals */ ++ *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals); ++ ++ /* BB Fix below so can return more than one referral */ ++ if(*number_of_UNC_in_array > 1) ++ *number_of_UNC_in_array = 1; ++ ++ /* get the length of the strings describing refs */ ++ name_len = 0; ++ for(i=0;i<*number_of_UNC_in_array;i++) { ++ /* make sure that DfsPathOffset not past end */ ++ referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset); ++ if(referrals->DfsPathOffset > pSMBr->DataCount) { ++ /* if invalid referral, stop here and do ++ not try to copy any more */ ++ *number_of_UNC_in_array = i; ++ break; ++ } ++ temp = ((char *)referrals) + referrals->DfsPathOffset; ++ ++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount); ++ } else { ++ name_len += strnlen(temp,pSMBr->DataCount); ++ } ++ referrals++; ++ /* BB add check that referral pointer does not fall off end PDU */ ++ ++ } ++ /* BB add check for name_len bigger than bcc */ ++ *targetUNCs = ++ kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL); ++ /* copy the ref strings */ ++ referrals = ++ (struct dfs_referral_level_3 *) ++ (8 /* sizeof data hdr */ + ++ pSMBr->DataOffset + ++ (char *) &pSMBr->hdr.Protocol); ++ ++ for(i=0;i<*number_of_UNC_in_array;i++) { ++ temp = ((char *)referrals) + referrals->DfsPathOffset; ++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { ++ cifs_strfromUCS_le(*targetUNCs, ++ (wchar_t *) temp, name_len, nls_codepage); ++ } else { ++ strncpy(*targetUNCs,temp,name_len); ++ } ++ /* BB update target_uncs pointers */ ++ referrals++; ++ } ++ temp = *targetUNCs; ++ temp[name_len] = 0; ++ } ++ ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto getDFSRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, ++ struct statfs *FSData, const struct nls_table *nls_codepage) ++{ ++/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */ ++ TRANSACTION2_QFSI_REQ *pSMB = NULL; ++ TRANSACTION2_QFSI_RSP *pSMBr = NULL; ++ FILE_SYSTEM_INFO *response_data; ++ int rc = 0; ++ int bytes_returned = 0; ++ ++ cFYI(1, ("In QFSInfo")); ++QFSInfoRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->TotalParameterCount = 2; /* level */ ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); ++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO); ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cERROR(1, ("Send error in QFSInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ cFYI(1, ++ ("Decoding qfsinfo response. BCC: %d Offset %d", ++ pSMBr->ByteCount, pSMBr->DataOffset)); ++ if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */ ++ rc = -EIO; /* bad smb */ ++ else { ++ response_data = ++ (FILE_SYSTEM_INFO ++ *) (((char *) &pSMBr->hdr.Protocol) + ++ pSMBr->DataOffset); ++ FSData->f_bsize = ++ le32_to_cpu(response_data->BytesPerSector) * ++ le32_to_cpu(response_data-> ++ SectorsPerAllocationUnit); ++ FSData->f_blocks = ++ le64_to_cpu(response_data->TotalAllocationUnits); ++ FSData->f_bfree = FSData->f_bavail = ++ le64_to_cpu(response_data->FreeAllocationUnits); ++ cFYI(1, ++ ("Blocks: %lld Free: %lld Block size %ld", ++ (unsigned long long)FSData->f_blocks, ++ (unsigned long long)FSData->f_bfree, ++ FSData->f_bsize)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto QFSInfoRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon, ++ const struct nls_table *nls_codepage) ++{ ++/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */ ++ TRANSACTION2_QFSI_REQ *pSMB = NULL; ++ TRANSACTION2_QFSI_RSP *pSMBr = NULL; ++ FILE_SYSTEM_ATTRIBUTE_INFO *response_data; ++ int rc = 0; ++ int bytes_returned = 0; ++ ++ cFYI(1, ("In QFSAttributeInfo")); ++QFSAttributeRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->TotalParameterCount = 2; /* level */ ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); ++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO); ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cERROR(1, ("Send error in QFSAttributeInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { /* BB also check enough bytes returned */ ++ rc = -EIO; /* bad smb */ ++ } else { ++ response_data = ++ (FILE_SYSTEM_ATTRIBUTE_INFO ++ *) (((char *) &pSMBr->hdr.Protocol) + ++ pSMBr->DataOffset); ++ response_data->Attributes = le32_to_cpu(response_data->Attributes); ++ response_data->MaxPathNameComponentLength = ++ le32_to_cpu(response_data->MaxPathNameComponentLength); ++ response_data->FileSystemNameLen = ++ le32_to_cpu(response_data->FileSystemNameLen); ++ memcpy(&tcon->fsAttrInfo, response_data, ++ sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto QFSAttributeRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon, ++ const struct nls_table *nls_codepage) ++{ ++/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */ ++ TRANSACTION2_QFSI_REQ *pSMB = NULL; ++ TRANSACTION2_QFSI_RSP *pSMBr = NULL; ++ FILE_SYSTEM_DEVICE_INFO *response_data; ++ int rc = 0; ++ int bytes_returned = 0; ++ ++ cFYI(1, ("In QFSDeviceInfo")); ++QFSDeviceRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->TotalParameterCount = 2; /* level */ ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); ++ ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); ++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO); ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in QFSDeviceInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)) ++ || (pSMBr->DataOffset > 512)) ++ rc = -EIO; /* bad smb */ ++ else { ++ response_data = ++ (FILE_SYSTEM_DEVICE_INFO ++ *) (((char *) &pSMBr->hdr.Protocol) + ++ pSMBr->DataOffset); ++ response_data->DeviceType = ++ le32_to_cpu(response_data->DeviceType); ++ response_data->DeviceCharacteristics = ++ le32_to_cpu(response_data->DeviceCharacteristics); ++ memcpy(&tcon->fsDevInfo, response_data, ++ sizeof (FILE_SYSTEM_DEVICE_INFO)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto QFSDeviceRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon, ++ const struct nls_table *nls_codepage) ++{ ++/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */ ++ TRANSACTION2_QFSI_REQ *pSMB = NULL; ++ TRANSACTION2_QFSI_RSP *pSMBr = NULL; ++ FILE_SYSTEM_UNIX_INFO *response_data; ++ int rc = 0; ++ int bytes_returned = 0; ++ ++ cFYI(1, ("In QFSUnixInfo")); ++QFSUnixRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->ParameterCount = 2; /* level */ ++ pSMB->TotalDataCount = 0; ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ; ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct ++ smb_com_transaction2_qfsi_req, InformationLevel) - 4); ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); ++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO); ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cERROR(1, ("Send error in QFSUnixInfo = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset); ++ if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { ++ rc = -EIO; /* bad smb */ ++ } else { ++ response_data = ++ (FILE_SYSTEM_UNIX_INFO ++ *) (((char *) &pSMBr->hdr.Protocol) + ++ pSMBr->DataOffset); ++ response_data->MajorVersionNumber = ++ le16_to_cpu(response_data->MajorVersionNumber); ++ response_data->MinorVersionNumber = ++ le16_to_cpu(response_data->MinorVersionNumber); ++ response_data->Capability = ++ le64_to_cpu(response_data->Capability); ++ memcpy(&tcon->fsUnixInfo, response_data, ++ sizeof (FILE_SYSTEM_UNIX_INFO)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto QFSUnixRetry; ++ ++ ++ return rc; ++} ++ ++/* We can not use write of zero bytes trick to ++ set file size due to need for large file support. Also note that ++ this SetPathInfo is preferred to SetFileInfo based method in next ++ routine which is only needed to work around a sharing violation bug ++ in Samba which this routine can run into */ ++ ++int ++CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName, ++ __u64 size, int SetAllocation, const struct nls_table *nls_codepage) ++{ ++ struct smb_com_transaction2_spi_req *pSMB = NULL; ++ struct smb_com_transaction2_spi_rsp *pSMBr = NULL; ++ struct file_end_of_file_info *parm_data; ++ int name_len; ++ int rc = 0; ++ int bytes_returned = 0; ++ ++ cFYI(1, ("In SetEOF")); ++SetEOFRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fileName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, fileName, name_len); ++ } ++ pSMB->ParameterCount = 6 + name_len; ++ pSMB->DataCount = sizeof (struct file_end_of_file_info); ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, ++ InformationLevel) - 4; ++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; ++ if(SetAllocation) { ++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); ++ else ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); ++ } else /* Set File Size */ { ++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); ++ else ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); ++ } ++ ++ parm_data = ++ (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + ++ pSMB->DataOffset); ++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); ++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); ++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; ++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount); ++ pSMB->TotalDataCount = pSMB->DataCount; ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ parm_data->FileSize = cpu_to_le64(size); ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("SetPathInfo (file size) returned %d", rc)); ++ } ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto SetEOFRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, ++ __u16 fid, __u32 pid_of_opener, int SetAllocation) ++{ ++ struct smb_com_transaction2_sfi_req *pSMB = NULL; ++ struct smb_com_transaction2_sfi_rsp *pSMBr = NULL; ++ char *data_offset; ++ struct file_end_of_file_info *parm_data; ++ int rc = 0; ++ int bytes_returned = 0; ++ __u32 tmp; ++ ++ cFYI(1, ("SetFileSize (via SetFileInfo) %lld", ++ (long long)size)); ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ tmp = cpu_to_le32(pid_of_opener); /* override pid of current process ++ so network fid will be valid */ ++ pSMB->hdr.Pid = tmp & 0xFFFF; ++ tmp >>= 16; ++ pSMB->hdr.PidHigh = tmp & 0xFFFF; ++ ++ pSMB->ParameterCount = 6; ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req, ++ Fid) - 4; ++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; ++ ++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; ++ ++ pSMB->DataCount = sizeof(struct file_end_of_file_info); ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION); ++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; ++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount); ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalDataCount = pSMB->DataCount; ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); ++ parm_data = ++ (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) + ++ pSMB->DataOffset); ++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */ ++ parm_data->FileSize = cpu_to_le64(size); ++ pSMB->Fid = fid; ++ if(SetAllocation) { ++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2); ++ else ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO); ++ } else /* Set File Size */ { ++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2); ++ else ++ pSMB->InformationLevel = ++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO); ++ } ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ++ ("Send error in SetFileInfo (SetFileSize) = %d", ++ rc)); ++ } ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ /* Note: On -EAGAIN error only caller can retry on handle based calls ++ since file handle passed in no longer valid */ ++ ++ return rc; ++} ++ ++int ++CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName, ++ FILE_BASIC_INFO * data, const struct nls_table *nls_codepage) ++{ ++ TRANSACTION2_SPI_REQ *pSMB = NULL; ++ TRANSACTION2_SPI_RSP *pSMBr = NULL; ++ int name_len; ++ int rc = 0; ++ int bytes_returned = 0; ++ char *data_offset; ++ ++ cFYI(1, ("In SetTimes")); ++ ++SetTimesRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fileName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, fileName, name_len); ++ } ++ ++ pSMB->ParameterCount = 6 + name_len; ++ pSMB->DataCount = sizeof (FILE_BASIC_INFO); ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, ++ InformationLevel) - 4; ++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; ++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset; ++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); ++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); ++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; ++ ++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount); ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->TotalDataCount = pSMB->DataCount; ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU) ++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2); ++ else ++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("SetPathInfo (times) returned %d", rc)); ++ } ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ ++ if (rc == -EAGAIN) ++ goto SetTimesRetry; ++ ++ return rc; ++} ++ ++int ++CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon, ++ char *fileName, __u64 mode, __u64 uid, __u64 gid, ++ dev_t device, const struct nls_table *nls_codepage) ++{ ++ TRANSACTION2_SPI_REQ *pSMB = NULL; ++ TRANSACTION2_SPI_RSP *pSMBr = NULL; ++ int name_len; ++ int rc = 0; ++ int bytes_returned = 0; ++ FILE_UNIX_BASIC_INFO *data_offset; ++ ++ cFYI(1, ("In SetUID/GID/Mode")); ++setPermsRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(fileName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, fileName, name_len); ++ } ++ ++ pSMB->ParameterCount = 6 + name_len; ++ pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO); ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req, ++ InformationLevel) - 4; ++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount; ++ data_offset = ++ (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol + ++ pSMB->DataOffset); ++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); ++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset); ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION); ++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount; ++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount); ++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount); ++ pSMB->TotalParameterCount = pSMB->ParameterCount; ++ pSMB->TotalDataCount = pSMB->DataCount; ++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ data_offset->Uid = cpu_to_le64(uid); ++ data_offset->Gid = cpu_to_le64(gid); ++ /* better to leave device as zero when it is */ ++ data_offset->DevMajor = cpu_to_le64(MAJOR(device)); ++ data_offset->DevMinor = cpu_to_le64(MINOR(device)); ++ data_offset->Permissions = cpu_to_le64(mode); ++ ++ if(S_ISREG(mode)) ++ data_offset->Type = cpu_to_le32(UNIX_FILE); ++ else if(S_ISDIR(mode)) ++ data_offset->Type = cpu_to_le32(UNIX_DIR); ++ else if(S_ISLNK(mode)) ++ data_offset->Type = cpu_to_le32(UNIX_SYMLINK); ++ else if(S_ISCHR(mode)) ++ data_offset->Type = cpu_to_le32(UNIX_CHARDEV); ++ else if(S_ISBLK(mode)) ++ data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV); ++ else if(S_ISFIFO(mode)) ++ data_offset->Type = cpu_to_le32(UNIX_FIFO); ++ else if(S_ISSOCK(mode)) ++ data_offset->Type = cpu_to_le32(UNIX_SOCKET); ++ ++ ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("SetPathInfo (perms) returned %d", rc)); ++ } ++ ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto setPermsRetry; ++ return rc; ++} ++ ++int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, ++ const int notify_subdirs, const __u16 netfid, ++ __u32 filter, const struct nls_table *nls_codepage) ++{ ++ int rc = 0; ++ struct smb_com_transaction_change_notify_req * pSMB = NULL; ++ struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; ++ int bytes_returned; ++ ++ cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); ++ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ pSMB->TotalParameterCount = 0 ; ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le32(2); ++ /* BB find exact data count max from sess structure BB */ ++ pSMB->MaxDataCount = 0; /* same in little endian or be */ ++ pSMB->MaxSetupCount = 4; ++ pSMB->Reserved = 0; ++ pSMB->ParameterOffset = 0; ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 4; /* single byte does not need le conversion */ ++ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ if(notify_subdirs) ++ pSMB->WatchTree = 1; /* one byte - no le conversion needed */ ++ pSMB->Reserved2 = 0; ++ pSMB->CompletionFilter = cpu_to_le32(filter); ++ pSMB->Fid = netfid; /* file handle always le */ ++ pSMB->ByteCount = 0; ++ ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Error in Notify = %d", rc)); ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++/* if (rc == -EAGAIN) ++ goto NotifyRetry; */ ++ return rc; ++} ++#ifdef CONFIG_CIFS_XATTR ++int ++CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, ++ const unsigned char *searchName, ++ char * EAData, size_t size, ++ const struct nls_table *nls_codepage) ++{ ++ /* BB assumes one setup word */ ++ TRANSACTION2_QPI_REQ *pSMB = NULL; ++ TRANSACTION2_QPI_RSP *pSMBr = NULL; ++ int rc = 0; ++ int bytes_returned; ++ int name_len; ++ ++ cFYI(1, ("In Query All EAs path %s", searchName)); ++QAllEAsRetry: ++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, ++ (void **) &pSMBr); ++ if (rc) ++ return rc; ++ ++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { ++ name_len = ++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530 ++ /* find define for this maxpathcomponent */ ++ , nls_codepage); ++ name_len++; /* trailing null */ ++ name_len *= 2; ++ } else { /* BB improve the check for buffer overruns BB */ ++ name_len = strnlen(searchName, 530); ++ name_len++; /* trailing null */ ++ strncpy(pSMB->FileName, searchName, name_len); ++ } ++ ++ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ + ++ name_len /* includes null */ ; ++ pSMB->TotalDataCount = 0; ++ pSMB->MaxParameterCount = cpu_to_le16(2); ++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */ ++ pSMB->MaxSetupCount = 0; ++ pSMB->Reserved = 0; ++ pSMB->Flags = 0; ++ pSMB->Timeout = 0; ++ pSMB->Reserved2 = 0; ++ pSMB->ParameterOffset = cpu_to_le16(offsetof( ++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4); ++ pSMB->DataCount = 0; ++ pSMB->DataOffset = 0; ++ pSMB->SetupCount = 1; ++ pSMB->Reserved3 = 0; ++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION); ++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ; ++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount); ++ pSMB->ParameterCount = pSMB->TotalParameterCount; ++ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS); ++ pSMB->Reserved4 = 0; ++ pSMB->hdr.smb_buf_length += pSMB->ByteCount; ++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount); ++ ++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, ++ (struct smb_hdr *) pSMBr, &bytes_returned, 0); ++ if (rc) { ++ cFYI(1, ("Send error in QueryAllEAs = %d", rc)); ++ } else { /* decode response */ ++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset); ++ /* BB also check enough total bytes returned */ ++ /* BB we need to improve the validity checking ++ of these trans2 responses */ ++ if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) ++ rc = -EIO; /* bad smb */ ++ /* else if (pFindData){ ++ memcpy((char *) pFindData, ++ (char *) &pSMBr->hdr.Protocol + ++ pSMBr->DataOffset, kl); ++ }*/ else { ++ /* check that length of list is not more than bcc */ ++ /* check that each entry does not go beyond length ++ of list */ ++ /* check that each element of each entry does not ++ go beyond end of list */ ++ struct fealist * ea_response_data; ++ rc = 0; ++ /* validate_trans2_offsets() */ ++ /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/ ++ ea_response_data = (struct fealist *) ++ (((char *) &pSMBr->hdr.Protocol) + ++ pSMBr->DataOffset); ++ cFYI(1,("ea length %d",ea_response_data->list_len)); ++ } ++ } ++ if (pSMB) ++ cifs_buf_release(pSMB); ++ if (rc == -EAGAIN) ++ goto QAllEAsRetry; ++ ++ return rc; ++} ++#endif +diff -urN linux-2.4.29.old/fs/cifs/cifs_unicode.c linux-2.4.29/fs/cifs/cifs_unicode.c +--- linux-2.4.29.old/fs/cifs/cifs_unicode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifs_unicode.c 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,87 @@ ++/* ++ * fs/cifs/cifs_unicode.c ++ * ++ * Copyright (c) International Business Machines Corp., 2000,2002 ++ * Modified by Steve French (sfrench@us.ibm.com) ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/fs.h> ++#include "cifs_unicode.h" ++#include "cifs_uniupr.h" ++#include "cifspdu.h" ++#include "cifs_debug.h" ++ ++/* ++ * NAME: cifs_strfromUCS() ++ * ++ * FUNCTION: Convert little-endian unicode string to character string ++ * ++ */ ++int ++cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ ++ int len, const struct nls_table *codepage) ++{ ++ int i; ++ int outlen = 0; ++ ++ for (i = 0; (i < len) && from[i]; i++) { ++ int charlen; ++ /* 2.4.0 kernel or greater */ ++ charlen = ++ codepage->uni2char(le16_to_cpu(from[i]), &to[outlen], ++ NLS_MAX_CHARSET_SIZE); ++ if (charlen > 0) { ++ outlen += charlen; ++ } else { ++ to[outlen++] = '?'; ++ } ++ } ++ to[outlen] = 0; ++ return outlen; ++} ++ ++/* ++ * NAME: cifs_strtoUCS() ++ * ++ * FUNCTION: Convert character string to unicode string ++ * ++ */ ++int ++cifs_strtoUCS(wchar_t * to, const char *from, int len, ++ const struct nls_table *codepage) ++{ ++ int charlen; ++ int i; ++ ++ for (i = 0; len && *from; i++, from += charlen, len -= charlen) { ++ ++ /* works for 2.4.0 kernel or later */ ++ charlen = codepage->char2uni(from, len, &to[i]); ++ if (charlen < 1) { ++ cERROR(1, ++ ("cifs_strtoUCS: char2uni returned %d", ++ charlen)); ++ to[i] = cpu_to_le16(0x003f); /* a question mark */ ++ charlen = 1; ++ } ++ to[i] = cpu_to_le16(to[i]); ++ ++ } ++ ++ to[i] = 0; ++ return i; ++} ++ +diff -urN linux-2.4.29.old/fs/cifs/cifs_unicode.h linux-2.4.29/fs/cifs/cifs_unicode.h +--- linux-2.4.29.old/fs/cifs/cifs_unicode.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifs_unicode.h 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,353 @@ ++/* ++ * cifs_unicode: Unicode kernel case support ++ * ++ * Function: ++ * Convert a unicode character to upper or lower case using ++ * compressed tables. ++ * ++ * Copyright (c) International Business Machines Corp., 2000,2002 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * ++ * Notes: ++ * These APIs are based on the C library functions. The semantics ++ * should match the C functions but with expanded size operands. ++ * ++ * The upper/lower functions are based on a table created by mkupr. ++ * This is a compressed table of upper and lower case conversion. ++ * ++ */ ++ ++#include <asm/byteorder.h> ++#include <linux/types.h> ++#include <linux/nls.h> ++ ++#define UNIUPR_NOLOWER /* Example to not expand lower case tables */ ++ ++/* Just define what we want from uniupr.h. We don't want to define the tables ++ * in each source file. ++ */ ++#ifndef UNICASERANGE_DEFINED ++struct UniCaseRange { ++ wchar_t start; ++ wchar_t end; ++ signed char *table; ++}; ++#endif /* UNICASERANGE_DEFINED */ ++ ++#ifndef UNIUPR_NOUPPER ++extern signed char CifsUniUpperTable[512]; ++extern const struct UniCaseRange CifsUniUpperRange[]; ++#endif /* UNIUPR_NOUPPER */ ++ ++#ifndef UNIUPR_NOLOWER ++extern signed char UniLowerTable[512]; ++extern struct UniCaseRange UniLowerRange[]; ++#endif /* UNIUPR_NOLOWER */ ++ ++#ifdef __KERNEL__ ++int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); ++int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); ++#endif ++ ++/* ++ * UniStrcat: Concatenate the second string to the first ++ * ++ * Returns: ++ * Address of the first string ++ */ ++static inline wchar_t * ++UniStrcat(wchar_t * ucs1, const wchar_t * ucs2) ++{ ++ wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */ ++ ++ while (*ucs1++) ; /* To end of first string */ ++ ucs1--; /* Return to the null */ ++ while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */ ++ return anchor; ++} ++ ++/* ++ * UniStrchr: Find a character in a string ++ * ++ * Returns: ++ * Address of first occurrence of character in string ++ * or NULL if the character is not in the string ++ */ ++static inline wchar_t * ++UniStrchr(const wchar_t * ucs, wchar_t uc) ++{ ++ while ((*ucs != uc) && *ucs) ++ ucs++; ++ ++ if (*ucs == uc) ++ return (wchar_t *) ucs; ++ return NULL; ++} ++ ++/* ++ * UniStrcmp: Compare two strings ++ * ++ * Returns: ++ * < 0: First string is less than second ++ * = 0: Strings are equal ++ * > 0: First string is greater than second ++ */ ++static inline int ++UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2) ++{ ++ while ((*ucs1 == *ucs2) && *ucs1) { ++ ucs1++; ++ ucs2++; ++ } ++ return (int) *ucs1 - (int) *ucs2; ++} ++ ++/* ++ * UniStrcpy: Copy a string ++ */ ++static inline wchar_t * ++UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2) ++{ ++ wchar_t *anchor = ucs1; /* save the start of result string */ ++ ++ while ((*ucs1++ = *ucs2++)) ; ++ return anchor; ++} ++ ++/* ++ * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes) ++ */ ++static inline size_t ++UniStrlen(const wchar_t * ucs1) ++{ ++ int i = 0; ++ ++ while (*ucs1++) ++ i++; ++ return i; ++} ++ ++/* ++ * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited) ++ */ ++static inline size_t ++UniStrnlen(const wchar_t * ucs1, int maxlen) ++{ ++ int i = 0; ++ ++ while (*ucs1++) { ++ i++; ++ if (i >= maxlen) ++ break; ++ } ++ return i; ++} ++ ++/* ++ * UniStrncat: Concatenate length limited string ++ */ ++static inline wchar_t * ++UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n) ++{ ++ wchar_t *anchor = ucs1; /* save pointer to string 1 */ ++ ++ while (*ucs1++) ; ++ ucs1--; /* point to null terminator of s1 */ ++ while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */ ++ ucs1++; ++ ucs2++; ++ } ++ *ucs1 = 0; /* Null terminate the result */ ++ return (anchor); ++} ++ ++/* ++ * UniStrncmp: Compare length limited string ++ */ ++static inline int ++UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) ++{ ++ if (!n) ++ return 0; /* Null strings are equal */ ++ while ((*ucs1 == *ucs2) && *ucs1 && --n) { ++ ucs1++; ++ ucs2++; ++ } ++ return (int) *ucs1 - (int) *ucs2; ++} ++ ++/* ++ * UniStrncmp_le: Compare length limited string - native to little-endian ++ */ ++static inline int ++UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n) ++{ ++ if (!n) ++ return 0; /* Null strings are equal */ ++ while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) { ++ ucs1++; ++ ucs2++; ++ } ++ return (int) *ucs1 - (int) __le16_to_cpu(*ucs2); ++} ++ ++/* ++ * UniStrncpy: Copy length limited string with pad ++ */ ++static inline wchar_t * ++UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n) ++{ ++ wchar_t *anchor = ucs1; ++ ++ while (n-- && *ucs2) /* Copy the strings */ ++ *ucs1++ = *ucs2++; ++ ++ n++; ++ while (n--) /* Pad with nulls */ ++ *ucs1++ = 0; ++ return anchor; ++} ++ ++/* ++ * UniStrncpy_le: Copy length limited string with pad to little-endian ++ */ ++static inline wchar_t * ++UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n) ++{ ++ wchar_t *anchor = ucs1; ++ ++ while (n-- && *ucs2) /* Copy the strings */ ++ *ucs1++ = __le16_to_cpu(*ucs2++); ++ ++ n++; ++ while (n--) /* Pad with nulls */ ++ *ucs1++ = 0; ++ return anchor; ++} ++ ++/* ++ * UniStrstr: Find a string in a string ++ * ++ * Returns: ++ * Address of first match found ++ * NULL if no matching string is found ++ */ ++static inline wchar_t * ++UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2) ++{ ++ const wchar_t *anchor1 = ucs1; ++ const wchar_t *anchor2 = ucs2; ++ ++ while (*ucs1) { ++ if (*ucs1 == *ucs2) { /* Partial match found */ ++ ucs1++; ++ ucs2++; ++ } else { ++ if (!*ucs2) /* Match found */ ++ return (wchar_t *) anchor1; ++ ucs1 = ++anchor1; /* No match */ ++ ucs2 = anchor2; ++ } ++ } ++ ++ if (!*ucs2) /* Both end together */ ++ return (wchar_t *) anchor1; /* Match found */ ++ return NULL; /* No match */ ++} ++ ++#ifndef UNIUPR_NOUPPER ++/* ++ * UniToupper: Convert a unicode character to upper case ++ */ ++static inline wchar_t ++UniToupper(register wchar_t uc) ++{ ++ register const struct UniCaseRange *rp; ++ ++ if (uc < sizeof (CifsUniUpperTable)) { /* Latin characters */ ++ return uc + CifsUniUpperTable[uc]; /* Use base tables */ ++ } else { ++ rp = CifsUniUpperRange; /* Use range tables */ ++ while (rp->start) { ++ if (uc < rp->start) /* Before start of range */ ++ return uc; /* Uppercase = input */ ++ if (uc <= rp->end) /* In range */ ++ return uc + rp->table[uc - rp->start]; ++ rp++; /* Try next range */ ++ } ++ } ++ return uc; /* Past last range */ ++} ++ ++/* ++ * UniStrupr: Upper case a unicode string ++ */ ++static inline wchar_t * ++UniStrupr(register wchar_t * upin) ++{ ++ register wchar_t *up; ++ ++ up = upin; ++ while (*up) { /* For all characters */ ++ *up = UniToupper(*up); ++ up++; ++ } ++ return upin; /* Return input pointer */ ++} ++#endif /* UNIUPR_NOUPPER */ ++ ++#ifndef UNIUPR_NOLOWER ++/* ++ * UniTolower: Convert a unicode character to lower case ++ */ ++static inline wchar_t ++UniTolower(wchar_t uc) ++{ ++ register struct UniCaseRange *rp; ++ ++ if (uc < sizeof (UniLowerTable)) { /* Latin characters */ ++ return uc + UniLowerTable[uc]; /* Use base tables */ ++ } else { ++ rp = UniLowerRange; /* Use range tables */ ++ while (rp->start) { ++ if (uc < rp->start) /* Before start of range */ ++ return uc; /* Uppercase = input */ ++ if (uc <= rp->end) /* In range */ ++ return uc + rp->table[uc - rp->start]; ++ rp++; /* Try next range */ ++ } ++ } ++ return uc; /* Past last range */ ++} ++ ++/* ++ * UniStrlwr: Lower case a unicode string ++ */ ++static inline wchar_t * ++UniStrlwr(register wchar_t * upin) ++{ ++ register wchar_t *up; ++ ++ up = upin; ++ while (*up) { /* For all characters */ ++ *up = UniTolower(*up); ++ up++; ++ } ++ return upin; /* Return input pointer */ ++} ++ ++#endif +diff -urN linux-2.4.29.old/fs/cifs/cifs_uniupr.h linux-2.4.29/fs/cifs/cifs_uniupr.h +--- linux-2.4.29.old/fs/cifs/cifs_uniupr.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/cifs_uniupr.h 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,253 @@ ++/* ++ * Copyright (c) International Business Machines Corp., 2000,2002 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * uniupr.h - Unicode compressed case ranges ++ * ++*/ ++ ++#ifndef UNIUPR_NOUPPER ++/* ++ * Latin upper case ++ */ ++signed char CifsUniUpperTable[512] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */ ++ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */ ++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */ ++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */ ++ -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */ ++ 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */ ++ -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */ ++ 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */ ++ 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */ ++ 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */ ++ -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */ ++ 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */ ++ -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */ ++ 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */ ++}; ++ ++/* Upper case range - Greek */ ++static signed char UniCaseRangeU03a0[47] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */ ++ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */ ++ -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64, ++ -63, -63, ++}; ++ ++/* Upper case range - Cyrillic */ ++static signed char UniCaseRangeU0430[48] = { ++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */ ++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */ ++ 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */ ++}; ++ ++/* Upper case range - Extended cyrillic */ ++static signed char UniCaseRangeU0490[61] = { ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */ ++ 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, ++}; ++ ++/* Upper case range - Extended latin and greek */ ++static signed char UniCaseRangeU1e00[509] = { ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */ ++ 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */ ++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ ++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */ ++ 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */ ++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */ ++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */ ++ 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */ ++ 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */ ++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */ ++ 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */ ++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */ ++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */ ++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */ ++ 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */ ++ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */ ++ 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */ ++ 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */ ++ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++/* Upper case range - Wide latin */ ++static signed char UniCaseRangeUff40[27] = { ++ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */ ++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, ++}; ++ ++/* ++ * Upper Case Range ++ */ ++const struct UniCaseRange CifsUniUpperRange[] = { ++ {0x03a0, 0x03ce, UniCaseRangeU03a0}, ++ {0x0430, 0x045f, UniCaseRangeU0430}, ++ {0x0490, 0x04cc, UniCaseRangeU0490}, ++ {0x1e00, 0x1ffc, UniCaseRangeU1e00}, ++ {0xff40, 0xff5a, UniCaseRangeUff40}, ++ {0, 0, NULL} ++}; ++#endif ++ ++#ifndef UNIUPR_NOLOWER ++/* ++ * Latin lower case ++ */ ++static signed char CifsUniLowerTable[512] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */ ++ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */ ++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */ ++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */ ++ 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */ ++ 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */ ++ 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */ ++ 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */ ++ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */ ++ 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */ ++ 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */ ++ 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */ ++ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */ ++ 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */ ++}; ++ ++/* Lower case range - Greek */ ++static signed char UniCaseRangeL0380[44] = { ++ 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */ ++ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */ ++ 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, ++}; ++ ++/* Lower case range - Cyrillic */ ++static signed char UniCaseRangeL0400[48] = { ++ 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */ ++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */ ++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */ ++}; ++ ++/* Lower case range - Extended cyrillic */ ++static signed char UniCaseRangeL0490[60] = { ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */ ++ 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, ++}; ++ ++/* Lower case range - Extended latin and greek */ ++static signed char UniCaseRangeL1e00[504] = { ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */ ++ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */ ++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */ ++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */ ++ 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++/* Lower case range - Wide latin */ ++static signed char UniCaseRangeLff20[27] = { ++ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */ ++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, ++}; ++ ++/* ++ * Lower Case Range ++ */ ++const static struct UniCaseRange CifsUniLowerRange[] = { ++ 0x0380, 0x03ab, UniCaseRangeL0380, ++ 0x0400, 0x042f, UniCaseRangeL0400, ++ 0x0490, 0x04cb, UniCaseRangeL0490, ++ 0x1e00, 0x1ff7, UniCaseRangeL1e00, ++ 0xff20, 0xff3a, UniCaseRangeLff20, ++ 0, 0, 0 ++}; ++#endif +diff -urN linux-2.4.29.old/fs/cifs/connect.c linux-2.4.29/fs/cifs/connect.c +--- linux-2.4.29.old/fs/cifs/connect.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/connect.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,2924 @@ ++/* ++ * fs/cifs/connect.c ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2004 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/fs.h> ++#include <linux/net.h> ++#include <linux/string.h> ++#include <linux/list.h> ++#include <linux/wait.h> ++#include <linux/version.h> ++#include <linux/ipv6.h> ++#include <linux/pagemap.h> ++#include <linux/ctype.h> ++#include <linux/utsname.h> ++#include <asm/uaccess.h> ++#include <asm/processor.h> ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_unicode.h" ++#include "cifs_debug.h" ++#include "cifs_fs_sb.h" ++#include "ntlmssp.h" ++#include "nterr.h" ++#include "rfc1002pdu.h" ++ ++#define CIFS_PORT 445 ++#define RFC1001_PORT 139 ++ ++extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, ++ unsigned char *p24); ++extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, ++ unsigned char *p24); ++extern int cifs_inet_pton(int, const char *, void *dst); ++ ++struct smb_vol { ++ char *username; ++ char *password; ++ char *domainname; ++ char *UNC; ++ char *UNCip; ++ char *iocharset; /* local code page for mapping to and from Unicode */ ++ char source_rfc1001_name[16]; /* netbios name of client */ ++ uid_t linux_uid; ++ gid_t linux_gid; ++ mode_t file_mode; ++ mode_t dir_mode; ++ int rw:1; ++ int retry:1; ++ int intr:1; ++ unsigned int rsize; ++ unsigned int wsize; ++ unsigned int sockopt; ++ unsigned short int port; ++}; ++ ++static int ipv4_connect(struct sockaddr_in *psin_server, ++ struct socket **csocket, ++ char * netb_name); ++static int ipv6_connect(struct sockaddr_in6 *psin_server, ++ struct socket **csocket); ++ ++ ++ /* ++ * cifs tcp session reconnection ++ * ++ * mark tcp session as reconnecting so temporarily locked ++ * mark all smb sessions as reconnecting for tcp session ++ * reconnect tcp session ++ * wake up waiters on reconnection? - (not needed currently) ++ */ ++ ++int ++cifs_reconnect(struct TCP_Server_Info *server) ++{ ++ int rc = 0; ++ struct list_head *tmp; ++ struct cifsSesInfo *ses; ++ struct cifsTconInfo *tcon; ++ struct mid_q_entry * mid_entry; ++ ++ spin_lock(&GlobalMid_Lock); ++ if(server->tcpStatus == CifsExiting) { ++ /* the demux thread will exit normally ++ next time through the loop */ ++ spin_unlock(&GlobalMid_Lock); ++ return rc; ++ } else ++ server->tcpStatus = CifsNeedReconnect; ++ spin_unlock(&GlobalMid_Lock); ++ server->maxBuf = 0; ++ ++ cFYI(1, ("Reconnecting tcp session ")); ++ ++ /* before reconnecting the tcp session, mark the smb session (uid) ++ and the tid bad so they are not used until reconnected */ ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(tmp, &GlobalSMBSessionList) { ++ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ++ if (ses->server) { ++ if (ses->server == server) { ++ ses->status = CifsNeedReconnect; ++ ses->ipc_tid = 0; ++ } ++ } ++ /* else tcp and smb sessions need reconnection */ ++ } ++ list_for_each(tmp, &GlobalTreeConnectionList) { ++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); ++ if((tcon) && (tcon->ses) && (tcon->ses->server == server)) { ++ tcon->tidStatus = CifsNeedReconnect; ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ /* do not want to be sending data on a socket we are freeing */ ++ down(&server->tcpSem); ++ if(server->ssocket) { ++ cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state, ++ server->ssocket->flags)); ++ server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN); ++ cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state, ++ server->ssocket->flags)); ++ sock_release(server->ssocket); ++ server->ssocket = NULL; ++ } ++ ++ spin_lock(&GlobalMid_Lock); ++ list_for_each(tmp, &server->pending_mid_q) { ++ mid_entry = list_entry(tmp, struct ++ mid_q_entry, ++ qhead); ++ if(mid_entry) { ++ if(mid_entry->midState == MID_REQUEST_SUBMITTED) { ++ /* Mark other intransit requests as needing retry so ++ we do not immediately mark the session bad again ++ (ie after we reconnect below) as they timeout too */ ++ mid_entry->midState = MID_RETRY_NEEDED; ++ } ++ } ++ } ++ spin_unlock(&GlobalMid_Lock); ++ up(&server->tcpSem); ++ ++ while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood)) ++ { ++ if(server->protocolType == IPV6) { ++ rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket); ++ } else { ++ rc = ipv4_connect(&server->addr.sockAddr, ++ &server->ssocket, ++ server->workstation_RFC1001_name); ++ } ++ if(rc) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(3 * HZ); ++ } else { ++ atomic_inc(&tcpSesReconnectCount); ++ spin_lock(&GlobalMid_Lock); ++ if(server->tcpStatus != CifsExiting) ++ server->tcpStatus = CifsGood; ++ spin_unlock(&GlobalMid_Lock); ++ /* atomic_set(&server->inFlight,0);*/ ++ wake_up(&server->response_q); ++ } ++ } ++ return rc; ++} ++ ++static int ++cifs_demultiplex_thread(struct TCP_Server_Info *server) ++{ ++ int length; ++ unsigned int pdu_length, total_read; ++ struct smb_hdr *smb_buffer = NULL; ++ struct msghdr smb_msg; ++ mm_segment_t temp_fs; ++ struct iovec iov; ++ struct socket *csocket = server->ssocket; ++ struct list_head *tmp; ++ struct cifsSesInfo *ses; ++ struct task_struct *task_to_wake = NULL; ++ struct mid_q_entry *mid_entry; ++ char *temp; ++ ++ daemonize(); ++ sprintf(current->comm,"cifsd"); ++ /* allow_signal(SIGKILL);*/ ++ current->flags |= PF_MEMALLOC; ++ server->tsk = current; /* save process info to wake at shutdown */ ++ cFYI(1, ("Demultiplex PID: %d", current->pid)); ++ ++ temp_fs = get_fs(); /* we must turn off socket api parm checking */ ++ set_fs(get_ds()); ++ ++ while (server->tcpStatus != CifsExiting) { ++ if (smb_buffer == NULL) ++ smb_buffer = cifs_buf_get(); ++ else ++ memset(smb_buffer, 0, sizeof (struct smb_hdr)); ++ ++ if (smb_buffer == NULL) { ++ cERROR(1,("Can not get memory for SMB response")); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ * 3); /* give system time to free memory */ ++ continue; ++ } ++ iov.iov_base = smb_buffer; ++ iov.iov_len = sizeof (struct smb_hdr) - 1; ++ /* 1 byte less above since wct is not always returned in error cases */ ++ smb_msg.msg_iov = &iov; ++ smb_msg.msg_iovlen = 1; ++ smb_msg.msg_control = NULL; ++ smb_msg.msg_controllen = 0; ++ ++ length = ++ sock_recvmsg(csocket, &smb_msg, ++ sizeof (struct smb_hdr) - ++ 1 /* RFC1001 header and SMB header */ , ++ MSG_PEEK /* flags see socket.h */ ); ++ ++ if(server->tcpStatus == CifsExiting) { ++ break; ++ } else if (server->tcpStatus == CifsNeedReconnect) { ++ cFYI(1,("Reconnecting after server stopped responding")); ++ cifs_reconnect(server); ++ cFYI(1,("call to reconnect done")); ++ csocket = server->ssocket; ++ continue; ++ } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(1); /* minimum sleep to prevent looping ++ allowing socket to clear and app threads to set ++ tcpStatus CifsNeedReconnect if server hung */ ++ continue; ++ } else if (length <= 0) { ++ if(server->tcpStatus == CifsNew) { ++ cFYI(1,("tcp session abended prematurely (after SMBnegprot)")); ++ /* some servers kill tcp session rather than returning ++ smb negprot error in which case reconnecting here is ++ not going to help - return error to mount */ ++ break; ++ } ++ if(length == -EINTR) { ++ cFYI(1,("cifsd thread killed")); ++ break; ++ } ++ cFYI(1,("Reconnecting after unexpected peek error %d",length)); ++ cifs_reconnect(server); ++ csocket = server->ssocket; ++ wake_up(&server->response_q); ++ continue; ++ } ++ ++ pdu_length = 4 + ntohl(smb_buffer->smb_buf_length); ++ /* Ony read pdu_length after below checks for too short (due ++ to e.g. int overflow) and too long ie beyond end of buf */ ++ cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length)); ++ ++ temp = (char *) smb_buffer; ++ if (length > 3) { ++ if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { ++ iov.iov_base = smb_buffer; ++ iov.iov_len = 4; ++ length = sock_recvmsg(csocket, &smb_msg, 4, 0); ++ cFYI(0,("Received 4 byte keep alive packet")); ++ } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) { ++ iov.iov_base = smb_buffer; ++ iov.iov_len = 4; ++ length = sock_recvmsg(csocket, &smb_msg, 4, 0); ++ cFYI(1,("Good RFC 1002 session rsp")); ++ } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) ++ && (length == 5)) { ++ /* we get this from Windows 98 instead of error on SMB negprot response */ ++ cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4])); ++ if(server->tcpStatus == CifsNew) { ++ /* if nack on negprot (rather than ++ ret of smb negprot error) reconnecting ++ not going to help, ret error to mount */ ++ break; ++ } else { ++ /* give server a second to ++ clean up before reconnect attempt */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ); ++ /* always try 445 first on reconnect ++ since we get NACK on some if we ever ++ connected to port 139 (the NACK is ++ since we do not begin with RFC1001 ++ session initialize frame) */ ++ server->addr.sockAddr.sin_port = CIFS_PORT; ++ cifs_reconnect(server); ++ csocket = server->ssocket; ++ wake_up(&server->response_q); ++ continue; ++ } ++ } else if (temp[0] != (char) 0) { ++ cERROR(1,("Unknown RFC 1002 frame")); ++ cifs_dump_mem(" Received Data: ", temp, length); ++ cifs_reconnect(server); ++ csocket = server->ssocket; ++ continue; ++ } else { ++ if ((length != sizeof (struct smb_hdr) - 1) ++ || (pdu_length > ++ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) ++ || (pdu_length < ++ sizeof (struct smb_hdr) - 1) ++ || ++ (checkSMBhdr ++ (smb_buffer, smb_buffer->Mid))) { ++ cERROR(1, ++ ("Invalid size or format for SMB found with length %d and pdu_lenght %d", ++ length, pdu_length)); ++ cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); ++ /* could we fix this network corruption by finding next ++ smb header (instead of killing the session) and ++ restart reading from next valid SMB found? */ ++ cifs_reconnect(server); ++ csocket = server->ssocket; ++ continue; ++ } else { /* length ok */ ++ ++ length = 0; ++ iov.iov_base = smb_buffer; ++ iov.iov_len = pdu_length; ++ for (total_read = 0; ++ total_read < pdu_length; ++ total_read += length) { ++ length = sock_recvmsg(csocket, &smb_msg, ++ pdu_length - total_read, 0); ++ if (length == 0) { ++ cERROR(1, ++ ("Zero length receive when expecting %d ", ++ pdu_length - total_read)); ++ cifs_reconnect(server); ++ csocket = server->ssocket; ++ continue; ++ } ++ } ++ } ++ ++ dump_smb(smb_buffer, length); ++ if (checkSMB ++ (smb_buffer, smb_buffer->Mid, total_read)) { ++ cERROR(1, ("Bad SMB Received ")); ++ continue; ++ } ++ ++ task_to_wake = NULL; ++ spin_lock(&GlobalMid_Lock); ++ list_for_each(tmp, &server->pending_mid_q) { ++ mid_entry = list_entry(tmp, struct ++ mid_q_entry, ++ qhead); ++ ++ if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) { ++ cFYI(1, ++ (" Mid 0x%x matched - waking up ",mid_entry->mid)); ++ task_to_wake = mid_entry->tsk; ++ mid_entry->resp_buf = ++ smb_buffer; ++ mid_entry->midState = ++ MID_RESPONSE_RECEIVED; ++ } ++ } ++ spin_unlock(&GlobalMid_Lock); ++ if (task_to_wake) { ++ smb_buffer = NULL; /* will be freed by users thread after he is done */ ++ wake_up_process(task_to_wake); ++ } else if (is_valid_oplock_break(smb_buffer) == FALSE) { ++ cERROR(1, ("No task to wake, unknown frame rcvd!")); ++ cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); ++ } ++ } ++ } else { ++ cFYI(0, ++ ("Frame less than four bytes received %d bytes long.", ++ length)); ++ if (length > 0) { ++ length = sock_recvmsg(csocket, &smb_msg, length, 0); /* throw away junk frame */ ++ cFYI(1, ++ (" with junk 0x%x in it ", ++ *(__u32 *) smb_buffer)); ++ } ++ } ++ } ++ spin_lock(&GlobalMid_Lock); ++ server->tcpStatus = CifsExiting; ++ server->tsk = NULL; ++ atomic_set(&server->inFlight, 0); ++ spin_unlock(&GlobalMid_Lock); ++ /* Although there should not be any requests blocked on ++ this queue it can not hurt to be paranoid and try to wake up requests ++ that may haven been blocked when more than 50 at time were on the wire ++ to the same server - they now will see the session is in exit state ++ and get out of SendReceive. */ ++ wake_up_all(&server->request_q); ++ /* give those requests time to exit */ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ/8); ++ ++ if(server->ssocket) { ++ sock_release(csocket); ++ server->ssocket = NULL; ++ } ++ set_fs(temp_fs); ++ if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */ ++ cifs_buf_release(smb_buffer); ++ ++ read_lock(&GlobalSMBSeslock); ++ if (list_empty(&server->pending_mid_q)) { ++ /* loop through server session structures attached to this and mark them dead */ ++ list_for_each(tmp, &GlobalSMBSessionList) { ++ ses = ++ list_entry(tmp, struct cifsSesInfo, ++ cifsSessionList); ++ if (ses->server == server) { ++ ses->status = CifsExiting; ++ ses->server = NULL; ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ } else { ++ spin_lock(&GlobalMid_Lock); ++ list_for_each(tmp, &server->pending_mid_q) { ++ mid_entry = list_entry(tmp, struct mid_q_entry, qhead); ++ if (mid_entry->midState == MID_REQUEST_SUBMITTED) { ++ cFYI(1, ++ (" Clearing Mid 0x%x - waking up ",mid_entry->mid)); ++ task_to_wake = mid_entry->tsk; ++ if(task_to_wake) { ++ wake_up_process(task_to_wake); ++ } ++ } ++ } ++ spin_unlock(&GlobalMid_Lock); ++ read_unlock(&GlobalSMBSeslock); ++ set_current_state(TASK_INTERRUPTIBLE); ++ /* 1/8th of sec is more than enough time for them to exit */ ++ schedule_timeout(HZ/8); ++ } ++ ++ if (list_empty(&server->pending_mid_q)) { ++ /* mpx threads have not exited yet give them ++ at least the smb send timeout time for long ops */ ++ cFYI(1, ("Wait for exit from demultiplex thread")); ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(46 * HZ); ++ /* if threads still have not exited they are probably never ++ coming home not much else we can do but free the memory */ ++ } ++ kfree(server); ++ ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ/4); ++ return 0; ++} ++ ++static void * ++cifs_kcalloc(size_t size, int type) ++{ ++ void *addr; ++ addr = kmalloc(size, type); ++ if (addr) ++ memset(addr, 0, size); ++ return addr; ++} ++ ++static int ++cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol) ++{ ++ char *value; ++ char *data; ++ unsigned int temp_len, i, j; ++ char separator[2]; ++ ++ separator[0] = ','; ++ separator[1] = 0; ++ ++ memset(vol->source_rfc1001_name,0x20,15); ++ for(i=0;i < strnlen(system_utsname.nodename,15);i++) { ++ /* does not have to be a perfect mapping since the field is ++ informational, only used for servers that do not support ++ port 445 and it can be overridden at mount time */ ++ vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]); ++ } ++ vol->source_rfc1001_name[15] = 0; ++ ++ vol->linux_uid = current->uid; /* current->euid instead? */ ++ vol->linux_gid = current->gid; ++ vol->dir_mode = S_IRWXUGO; ++ /* 2767 perms indicate mandatory locking support */ ++ vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP); ++ ++ /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ ++ vol->rw = TRUE; ++ ++ if (!options) ++ return 1; ++ ++ if(strncmp(options,"sep=",4) == 0) { ++ if(options[4] != 0) { ++ separator[0] = options[4]; ++ options += 5; ++ } else { ++ cFYI(1,("Null separator not allowed")); ++ } ++ } ++ ++ while ((data = strsep(&options, separator)) != NULL) { ++ if (!*data) ++ continue; ++ if ((value = strchr(data, '=')) != NULL) ++ *value++ = '\0'; ++ if (strnicmp(data, "user", 4) == 0) { ++ if (!value || !*value) { ++ printk(KERN_WARNING ++ "CIFS: invalid or missing username\n"); ++ return 1; /* needs_arg; */ ++ } ++ if (strnlen(value, 200) < 200) { ++ vol->username = value; ++ } else { ++ printk(KERN_WARNING "CIFS: username too long\n"); ++ return 1; ++ } ++ } else if (strnicmp(data, "pass", 4) == 0) { ++ if (!value || !*value) { ++ vol->password = NULL; ++ continue; ++ } ++ temp_len = strlen(value); ++ /* removed password length check, NTLM passwords ++ can be arbitrarily long */ ++ ++ /* if comma in password, the string will be ++ prematurely null terminated. Commas in password are ++ specified across the cifs mount interface by a double ++ comma ie ,, and a comma used as in other cases ie ',' ++ as a parameter delimiter/separator is single and due ++ to the strsep above is temporarily zeroed. */ ++ ++ /* NB: password legally can have multiple commas and ++ the only illegal character in a password is null */ ++ ++ if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) { ++ /* reinsert comma */ ++ value[temp_len] = separator[0]; ++ temp_len+=2; /* move after the second comma */ ++ while(value[temp_len] != 0) { ++ if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) { ++ /* single comma indicating start of next parm */ ++ break; ++ } ++ temp_len++; ++ } ++ if(value[temp_len] == 0) { ++ options = NULL; ++ } else { ++ value[temp_len] = 0; ++ /* move options to point to start of next parm */ ++ options = value + temp_len + 1; ++ } ++ /* go from value to (value + temp_len) condensing double commas to singles */ ++ vol->password = cifs_kcalloc(temp_len, GFP_KERNEL); ++ for(i=0,j=0;i<temp_len;i++,j++) { ++ vol->password[j] = value[i]; ++ if(value[i] == separator[0] && value[i+1] == separator[0]) { ++ /* skip second comma */ ++ i++; ++ } ++ } ++ /* value[temp_len] is zeroed above so ++ vol->password[temp_len] guaranteed to be null */ ++ } else { ++ vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL); ++ strcpy(vol->password, value); ++ } ++ } else if (strnicmp(data, "ip", 2) == 0) { ++ if (!value || !*value) { ++ vol->UNCip = NULL; ++ } else if (strnlen(value, 35) < 35) { ++ vol->UNCip = value; ++ } else { ++ printk(KERN_WARNING "CIFS: ip address too long\n"); ++ return 1; ++ } ++ } else if ((strnicmp(data, "unc", 3) == 0) ++ || (strnicmp(data, "target", 6) == 0) ++ || (strnicmp(data, "path", 4) == 0)) { ++ if (!value || !*value) { ++ printk(KERN_WARNING ++ "CIFS: invalid path to network resource\n"); ++ return 1; /* needs_arg; */ ++ } ++ if ((temp_len = strnlen(value, 300)) < 300) { ++ vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); ++ if(vol->UNC == NULL) ++ return 1; ++ strcpy(vol->UNC,value); ++ if (strncmp(vol->UNC, "//", 2) == 0) { ++ vol->UNC[0] = '\\'; ++ vol->UNC[1] = '\\'; ++ } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { ++ printk(KERN_WARNING ++ "CIFS: UNC Path does not begin with // or \\\\ \n"); ++ return 1; ++ } ++ } else { ++ printk(KERN_WARNING "CIFS: UNC name too long\n"); ++ return 1; ++ } ++ } else if ((strnicmp(data, "domain", 3) == 0) ++ || (strnicmp(data, "workgroup", 5) == 0)) { ++ if (!value || !*value) { ++ printk(KERN_WARNING "CIFS: invalid domain name\n"); ++ return 1; /* needs_arg; */ ++ } ++ /* BB are there cases in which a comma can be valid in ++ a domain name and need special handling? */ ++ if (strnlen(value, 65) < 65) { ++ vol->domainname = value; ++ cFYI(1, ("Domain name set")); ++ } else { ++ printk(KERN_WARNING "CIFS: domain name too long\n"); ++ return 1; ++ } ++ } else if (strnicmp(data, "iocharset", 9) == 0) { ++ if (!value || !*value) { ++ printk(KERN_WARNING "CIFS: invalid iocharset specified\n"); ++ return 1; /* needs_arg; */ ++ } ++ if (strnlen(value, 65) < 65) { ++ if(strnicmp(value,"default",7)) ++ vol->iocharset = value; ++ /* if iocharset not set load_nls_default used by caller */ ++ cFYI(1, ("iocharset set to %s",value)); ++ } else { ++ printk(KERN_WARNING "CIFS: iocharset name too long.\n"); ++ return 1; ++ } ++ } else if (strnicmp(data, "uid", 3) == 0) { ++ if (value && *value) { ++ vol->linux_uid = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "gid", 3) == 0) { ++ if (value && *value) { ++ vol->linux_gid = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "file_mode", 4) == 0) { ++ if (value && *value) { ++ vol->file_mode = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "dir_mode", 3) == 0) { ++ if (value && *value) { ++ vol->dir_mode = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "port", 4) == 0) { ++ if (value && *value) { ++ vol->port = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "rsize", 5) == 0) { ++ if (value && *value) { ++ vol->rsize = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "wsize", 5) == 0) { ++ if (value && *value) { ++ vol->wsize = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "sockopt", 5) == 0) { ++ if (value && *value) { ++ vol->sockopt = ++ simple_strtoul(value, &value, 0); ++ } ++ } else if (strnicmp(data, "netbiosname", 4) == 0) { ++ if (!value || !*value || (*value == ' ')) { ++ cFYI(1,("invalid (empty) netbiosname specified")); ++ } else { ++ memset(vol->source_rfc1001_name,0x20,15); ++ for(i=0;i<15;i++) { ++ /* BB are there cases in which a comma can be ++ valid in this workstation netbios name (and need ++ special handling)? */ ++ ++ /* We do not uppercase netbiosname for user */ ++ if (value[i]==0) ++ break; ++ else ++ vol->source_rfc1001_name[i] = value[i]; ++ } ++ /* The string has 16th byte zero still from ++ set at top of the function */ ++ if((i==15) && (value[i] != 0)) ++ printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); ++ } ++ } else if (strnicmp(data, "credentials", 4) == 0) { ++ /* ignore */ ++ } else if (strnicmp(data, "version", 3) == 0) { ++ /* ignore */ ++ } else if (strnicmp(data, "rw", 2) == 0) { ++ vol->rw = TRUE; ++ } else if ((strnicmp(data, "suid", 4) == 0) || ++ (strnicmp(data, "nosuid", 6) == 0) || ++ (strnicmp(data, "exec", 4) == 0) || ++ (strnicmp(data, "noexec", 6) == 0) || ++ (strnicmp(data, "nodev", 5) == 0) || ++ (strnicmp(data, "noauto", 6) == 0) || ++ (strnicmp(data, "dev", 3) == 0)) { ++ /* The mount tool or mount.cifs helper (if present) ++ uses these opts to set flags, and the flags are read ++ by the kernel vfs layer before we get here (ie ++ before read super) so there is no point trying to ++ parse these options again and set anything and it ++ is ok to just ignore them */ ++ continue; ++ } else if (strnicmp(data, "ro", 2) == 0) { ++ vol->rw = FALSE; ++ } else if (strnicmp(data, "hard", 4) == 0) { ++ vol->retry = 1; ++ } else if (strnicmp(data, "soft", 4) == 0) { ++ vol->retry = 0; ++ } else if (strnicmp(data, "nohard", 6) == 0) { ++ vol->retry = 0; ++ } else if (strnicmp(data, "nosoft", 6) == 0) { ++ vol->retry = 1; ++ } else if (strnicmp(data, "nointr", 6) == 0) { ++ vol->intr = 0; ++ } else if (strnicmp(data, "intr", 4) == 0) { ++ vol->intr = 1; ++ } else if (strnicmp(data, "noac", 4) == 0) { ++ printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n"); ++ } else ++ printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data); ++ } ++ if (vol->UNC == NULL) { ++ if(devname == NULL) { ++ printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); ++ return 1; ++ } ++ if ((temp_len = strnlen(devname, 300)) < 300) { ++ vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); ++ if(vol->UNC == NULL) ++ return 1; ++ strcpy(vol->UNC,devname); ++ if (strncmp(vol->UNC, "//", 2) == 0) { ++ vol->UNC[0] = '\\'; ++ vol->UNC[1] = '\\'; ++ } else if (strncmp(vol->UNC, "\\\\", 2) != 0) { ++ printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n"); ++ return 1; ++ } ++ } else { ++ printk(KERN_WARNING "CIFS: UNC name too long\n"); ++ return 1; ++ } ++ } ++ if(vol->UNCip == 0) ++ vol->UNCip = &vol->UNC[2]; ++ ++ return 0; ++} ++ ++static struct cifsSesInfo * ++cifs_find_tcp_session(__u32 new_target_ip_addr, ++ char *userName, struct TCP_Server_Info **psrvTcp) ++{ ++ struct list_head *tmp; ++ struct cifsSesInfo *ses; ++ ++ *psrvTcp = NULL; ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(tmp, &GlobalSMBSessionList) { ++ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); ++ if (ses->server) { ++ if (ses->server->addr.sockAddr.sin_addr.s_addr == ++ new_target_ip_addr) { ++ /* BB lock server and tcp session and increment use count here?? */ ++ *psrvTcp = ses->server; /* found a match on the TCP session */ ++ /* BB check if reconnection needed */ ++ if (strncmp ++ (ses->userName, userName, ++ MAX_USERNAME_SIZE) == 0){ ++ read_unlock(&GlobalSMBSeslock); ++ return ses; /* found exact match on both tcp and SMB sessions */ ++ } ++ } ++ } ++ /* else tcp and smb sessions need reconnection */ ++ } ++ read_unlock(&GlobalSMBSeslock); ++ return NULL; ++} ++ ++static struct cifsTconInfo * ++find_unc(__u32 new_target_ip_addr, char *uncName, char *userName) ++{ ++ struct list_head *tmp; ++ struct cifsTconInfo *tcon; ++ ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(tmp, &GlobalTreeConnectionList) { ++ cFYI(1, ("Next tcon - ")); ++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); ++ if (tcon->ses) { ++ if (tcon->ses->server) { ++ cFYI(1, ++ (" old ip addr: %x == new ip %x ?", ++ tcon->ses->server->addr.sockAddr.sin_addr. ++ s_addr, new_target_ip_addr)); ++ if (tcon->ses->server->addr.sockAddr.sin_addr. ++ s_addr == new_target_ip_addr) { ++ /* BB lock tcon and server and tcp session and increment use count here? */ ++ /* found a match on the TCP session */ ++ /* BB check if reconnection needed */ ++ cFYI(1,("Matched ip, old UNC: %s == new: %s ?", ++ tcon->treeName, uncName)); ++ if (strncmp ++ (tcon->treeName, uncName, ++ MAX_TREE_SIZE) == 0) { ++ cFYI(1, ++ ("Matched UNC, old user: %s == new: %s ?", ++ tcon->treeName, uncName)); ++ if (strncmp ++ (tcon->ses->userName, ++ userName, ++ MAX_USERNAME_SIZE) == 0) { ++ read_unlock(&GlobalSMBSeslock); ++ return tcon;/* also matched user (smb session)*/ ++ } ++ } ++ } ++ } ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ return NULL; ++} ++ ++int ++connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ++ const char *old_path, const struct nls_table *nls_codepage) ++{ ++ unsigned char *referrals = NULL; ++ unsigned int num_referrals; ++ int rc = 0; ++ ++ rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, ++ &num_referrals, &referrals); ++ ++ /* BB Add in code to: if valid refrl, if not ip address contact ++ the helper that resolves tcp names, mount to it, try to ++ tcon to it unmount it if fail */ ++ ++ if(referrals) ++ kfree(referrals); ++ ++ return rc; ++} ++ ++int ++get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, ++ const char *old_path, const struct nls_table *nls_codepage, ++ unsigned int *pnum_referrals, unsigned char ** preferrals) ++{ ++ char *temp_unc; ++ int rc = 0; ++ ++ *pnum_referrals = 0; ++ ++ if (pSesInfo->ipc_tid == 0) { ++ temp_unc = kmalloc(2 /* for slashes */ + ++ strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2) ++ + 1 + 4 /* slash IPC$ */ + 2, ++ GFP_KERNEL); ++ if (temp_unc == NULL) ++ return -ENOMEM; ++ temp_unc[0] = '\\'; ++ temp_unc[1] = '\\'; ++ strcpy(temp_unc + 2, pSesInfo->serverName); ++ strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$"); ++ rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage); ++ cFYI(1, ++ ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid)); ++ kfree(temp_unc); ++ } ++ if (rc == 0) ++ rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals, ++ pnum_referrals, nls_codepage); ++ ++ return rc; ++} ++ ++/* See RFC1001 section 14 on representation of Netbios names */ ++static void rfc1002mangle(char * target,char * source, unsigned int length) ++{ ++ unsigned int i,j; ++ ++ for(i=0,j=0;i<(length);i++) { ++ /* mask a nibble at a time and encode */ ++ target[j] = 'A' + (0x0F & (source[i] >> 4)); ++ target[j+1] = 'A' + (0x0F & source[i]); ++ j+=2; ++ } ++ ++} ++ ++ ++static int ++ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, ++ char * netbios_name) ++{ ++ int rc = 0; ++ int connected = 0; ++ unsigned short int orig_port = 0; ++ ++ if(*csocket == NULL) { ++ rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket); ++ if (rc < 0) { ++ cERROR(1, ("Error %d creating socket",rc)); ++ *csocket = NULL; ++ return rc; ++ } else { ++ /* BB other socket options to set KEEPALIVE, NODELAY? */ ++ cFYI(1,("Socket created")); ++ (*csocket)->sk->allocation = GFP_NOFS; ++ } ++ } ++ ++ psin_server->sin_family = AF_INET; ++ if(psin_server->sin_port) { /* user overrode default port */ ++ rc = (*csocket)->ops->connect(*csocket, ++ (struct sockaddr *) psin_server, ++ sizeof (struct sockaddr_in),0); ++ if (rc >= 0) ++ connected = 1; ++ } ++ ++ if(!connected) { ++ /* save original port so we can retry user specified port ++ later if fall back ports fail this time */ ++ orig_port = psin_server->sin_port; ++ ++ /* do not retry on the same port we just failed on */ ++ if(psin_server->sin_port != htons(CIFS_PORT)) { ++ psin_server->sin_port = htons(CIFS_PORT); ++ ++ rc = (*csocket)->ops->connect(*csocket, ++ (struct sockaddr *) psin_server, ++ sizeof (struct sockaddr_in),0); ++ if (rc >= 0) ++ connected = 1; ++ } ++ } ++ if (!connected) { ++ psin_server->sin_port = htons(RFC1001_PORT); ++ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) ++ psin_server, sizeof (struct sockaddr_in),0); ++ if (rc >= 0) ++ connected = 1; ++ } ++ ++ /* give up here - unless we want to retry on different ++ protocol families some day */ ++ if (!connected) { ++ if(orig_port) ++ psin_server->sin_port = orig_port; ++ cFYI(1,("Error %d connecting to server via ipv4",rc)); ++ sock_release(*csocket); ++ *csocket = NULL; ++ return rc; ++ } ++ /* Eventually check for other socket options to change from ++ the default. sock_setsockopt not used because it expects ++ user space buffer */ ++ (*csocket)->sk->rcvtimeo = 7 * HZ; ++ ++ /* send RFC1001 sessinit */ ++ ++ if(psin_server->sin_port == htons(139)) { ++ /* some servers require RFC1001 sessinit before sending ++ negprot - BB check reconnection in case where second ++ sessinit is sent but no second negprot */ ++ struct rfc1002_session_packet * ses_init_buf; ++ struct smb_hdr * smb_buf; ++ ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); ++ if(ses_init_buf) { ++ ses_init_buf->trailer.session_req.called_len = 32; ++ rfc1002mangle(ses_init_buf->trailer.session_req.called_name, ++ DEFAULT_CIFS_CALLED_NAME,16); ++ ses_init_buf->trailer.session_req.calling_len = 32; ++ /* calling name ends in null (byte 16) from old smb ++ convention. */ ++ if(netbios_name && (netbios_name[0] !=0)) { ++ rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, ++ netbios_name,16); ++ } else { ++ rfc1002mangle(ses_init_buf->trailer.session_req.calling_name, ++ "LINUX_CIFS_CLNT",16); ++ } ++ ses_init_buf->trailer.session_req.scope1 = 0; ++ ses_init_buf->trailer.session_req.scope2 = 0; ++ smb_buf = (struct smb_hdr *)ses_init_buf; ++ /* sizeof RFC1002_SESSION_REQUEST with no scope */ ++ smb_buf->smb_buf_length = 0x81000044; ++ rc = smb_send(*csocket, smb_buf, 0x44, ++ (struct sockaddr *)psin_server); ++ kfree(ses_init_buf); ++ } ++ /* else the negprot may still work without this ++ even though malloc failed */ ++ ++ } ++ ++ return rc; ++} ++ ++static int ++ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) ++{ ++ int rc = 0; ++ int connected = 0; ++ ++ if(*csocket == NULL) { ++ rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket); ++ if (rc < 0) { ++ cERROR(1, ("Error %d creating ipv6 socket",rc)); ++ *csocket = NULL; ++ return rc; ++ } else { ++ /* BB other socket options to set KEEPALIVE, NODELAY? */ ++ cFYI(1,("ipv6 Socket created")); ++ (*csocket)->sk->allocation = GFP_NOFS; ++ } ++ } ++ ++ psin_server->sin6_family = AF_INET6; ++ ++ if(psin_server->sin6_port) { /* user overrode default port */ ++ rc = (*csocket)->ops->connect(*csocket, ++ (struct sockaddr *) psin_server, ++ sizeof (struct sockaddr_in6),0); ++ if (rc >= 0) ++ connected = 1; ++ } ++ ++ if(!connected) { ++ /* do not retry on the same port we just failed on */ ++ if(psin_server->sin6_port != htons(CIFS_PORT)) { ++ psin_server->sin6_port = htons(CIFS_PORT); ++ ++ rc = (*csocket)->ops->connect(*csocket, ++ (struct sockaddr *) psin_server, ++ sizeof (struct sockaddr_in6),0); ++ if (rc >= 0) ++ connected = 1; ++ } ++ } ++ if (!connected) { ++ psin_server->sin6_port = htons(RFC1001_PORT); ++ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) ++ psin_server, sizeof (struct sockaddr_in6),0); ++ if (rc >= 0) ++ connected = 1; ++ } ++ ++ /* give up here - unless we want to retry on different ++ protocol families some day */ ++ if (!connected) { ++ cFYI(1,("Error %d connecting to server via ipv6",rc)); ++ sock_release(*csocket); ++ *csocket = NULL; ++ return rc; ++ } ++ /* Eventually check for other socket options to change from ++ the default. sock_setsockopt not used because it expects ++ user space buffer */ ++ (*csocket)->sk->rcvtimeo = 7 * HZ; ++ ++ return rc; ++} ++ ++int ++cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, ++ char *mount_data, const char *devname) ++{ ++ int rc = 0; ++ int xid; ++ struct socket *csocket = NULL; ++ struct sockaddr_in sin_server; ++ struct sockaddr_in6 sin_server6; ++ struct smb_vol volume_info; ++ struct cifsSesInfo *pSesInfo = NULL; ++ struct cifsSesInfo *existingCifsSes = NULL; ++ struct cifsTconInfo *tcon = NULL; ++ struct TCP_Server_Info *srvTcp = NULL; ++ ++ xid = GetXid(); ++ ++ cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); /* BB removeme BB fixme */ ++ ++ memset(&volume_info,0,sizeof(struct smb_vol)); ++ if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return -EINVAL; ++ } ++ ++ if (volume_info.username) { ++ cFYI(1, ("Username: %s ", volume_info.username)); ++ ++ } else { ++ cifserror("No username specified "); ++ /* In userspace mount helper we can get user name from alternate ++ locations such as env variables and files on disk */ ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return -EINVAL; ++ } ++ ++ if (volume_info.UNCip && volume_info.UNC) { ++ rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr); ++ ++ if(rc == 0) { ++ /* not ipv4 address, try ipv6 */ ++ rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u); ++ } ++ ++ if(rc != 1) { ++ /* we failed translating address */ ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return -EINVAL; ++ } ++ ++ cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip)); ++ /* success */ ++ rc = 0; ++ } else if (volume_info.UNCip){ ++ /* BB using ip addr as server name connect to the DFS root below */ ++ cERROR(1,("Connecting to DFS root not implemented yet")); ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return -EINVAL; ++ } else /* which servers DFS root would we conect to */ { ++ cERROR(1, ++ ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return -EINVAL; ++ } ++ ++ /* this is needed for ASCII cp to Unicode converts */ ++ if(volume_info.iocharset == NULL) { ++ cifs_sb->local_nls = load_nls_default(); ++ /* load_nls_default can not return null */ ++ } else { ++ cifs_sb->local_nls = load_nls(volume_info.iocharset); ++ if(cifs_sb->local_nls == NULL) { ++ cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset)); ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return -ELIBACC; ++ } ++ } ++ ++ existingCifsSes = ++ cifs_find_tcp_session(sin_server.sin_addr.s_addr, ++ volume_info.username, &srvTcp); ++ if (srvTcp) { ++ cFYI(1, ("Existing tcp session with server found ")); ++ } else { /* create socket */ ++ if(volume_info.port) ++ sin_server.sin_port = htons(volume_info.port); ++ else ++ sin_server.sin_port = 0; ++ rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); ++ if (rc < 0) { ++ cERROR(1, ++ ("Error connecting to IPv4 socket. Aborting operation")); ++ if(csocket != NULL) ++ sock_release(csocket); ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return rc; ++ } ++ ++ srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); ++ if (srvTcp == NULL) { ++ rc = -ENOMEM; ++ sock_release(csocket); ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ FreeXid(xid); ++ return rc; ++ } else { ++ memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); ++ memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); ++ atomic_set(&srvTcp->inFlight,0); ++ /* BB Add code for ipv6 case too */ ++ srvTcp->ssocket = csocket; ++ srvTcp->protocolType = IPV4; ++ init_waitqueue_head(&srvTcp->response_q); ++ init_waitqueue_head(&srvTcp->request_q); ++ INIT_LIST_HEAD(&srvTcp->pending_mid_q); ++ /* at this point we are the only ones with the pointer ++ to the struct since the kernel thread not created yet ++ so no need to spinlock this init of tcpStatus */ ++ srvTcp->tcpStatus = CifsNew; ++ init_MUTEX(&srvTcp->tcpSem); ++ kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp, ++ CLONE_FS | CLONE_FILES | CLONE_VM); ++ memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); ++ } ++ } ++ ++ if (existingCifsSes) { ++ pSesInfo = existingCifsSes; ++ cFYI(1, ("Existing smb sess found ")); ++ if(volume_info.password) ++ kfree(volume_info.password); ++ /* volume_info.UNC freed at end of function */ ++ } else if (!rc) { ++ cFYI(1, ("Existing smb sess not found ")); ++ pSesInfo = sesInfoAlloc(); ++ if (pSesInfo == NULL) ++ rc = -ENOMEM; ++ else { ++ pSesInfo->server = srvTcp; ++ sprintf(pSesInfo->serverName, "%u.%u.%u.%u", ++ NIPQUAD(sin_server.sin_addr.s_addr)); ++ } ++ ++ if (!rc){ ++ /* volume_info.password freed at unmount */ ++ if (volume_info.password) ++ pSesInfo->password = volume_info.password; ++ if (volume_info.username) ++ strncpy(pSesInfo->userName, ++ volume_info.username,MAX_USERNAME_SIZE); ++ if (volume_info.domainname) ++ strncpy(pSesInfo->domainName, ++ volume_info.domainname,MAX_USERNAME_SIZE); ++ pSesInfo->linux_uid = volume_info.linux_uid; ++ down(&pSesInfo->sesSem); ++ rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); ++ up(&pSesInfo->sesSem); ++ if(!rc) ++ atomic_inc(&srvTcp->socketUseCount); ++ } else ++ if(volume_info.password) ++ kfree(volume_info.password); ++ } ++ ++ /* search for existing tcon to this server share */ ++ if (!rc) { ++ if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) ++ cifs_sb->rsize = volume_info.rsize; ++ else ++ cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ ++ if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf)) ++ cifs_sb->wsize = volume_info.wsize; ++ else ++ cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ ++ if(cifs_sb->rsize < PAGE_CACHE_SIZE) { ++ cifs_sb->rsize = PAGE_CACHE_SIZE; ++ cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); ++ } ++ cifs_sb->mnt_uid = volume_info.linux_uid; ++ cifs_sb->mnt_gid = volume_info.linux_gid; ++ cifs_sb->mnt_file_mode = volume_info.file_mode; ++ cifs_sb->mnt_dir_mode = volume_info.dir_mode; ++ cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); ++ tcon = ++ find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, ++ volume_info.username); ++ if (tcon) { ++ cFYI(1, ("Found match on UNC path ")); ++ /* we can have only one retry value for a connection ++ to a share so for resources mounted more than once ++ to the same server share the last value passed in ++ for the retry flag is used */ ++ tcon->retry = volume_info.retry; ++ } else { ++ tcon = tconInfoAlloc(); ++ if (tcon == NULL) ++ rc = -ENOMEM; ++ else { ++ /* check for null share name ie connect to dfs root */ ++ ++ /* BB check if this works for exactly length three strings */ ++ if ((strchr(volume_info.UNC + 3, '\\') == NULL) ++ && (strchr(volume_info.UNC + 3, '/') == ++ NULL)) { ++ rc = connect_to_dfs_path(xid, ++ pSesInfo, ++ "", ++ cifs_sb-> ++ local_nls); ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ FreeXid(xid); ++ return -ENODEV; ++ } else { ++ rc = CIFSTCon(xid, pSesInfo, ++ volume_info.UNC, ++ tcon, cifs_sb->local_nls); ++ cFYI(1, ("CIFS Tcon rc = %d", rc)); ++ } ++ if (!rc) { ++ atomic_inc(&pSesInfo->inUse); ++ tcon->retry = volume_info.retry; ++ } ++ } ++ } ++ } ++ if(pSesInfo) { ++ if (pSesInfo->capabilities & CAP_LARGE_FILES) { ++ sb->s_maxbytes = (u64) 1 << 63; ++ } else ++ sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */ ++ } ++ ++/* on error free sesinfo and tcon struct if needed */ ++ if (rc) { ++ /* if session setup failed, use count is zero but ++ we still need to free cifsd thread */ ++ if(atomic_read(&srvTcp->socketUseCount) == 0) { ++ spin_lock(&GlobalMid_Lock); ++ srvTcp->tcpStatus = CifsExiting; ++ spin_unlock(&GlobalMid_Lock); ++ if(srvTcp->tsk) ++ send_sig(SIGKILL,srvTcp->tsk,1); ++ } ++ /* If find_unc succeeded then rc == 0 so we can not end */ ++ if (tcon) /* up accidently freeing someone elses tcon struct */ ++ tconInfoFree(tcon); ++ if (existingCifsSes == 0) { ++ if (pSesInfo) { ++ if ((pSesInfo->server) && ++ (pSesInfo->status == CifsGood)) { ++ int temp_rc; ++ temp_rc = CIFSSMBLogoff(xid, pSesInfo); ++ /* if the socketUseCount is now zero */ ++ if((temp_rc == -ESHUTDOWN) && ++ (pSesInfo->server->tsk)) ++ send_sig(SIGKILL,pSesInfo->server->tsk,1); ++ } else ++ cFYI(1, ("No session or bad tcon")); ++ sesInfoFree(pSesInfo); ++ /* pSesInfo = NULL; */ ++ } ++ } ++ } else { ++ atomic_inc(&tcon->useCount); ++ cifs_sb->tcon = tcon; ++ tcon->ses = pSesInfo; ++ ++ /* do not care if following two calls succeed - informational only */ ++ CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls); ++ CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls); ++ if (tcon->ses->capabilities & CAP_UNIX) ++ CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls); ++ } ++ ++ /* volume_info.password is freed above when existing session found ++ (in which case it is not needed anymore) but when new sesion is created ++ the password ptr is put in the new session structure (in which case the ++ password will be freed at unmount time) */ ++ if(volume_info.UNC) ++ kfree(volume_info.UNC); ++ FreeXid(xid); ++ return rc; ++} ++ ++static int ++CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, ++ char session_key[CIFS_SESSION_KEY_SIZE], ++ const struct nls_table *nls_codepage) ++{ ++ struct smb_hdr *smb_buffer; ++ struct smb_hdr *smb_buffer_response; ++ SESSION_SETUP_ANDX *pSMB; ++ SESSION_SETUP_ANDX *pSMBr; ++ char *bcc_ptr; ++ char *user = ses->userName; ++ char *domain = ses->domainName; ++ int rc = 0; ++ int remaining_words = 0; ++ int bytes_returned = 0; ++ int len; ++ ++ cFYI(1, ("In sesssetup ")); ++ ++ smb_buffer = cifs_buf_get(); ++ if (smb_buffer == 0) { ++ return -ENOMEM; ++ } ++ smb_buffer_response = smb_buffer; ++ pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; ++ ++ /* send SMBsessionSetup here */ ++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, ++ NULL /* no tCon exists yet */ , 13 /* wct */ ); ++ ++ pSMB->req_no_secext.AndXCommand = 0xFF; ++ pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); ++ pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); ++ ++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) ++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; ++ ++ pSMB->req_no_secext.Capabilities = ++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS; ++ if (ses->capabilities & CAP_UNICODE) { ++ smb_buffer->Flags2 |= SMBFLG2_UNICODE; ++ pSMB->req_no_secext.Capabilities |= CAP_UNICODE; ++ } ++ if (ses->capabilities & CAP_STATUS32) { ++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; ++ pSMB->req_no_secext.Capabilities |= CAP_STATUS32; ++ } ++ if (ses->capabilities & CAP_DFS) { ++ smb_buffer->Flags2 |= SMBFLG2_DFS; ++ pSMB->req_no_secext.Capabilities |= CAP_DFS; ++ } ++ pSMB->req_no_secext.Capabilities = ++ cpu_to_le32(pSMB->req_no_secext.Capabilities); ++ /* pSMB->req_no_secext.CaseInsensitivePasswordLength = ++ CIFS_SESSION_KEY_SIZE; */ ++ pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; ++ pSMB->req_no_secext.CaseSensitivePasswordLength = ++ cpu_to_le16(CIFS_SESSION_KEY_SIZE); ++ bcc_ptr = pByteArea(smb_buffer); ++ /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE); ++ bcc_ptr += CIFS_SESSION_KEY_SIZE; */ ++ memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); ++ bcc_ptr += CIFS_SESSION_KEY_SIZE; ++ ++ if (ses->capabilities & CAP_UNICODE) { ++ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ } ++ if(user == NULL) ++ bytes_returned = 0; /* skill null user */ ++ else ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, ++ nls_codepage); ++ bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */ ++ bcc_ptr += 2; /* trailing null */ ++ if (domain == NULL) ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, ++ "CIFS_LINUX_DOM", 32, nls_codepage); ++ else ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, ++ nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", ++ 32, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, ++ nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, ++ 64, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; ++ } else { ++ if(user != NULL) { ++ strncpy(bcc_ptr, user, 200); ++ bcc_ptr += strnlen(user, 200); ++ } ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ if (domain == NULL) { ++ strcpy(bcc_ptr, "CIFS_LINUX_DOM"); ++ bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; ++ } else { ++ strncpy(bcc_ptr, domain, 64); ++ bcc_ptr += strnlen(domain, 64); ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ } ++ strcpy(bcc_ptr, "Linux version "); ++ bcc_ptr += strlen("Linux version "); ++ strcpy(bcc_ptr, UTS_RELEASE); ++ bcc_ptr += strlen(UTS_RELEASE) + 1; ++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); ++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ } ++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); ++ smb_buffer->smb_buf_length += BCC(smb_buffer); ++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); ++ ++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, ++ &bytes_returned, 1); ++ if (rc) { ++/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ ++ } else if ((smb_buffer_response->WordCount == 3) ++ || (smb_buffer_response->WordCount == 4)) { ++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); ++ if (pSMBr->resp.Action & GUEST_LOGIN) ++ cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */ ++ if (ses) { ++ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ ++ cFYI(1, ("UID = %d ", ses->Suid)); ++ /* response can have either 3 or 4 word count - Samba sends 3 */ ++ bcc_ptr = pByteArea(smb_buffer_response); ++ if ((pSMBr->resp.hdr.WordCount == 3) ++ || ((pSMBr->resp.hdr.WordCount == 4) ++ && (pSMBr->resp.SecurityBlobLength < ++ pSMBr->resp.ByteCount))) { ++ if (pSMBr->resp.hdr.WordCount == 4) ++ bcc_ptr += ++ pSMBr->resp.SecurityBlobLength; ++ ++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { ++ if ((long) (bcc_ptr) % 2) { ++ remaining_words = ++ (BCC(smb_buffer_response) ++ - 1) / 2; ++ bcc_ptr++; /* Unicode strings must be word aligned */ ++ } else { ++ remaining_words = ++ BCC ++ (smb_buffer_response) / 2; ++ } ++ len = ++ UniStrnlen((wchar_t *) bcc_ptr, ++ remaining_words - 1); ++/* We look for obvious messed up bcc or strings in response so we do not go off ++ the end since (at least) WIN2K and Windows XP have a major bug in not null ++ terminating last Unicode string in response */ ++ ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverOS, ++ (wchar_t *)bcc_ptr, len,nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ remaining_words -= len + 1; ++ ses->serverOS[2 * len] = 0; ++ ses->serverOS[1 + (2 * len)] = 0; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *)bcc_ptr, ++ remaining_words ++ - 1); ++ ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverNOS, ++ (wchar_t *)bcc_ptr,len,nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ ses->serverNOS[2 * len] = 0; ++ ses->serverNOS[1 + (2 * len)] = 0; ++ remaining_words -= len + 1; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); ++ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ++ ses->serverDomain = ++ cifs_kcalloc(2*(len+1),GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverDomain, ++ (wchar_t *)bcc_ptr,len,nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ ses->serverDomain[2*len] = 0; ++ ses->serverDomain[1+(2*len)] = 0; ++ } /* else no more room so create dummy domain string */ ++ else ++ ses->serverDomain = ++ cifs_kcalloc(2, ++ GFP_KERNEL); ++ } else { /* no room so create dummy domain and NOS string */ ++ ses->serverDomain = ++ cifs_kcalloc(2, GFP_KERNEL); ++ ses->serverNOS = ++ cifs_kcalloc(2, GFP_KERNEL); ++ } ++ } else { /* ASCII */ ++ len = strnlen(bcc_ptr, 1024); ++ if (((long) bcc_ptr + len) - (long) ++ pByteArea(smb_buffer_response) ++ <= BCC(smb_buffer_response)) { ++ ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); ++ strncpy(ses->serverOS,bcc_ptr, len); ++ ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; /* null terminate the string */ ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); ++ strncpy(ses->serverNOS, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL); ++ strncpy(ses->serverDomain, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ } else ++ cFYI(1, ++ ("Variable field of length %d extends beyond end of smb ", ++ len)); ++ } ++ } else { ++ cERROR(1, ++ (" Security Blob Length extends beyond end of SMB")); ++ } ++ } else { ++ cERROR(1, ("No session structure passed in.")); ++ } ++ } else { ++ cERROR(1, ++ (" Invalid Word count %d: ", ++ smb_buffer_response->WordCount)); ++ rc = -EIO; ++ } ++ ++ if (smb_buffer) ++ cifs_buf_release(smb_buffer); ++ ++ return rc; ++} ++ ++static int ++CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, ++ char *SecurityBlob,int SecurityBlobLength, ++ const struct nls_table *nls_codepage) ++{ ++ struct smb_hdr *smb_buffer; ++ struct smb_hdr *smb_buffer_response; ++ SESSION_SETUP_ANDX *pSMB; ++ SESSION_SETUP_ANDX *pSMBr; ++ char *bcc_ptr; ++ char *user = ses->userName; ++ char *domain = ses->domainName; ++ int rc = 0; ++ int remaining_words = 0; ++ int bytes_returned = 0; ++ int len; ++ ++ cFYI(1, ("In spnego sesssetup ")); ++ ++ smb_buffer = cifs_buf_get(); ++ if (smb_buffer == 0) { ++ return -ENOMEM; ++ } ++ smb_buffer_response = smb_buffer; ++ pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; ++ ++ /* send SMBsessionSetup here */ ++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, ++ NULL /* no tCon exists yet */ , 12 /* wct */ ); ++ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; ++ pSMB->req.AndXCommand = 0xFF; ++ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); ++ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); ++ ++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) ++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; ++ ++ pSMB->req.Capabilities = ++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | ++ CAP_EXTENDED_SECURITY; ++ if (ses->capabilities & CAP_UNICODE) { ++ smb_buffer->Flags2 |= SMBFLG2_UNICODE; ++ pSMB->req.Capabilities |= CAP_UNICODE; ++ } ++ if (ses->capabilities & CAP_STATUS32) { ++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; ++ pSMB->req.Capabilities |= CAP_STATUS32; ++ } ++ if (ses->capabilities & CAP_DFS) { ++ smb_buffer->Flags2 |= SMBFLG2_DFS; ++ pSMB->req.Capabilities |= CAP_DFS; ++ } ++ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); ++ ++ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); ++ bcc_ptr = pByteArea(smb_buffer); ++ memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength); ++ bcc_ptr += SecurityBlobLength; ++ ++ if (ses->capabilities & CAP_UNICODE) { ++ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */ ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ } ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ ++ bcc_ptr += 2; /* trailing null */ ++ if (domain == NULL) ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, ++ "CIFS_LINUX_DOM", 32, nls_codepage); ++ else ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, ++ nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", ++ 32, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, ++ nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, ++ 64, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; ++ } else { ++ strncpy(bcc_ptr, user, 200); ++ bcc_ptr += strnlen(user, 200); ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ if (domain == NULL) { ++ strcpy(bcc_ptr, "CIFS_LINUX_DOM"); ++ bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; ++ } else { ++ strncpy(bcc_ptr, domain, 64); ++ bcc_ptr += strnlen(domain, 64); ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ } ++ strcpy(bcc_ptr, "Linux version "); ++ bcc_ptr += strlen("Linux version "); ++ strcpy(bcc_ptr, UTS_RELEASE); ++ bcc_ptr += strlen(UTS_RELEASE) + 1; ++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); ++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ } ++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); ++ smb_buffer->smb_buf_length += BCC(smb_buffer); ++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); ++ ++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, ++ &bytes_returned, 1); ++ if (rc) { ++/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ ++ } else if ((smb_buffer_response->WordCount == 3) ++ || (smb_buffer_response->WordCount == 4)) { ++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); ++ pSMBr->resp.SecurityBlobLength = ++ le16_to_cpu(pSMBr->resp.SecurityBlobLength); ++ if (pSMBr->resp.Action & GUEST_LOGIN) ++ cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ ++ if (ses) { ++ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ ++ cFYI(1, ("UID = %d ", ses->Suid)); ++ bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ ++ ++ /* BB Fix below to make endian neutral !! */ ++ ++ if ((pSMBr->resp.hdr.WordCount == 3) ++ || ((pSMBr->resp.hdr.WordCount == 4) ++ && (pSMBr->resp.SecurityBlobLength < ++ pSMBr->resp.ByteCount))) { ++ if (pSMBr->resp.hdr.WordCount == 4) { ++ bcc_ptr += ++ pSMBr->resp.SecurityBlobLength; ++ cFYI(1, ++ ("Security Blob Length %d ", ++ pSMBr->resp.SecurityBlobLength)); ++ } ++ ++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { ++ if ((long) (bcc_ptr) % 2) { ++ remaining_words = ++ (BCC(smb_buffer_response) ++ - 1) / 2; ++ bcc_ptr++; /* Unicode strings must be word aligned */ ++ } else { ++ remaining_words = ++ BCC ++ (smb_buffer_response) / 2; ++ } ++ len = ++ UniStrnlen((wchar_t *) bcc_ptr, ++ remaining_words - 1); ++/* We look for obvious messed up bcc or strings in response so we do not go off ++ the end since (at least) WIN2K and Windows XP have a major bug in not null ++ terminating last Unicode string in response */ ++ ses->serverOS = ++ cifs_kcalloc(2 * (len + 1), GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverOS, ++ (wchar_t *) ++ bcc_ptr, len, ++ nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ remaining_words -= len + 1; ++ ses->serverOS[2 * len] = 0; ++ ses->serverOS[1 + (2 * len)] = 0; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *)bcc_ptr, ++ remaining_words ++ - 1); ++ ses->serverNOS = ++ cifs_kcalloc(2 * (len + 1), ++ GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverNOS, ++ (wchar_t *)bcc_ptr, ++ len, ++ nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ ses->serverNOS[2 * len] = 0; ++ ses->serverNOS[1 + (2 * len)] = 0; ++ remaining_words -= len + 1; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); ++ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ++ ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverDomain, ++ (wchar_t *)bcc_ptr, ++ len, ++ nls_codepage); ++ bcc_ptr += 2*(len+1); ++ ses->serverDomain[2*len] = 0; ++ ses->serverDomain[1+(2*len)] = 0; ++ } /* else no more room so create dummy domain string */ ++ else ++ ses->serverDomain = ++ cifs_kcalloc(2,GFP_KERNEL); ++ } else { /* no room so create dummy domain and NOS string */ ++ ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); ++ ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); ++ } ++ } else { /* ASCII */ ++ ++ len = strnlen(bcc_ptr, 1024); ++ if (((long) bcc_ptr + len) - (long) ++ pByteArea(smb_buffer_response) ++ <= BCC(smb_buffer_response)) { ++ ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL); ++ strncpy(ses->serverOS, bcc_ptr, len); ++ ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; /* null terminate the string */ ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL); ++ strncpy(ses->serverNOS, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL); ++ strncpy(ses->serverDomain, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ } else ++ cFYI(1, ++ ("Variable field of length %d extends beyond end of smb ", ++ len)); ++ } ++ } else { ++ cERROR(1, ++ (" Security Blob Length extends beyond end of SMB")); ++ } ++ } else { ++ cERROR(1, ("No session structure passed in.")); ++ } ++ } else { ++ cERROR(1, ++ (" Invalid Word count %d: ", ++ smb_buffer_response->WordCount)); ++ rc = -EIO; ++ } ++ ++ if (smb_buffer) ++ cifs_buf_release(smb_buffer); ++ ++ return rc; ++} ++ ++static int ++CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ++ struct cifsSesInfo *ses, int * pNTLMv2_flag, ++ const struct nls_table *nls_codepage) ++{ ++ struct smb_hdr *smb_buffer; ++ struct smb_hdr *smb_buffer_response; ++ SESSION_SETUP_ANDX *pSMB; ++ SESSION_SETUP_ANDX *pSMBr; ++ char *bcc_ptr; ++ char *domain = ses->domainName; ++ int rc = 0; ++ int remaining_words = 0; ++ int bytes_returned = 0; ++ int len; ++ int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); ++ PNEGOTIATE_MESSAGE SecurityBlob; ++ PCHALLENGE_MESSAGE SecurityBlob2; ++ ++ cFYI(1, ("In NTLMSSP sesssetup (negotiate) ")); ++ *pNTLMv2_flag = FALSE; ++ smb_buffer = cifs_buf_get(); ++ if (smb_buffer == 0) { ++ return -ENOMEM; ++ } ++ smb_buffer_response = smb_buffer; ++ pSMB = (SESSION_SETUP_ANDX *) smb_buffer; ++ pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; ++ ++ /* send SMBsessionSetup here */ ++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, ++ NULL /* no tCon exists yet */ , 12 /* wct */ ); ++ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; ++ pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); ++ ++ pSMB->req.AndXCommand = 0xFF; ++ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); ++ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); ++ ++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) ++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; ++ ++ pSMB->req.Capabilities = ++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | ++ CAP_EXTENDED_SECURITY; ++ if (ses->capabilities & CAP_UNICODE) { ++ smb_buffer->Flags2 |= SMBFLG2_UNICODE; ++ pSMB->req.Capabilities |= CAP_UNICODE; ++ } ++ if (ses->capabilities & CAP_STATUS32) { ++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; ++ pSMB->req.Capabilities |= CAP_STATUS32; ++ } ++ if (ses->capabilities & CAP_DFS) { ++ smb_buffer->Flags2 |= SMBFLG2_DFS; ++ pSMB->req.Capabilities |= CAP_DFS; ++ } ++ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); ++ ++ bcc_ptr = (char *) &pSMB->req.SecurityBlob; ++ SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; ++ strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); ++ SecurityBlob->MessageType = NtLmNegotiate; ++ SecurityBlob->NegotiateFlags = ++ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | ++ NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 | ++ /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; ++ if(sign_CIFS_PDUs) ++ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN; ++ if(ntlmv2_support) ++ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; ++ /* setup pointers to domain name and workstation name */ ++ bcc_ptr += SecurityBlobLength; ++ ++ SecurityBlob->WorkstationName.Buffer = 0; ++ SecurityBlob->WorkstationName.Length = 0; ++ SecurityBlob->WorkstationName.MaximumLength = 0; ++ ++ if (domain == NULL) { ++ SecurityBlob->DomainName.Buffer = 0; ++ SecurityBlob->DomainName.Length = 0; ++ SecurityBlob->DomainName.MaximumLength = 0; ++ } else { ++ SecurityBlob->NegotiateFlags |= ++ NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; ++ strncpy(bcc_ptr, domain, 63); ++ SecurityBlob->DomainName.Length = strnlen(domain, 64); ++ SecurityBlob->DomainName.MaximumLength = ++ cpu_to_le16(SecurityBlob->DomainName.Length); ++ SecurityBlob->DomainName.Buffer = ++ cpu_to_le32((long) &SecurityBlob-> ++ DomainString - ++ (long) &SecurityBlob->Signature); ++ bcc_ptr += SecurityBlob->DomainName.Length; ++ SecurityBlobLength += SecurityBlob->DomainName.Length; ++ SecurityBlob->DomainName.Length = ++ cpu_to_le16(SecurityBlob->DomainName.Length); ++ } ++ if (ses->capabilities & CAP_UNICODE) { ++ if ((long) bcc_ptr % 2) { ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ } ++ ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", ++ 32, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, ++ nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; /* null terminate Linux version */ ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, ++ 64, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ *(bcc_ptr + 1) = 0; ++ *(bcc_ptr + 2) = 0; ++ bcc_ptr += 2; /* null terminate network opsys string */ ++ *(bcc_ptr + 1) = 0; ++ *(bcc_ptr + 2) = 0; ++ bcc_ptr += 2; /* null domain */ ++ } else { /* ASCII */ ++ strcpy(bcc_ptr, "Linux version "); ++ bcc_ptr += strlen("Linux version "); ++ strcpy(bcc_ptr, UTS_RELEASE); ++ bcc_ptr += strlen(UTS_RELEASE) + 1; ++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); ++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ bcc_ptr++; /* empty domain field */ ++ *bcc_ptr = 0; ++ } ++ SecurityBlob->NegotiateFlags = ++ cpu_to_le32(SecurityBlob->NegotiateFlags); ++ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); ++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); ++ smb_buffer->smb_buf_length += BCC(smb_buffer); ++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); ++ ++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, ++ &bytes_returned, 1); ++ ++ if (smb_buffer_response->Status.CifsError == ++ (NT_STATUS_MORE_PROCESSING_REQUIRED)) ++ rc = 0; ++ ++ if (rc) { ++/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ ++ } else if ((smb_buffer_response->WordCount == 3) ++ || (smb_buffer_response->WordCount == 4)) { ++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); ++ pSMBr->resp.SecurityBlobLength = ++ le16_to_cpu(pSMBr->resp.SecurityBlobLength); ++ if (pSMBr->resp.Action & GUEST_LOGIN) ++ cFYI(1, (" Guest login")); ++ /* Do we want to set anything in SesInfo struct when guest login? */ ++ ++ bcc_ptr = pByteArea(smb_buffer_response); ++ /* response can have either 3 or 4 word count - Samba sends 3 */ ++ ++ SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; ++ if (SecurityBlob2->MessageType != NtLmChallenge) { ++ cFYI(1, ++ ("Unexpected NTLMSSP message type received %d", ++ SecurityBlob2->MessageType)); ++ } else if (ses) { ++ ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ ++ cFYI(1, ("UID = %d ", ses->Suid)); ++ if ((pSMBr->resp.hdr.WordCount == 3) ++ || ((pSMBr->resp.hdr.WordCount == 4) ++ && (pSMBr->resp.SecurityBlobLength < ++ pSMBr->resp.ByteCount))) { ++ if (pSMBr->resp.hdr.WordCount == 4) { ++ bcc_ptr += ++ pSMBr->resp.SecurityBlobLength; ++ cFYI(1, ++ ("Security Blob Length %d ", ++ pSMBr->resp.SecurityBlobLength)); ++ } ++ ++ cFYI(1, ("NTLMSSP Challenge rcvd ")); ++ ++ memcpy(ses->server->cryptKey, ++ SecurityBlob2->Challenge, ++ CIFS_CRYPTO_KEY_SIZE); ++ if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2) ++ *pNTLMv2_flag = TRUE; ++ ++ if((SecurityBlob2->NegotiateFlags & ++ NTLMSSP_NEGOTIATE_ALWAYS_SIGN) ++ || (sign_CIFS_PDUs > 1)) ++ ses->server->secMode |= ++ SECMODE_SIGN_REQUIRED; ++ if ((SecurityBlob2->NegotiateFlags & ++ NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs)) ++ ses->server->secMode |= ++ SECMODE_SIGN_ENABLED; ++ ++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { ++ if ((long) (bcc_ptr) % 2) { ++ remaining_words = ++ (BCC(smb_buffer_response) ++ - 1) / 2; ++ bcc_ptr++; /* Unicode strings must be word aligned */ ++ } else { ++ remaining_words = ++ BCC ++ (smb_buffer_response) / 2; ++ } ++ len = ++ UniStrnlen((wchar_t *) bcc_ptr, ++ remaining_words - 1); ++/* We look for obvious messed up bcc or strings in response so we do not go off ++ the end since (at least) WIN2K and Windows XP have a major bug in not null ++ terminating last Unicode string in response */ ++ ses->serverOS = ++ cifs_kcalloc(2 * (len + 1), GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverOS, ++ (wchar_t *) ++ bcc_ptr, len, ++ nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ remaining_words -= len + 1; ++ ses->serverOS[2 * len] = 0; ++ ses->serverOS[1 + (2 * len)] = 0; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *) ++ bcc_ptr, ++ remaining_words ++ - 1); ++ ses->serverNOS = ++ cifs_kcalloc(2 * (len + 1), ++ GFP_KERNEL); ++ cifs_strfromUCS_le(ses-> ++ serverNOS, ++ (wchar_t *) ++ bcc_ptr, ++ len, ++ nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ ses->serverNOS[2 * len] = 0; ++ ses->serverNOS[1 + ++ (2 * len)] = 0; ++ remaining_words -= len + 1; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); ++ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ++ ses->serverDomain = ++ cifs_kcalloc(2 * ++ (len + ++ 1), ++ GFP_KERNEL); ++ cifs_strfromUCS_le ++ (ses-> ++ serverDomain, ++ (wchar_t *) ++ bcc_ptr, len, ++ nls_codepage); ++ bcc_ptr += ++ 2 * (len + 1); ++ ses-> ++ serverDomain[2 ++ * len] ++ = 0; ++ ses-> ++ serverDomain[1 ++ + ++ (2 ++ * ++ len)] ++ = 0; ++ } /* else no more room so create dummy domain string */ ++ else ++ ses->serverDomain = ++ cifs_kcalloc(2, ++ GFP_KERNEL); ++ } else { /* no room so create dummy domain and NOS string */ ++ ses->serverDomain = ++ cifs_kcalloc(2, GFP_KERNEL); ++ ses->serverNOS = ++ cifs_kcalloc(2, GFP_KERNEL); ++ } ++ } else { /* ASCII */ ++ len = strnlen(bcc_ptr, 1024); ++ if (((long) bcc_ptr + len) - (long) ++ pByteArea(smb_buffer_response) ++ <= BCC(smb_buffer_response)) { ++ ses->serverOS = ++ cifs_kcalloc(len + 1, ++ GFP_KERNEL); ++ strncpy(ses->serverOS, ++ bcc_ptr, len); ++ ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; /* null terminate string */ ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverNOS = ++ cifs_kcalloc(len + 1, ++ GFP_KERNEL); ++ strncpy(ses->serverNOS, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverDomain = ++ cifs_kcalloc(len + 1, ++ GFP_KERNEL); ++ strncpy(ses->serverDomain, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ } else ++ cFYI(1, ++ ("Variable field of length %d extends beyond end of smb ", ++ len)); ++ } ++ } else { ++ cERROR(1, ++ (" Security Blob Length extends beyond end of SMB")); ++ } ++ } else { ++ cERROR(1, ("No session structure passed in.")); ++ } ++ } else { ++ cERROR(1, ++ (" Invalid Word count %d: ", ++ smb_buffer_response->WordCount)); ++ rc = -EIO; ++ } ++ ++ if (smb_buffer) ++ cifs_buf_release(smb_buffer); ++ ++ return rc; ++} ++ ++static int ++CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ++ char *ntlm_session_key, int ntlmv2_flag, ++ const struct nls_table *nls_codepage) ++{ ++ struct smb_hdr *smb_buffer; ++ struct smb_hdr *smb_buffer_response; ++ SESSION_SETUP_ANDX *pSMB; ++ SESSION_SETUP_ANDX *pSMBr; ++ char *bcc_ptr; ++ char *user = ses->userName; ++ char *domain = ses->domainName; ++ int rc = 0; ++ int remaining_words = 0; ++ int bytes_returned = 0; ++ int len; ++ int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); ++ PAUTHENTICATE_MESSAGE SecurityBlob; ++ ++ cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); ++ ++ smb_buffer = cifs_buf_get(); ++ if (smb_buffer == 0) { ++ return -ENOMEM; ++ } ++ smb_buffer_response = smb_buffer; ++ pSMB = (SESSION_SETUP_ANDX *) smb_buffer; ++ pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; ++ ++ /* send SMBsessionSetup here */ ++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, ++ NULL /* no tCon exists yet */ , 12 /* wct */ ); ++ pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); ++ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; ++ pSMB->req.AndXCommand = 0xFF; ++ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); ++ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); ++ ++ pSMB->req.hdr.Uid = ses->Suid; ++ ++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) ++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; ++ ++ pSMB->req.Capabilities = ++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | ++ CAP_EXTENDED_SECURITY; ++ if (ses->capabilities & CAP_UNICODE) { ++ smb_buffer->Flags2 |= SMBFLG2_UNICODE; ++ pSMB->req.Capabilities |= CAP_UNICODE; ++ } ++ if (ses->capabilities & CAP_STATUS32) { ++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; ++ pSMB->req.Capabilities |= CAP_STATUS32; ++ } ++ if (ses->capabilities & CAP_DFS) { ++ smb_buffer->Flags2 |= SMBFLG2_DFS; ++ pSMB->req.Capabilities |= CAP_DFS; ++ } ++ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities); ++ ++ bcc_ptr = (char *) &pSMB->req.SecurityBlob; ++ SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; ++ strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); ++ SecurityBlob->MessageType = NtLmAuthenticate; ++ bcc_ptr += SecurityBlobLength; ++ SecurityBlob->NegotiateFlags = ++ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | ++ NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | ++ 0x80000000 | NTLMSSP_NEGOTIATE_128; ++ if(sign_CIFS_PDUs) ++ SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; ++ if(ntlmv2_flag) ++ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2; ++ ++/* setup pointers to domain name and workstation name */ ++ ++ SecurityBlob->WorkstationName.Buffer = 0; ++ SecurityBlob->WorkstationName.Length = 0; ++ SecurityBlob->WorkstationName.MaximumLength = 0; ++ SecurityBlob->SessionKey.Length = 0; ++ SecurityBlob->SessionKey.MaximumLength = 0; ++ SecurityBlob->SessionKey.Buffer = 0; ++ ++ SecurityBlob->LmChallengeResponse.Length = 0; ++ SecurityBlob->LmChallengeResponse.MaximumLength = 0; ++ SecurityBlob->LmChallengeResponse.Buffer = 0; ++ ++ SecurityBlob->NtChallengeResponse.Length = ++ cpu_to_le16(CIFS_SESSION_KEY_SIZE); ++ SecurityBlob->NtChallengeResponse.MaximumLength = ++ cpu_to_le16(CIFS_SESSION_KEY_SIZE); ++ memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); ++ SecurityBlob->NtChallengeResponse.Buffer = ++ cpu_to_le32(SecurityBlobLength); ++ SecurityBlobLength += CIFS_SESSION_KEY_SIZE; ++ bcc_ptr += CIFS_SESSION_KEY_SIZE; ++ ++ if (ses->capabilities & CAP_UNICODE) { ++ if (domain == NULL) { ++ SecurityBlob->DomainName.Buffer = 0; ++ SecurityBlob->DomainName.Length = 0; ++ SecurityBlob->DomainName.MaximumLength = 0; ++ } else { ++ SecurityBlob->DomainName.Length = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, ++ nls_codepage); ++ SecurityBlob->DomainName.Length *= 2; ++ SecurityBlob->DomainName.MaximumLength = ++ cpu_to_le16(SecurityBlob->DomainName.Length); ++ SecurityBlob->DomainName.Buffer = ++ cpu_to_le32(SecurityBlobLength); ++ bcc_ptr += SecurityBlob->DomainName.Length; ++ SecurityBlobLength += SecurityBlob->DomainName.Length; ++ SecurityBlob->DomainName.Length = ++ cpu_to_le16(SecurityBlob->DomainName.Length); ++ } ++ if (user == NULL) { ++ SecurityBlob->UserName.Buffer = 0; ++ SecurityBlob->UserName.Length = 0; ++ SecurityBlob->UserName.MaximumLength = 0; ++ } else { ++ SecurityBlob->UserName.Length = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, ++ nls_codepage); ++ SecurityBlob->UserName.Length *= 2; ++ SecurityBlob->UserName.MaximumLength = ++ cpu_to_le16(SecurityBlob->UserName.Length); ++ SecurityBlob->UserName.Buffer = ++ cpu_to_le32(SecurityBlobLength); ++ bcc_ptr += SecurityBlob->UserName.Length; ++ SecurityBlobLength += SecurityBlob->UserName.Length; ++ SecurityBlob->UserName.Length = ++ cpu_to_le16(SecurityBlob->UserName.Length); ++ } ++ ++ /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); ++ SecurityBlob->WorkstationName.Length *= 2; ++ SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); ++ SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); ++ bcc_ptr += SecurityBlob->WorkstationName.Length; ++ SecurityBlobLength += SecurityBlob->WorkstationName.Length; ++ SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ ++ ++ if ((long) bcc_ptr % 2) { ++ *bcc_ptr = 0; ++ bcc_ptr++; ++ } ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", ++ 32, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32, ++ nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ bcc_ptr += 2; /* null term version string */ ++ bytes_returned = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, ++ 64, nls_codepage); ++ bcc_ptr += 2 * bytes_returned; ++ *(bcc_ptr + 1) = 0; ++ *(bcc_ptr + 2) = 0; ++ bcc_ptr += 2; /* null terminate network opsys string */ ++ *(bcc_ptr + 1) = 0; ++ *(bcc_ptr + 2) = 0; ++ bcc_ptr += 2; /* null domain */ ++ } else { /* ASCII */ ++ if (domain == NULL) { ++ SecurityBlob->DomainName.Buffer = 0; ++ SecurityBlob->DomainName.Length = 0; ++ SecurityBlob->DomainName.MaximumLength = 0; ++ } else { ++ SecurityBlob->NegotiateFlags |= ++ NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; ++ strncpy(bcc_ptr, domain, 63); ++ SecurityBlob->DomainName.Length = strnlen(domain, 64); ++ SecurityBlob->DomainName.MaximumLength = ++ cpu_to_le16(SecurityBlob->DomainName.Length); ++ SecurityBlob->DomainName.Buffer = ++ cpu_to_le32(SecurityBlobLength); ++ bcc_ptr += SecurityBlob->DomainName.Length; ++ SecurityBlobLength += SecurityBlob->DomainName.Length; ++ SecurityBlob->DomainName.Length = ++ cpu_to_le16(SecurityBlob->DomainName.Length); ++ } ++ if (user == NULL) { ++ SecurityBlob->UserName.Buffer = 0; ++ SecurityBlob->UserName.Length = 0; ++ SecurityBlob->UserName.MaximumLength = 0; ++ } else { ++ strncpy(bcc_ptr, user, 63); ++ SecurityBlob->UserName.Length = strnlen(user, 64); ++ SecurityBlob->UserName.MaximumLength = ++ cpu_to_le16(SecurityBlob->UserName.Length); ++ SecurityBlob->UserName.Buffer = ++ cpu_to_le32(SecurityBlobLength); ++ bcc_ptr += SecurityBlob->UserName.Length; ++ SecurityBlobLength += SecurityBlob->UserName.Length; ++ SecurityBlob->UserName.Length = ++ cpu_to_le16(SecurityBlob->UserName.Length); ++ } ++ /* BB fill in our workstation name if known BB */ ++ ++ strcpy(bcc_ptr, "Linux version "); ++ bcc_ptr += strlen("Linux version "); ++ strcpy(bcc_ptr, UTS_RELEASE); ++ bcc_ptr += strlen(UTS_RELEASE) + 1; ++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); ++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; ++ bcc_ptr++; /* null domain */ ++ *bcc_ptr = 0; ++ } ++ SecurityBlob->NegotiateFlags = ++ cpu_to_le32(SecurityBlob->NegotiateFlags); ++ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); ++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); ++ smb_buffer->smb_buf_length += BCC(smb_buffer); ++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); ++ ++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, ++ &bytes_returned, 1); ++ if (rc) { ++/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ ++ } else if ((smb_buffer_response->WordCount == 3) ++ || (smb_buffer_response->WordCount == 4)) { ++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action); ++ pSMBr->resp.SecurityBlobLength = ++ le16_to_cpu(pSMBr->resp.SecurityBlobLength); ++ if (pSMBr->resp.Action & GUEST_LOGIN) ++ cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ ++/* if(SecurityBlob2->MessageType != NtLm??){ ++ cFYI("Unexpected message type on auth response is %d ")); ++ } */ ++ if (ses) { ++ cFYI(1, ++ ("Does UID on challenge %d match auth response UID %d ", ++ ses->Suid, smb_buffer_response->Uid)); ++ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */ ++ bcc_ptr = pByteArea(smb_buffer_response); ++ /* response can have either 3 or 4 word count - Samba sends 3 */ ++ if ((pSMBr->resp.hdr.WordCount == 3) ++ || ((pSMBr->resp.hdr.WordCount == 4) ++ && (pSMBr->resp.SecurityBlobLength < ++ pSMBr->resp.ByteCount))) { ++ if (pSMBr->resp.hdr.WordCount == 4) { ++ bcc_ptr += ++ pSMBr->resp.SecurityBlobLength; ++ cFYI(1, ++ ("Security Blob Length %d ", ++ pSMBr->resp.SecurityBlobLength)); ++ } ++ ++ cFYI(1, ++ ("NTLMSSP response to Authenticate ")); ++ ++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { ++ if ((long) (bcc_ptr) % 2) { ++ remaining_words = ++ (BCC(smb_buffer_response) ++ - 1) / 2; ++ bcc_ptr++; /* Unicode strings must be word aligned */ ++ } else { ++ remaining_words = BCC(smb_buffer_response) / 2; ++ } ++ len = ++ UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); ++/* We look for obvious messed up bcc or strings in response so we do not go off ++ the end since (at least) WIN2K and Windows XP have a major bug in not null ++ terminating last Unicode string in response */ ++ ses->serverOS = ++ cifs_kcalloc(2 * (len + 1), GFP_KERNEL); ++ cifs_strfromUCS_le(ses->serverOS, ++ (wchar_t *) ++ bcc_ptr, len, ++ nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ remaining_words -= len + 1; ++ ses->serverOS[2 * len] = 0; ++ ses->serverOS[1 + (2 * len)] = 0; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *) ++ bcc_ptr, ++ remaining_words ++ - 1); ++ ses->serverNOS = ++ cifs_kcalloc(2 * (len + 1), ++ GFP_KERNEL); ++ cifs_strfromUCS_le(ses-> ++ serverNOS, ++ (wchar_t *) ++ bcc_ptr, ++ len, ++ nls_codepage); ++ bcc_ptr += 2 * (len + 1); ++ ses->serverNOS[2 * len] = 0; ++ ses->serverNOS[1+(2*len)] = 0; ++ remaining_words -= len + 1; ++ if (remaining_words > 0) { ++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); ++ /* last string not always null terminated (e.g. for Windows XP & 2000) */ ++ ses->serverDomain = ++ cifs_kcalloc(2 * ++ (len + ++ 1), ++ GFP_KERNEL); ++ cifs_strfromUCS_le ++ (ses-> ++ serverDomain, ++ (wchar_t *) ++ bcc_ptr, len, ++ nls_codepage); ++ bcc_ptr += ++ 2 * (len + 1); ++ ses-> ++ serverDomain[2 ++ * len] ++ = 0; ++ ses-> ++ serverDomain[1 ++ + ++ (2 ++ * ++ len)] ++ = 0; ++ } /* else no more room so create dummy domain string */ ++ else ++ ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL); ++ } else { /* no room so create dummy domain and NOS string */ ++ ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL); ++ ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL); ++ } ++ } else { /* ASCII */ ++ len = strnlen(bcc_ptr, 1024); ++ if (((long) bcc_ptr + len) - ++ (long) pByteArea(smb_buffer_response) ++ <= BCC(smb_buffer_response)) { ++ ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL); ++ strncpy(ses->serverOS,bcc_ptr, len); ++ ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; /* null terminate the string */ ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL); ++ strncpy(ses->serverNOS, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ ++ len = strnlen(bcc_ptr, 1024); ++ ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL); ++ strncpy(ses->serverDomain, bcc_ptr, len); ++ bcc_ptr += len; ++ bcc_ptr[0] = 0; ++ bcc_ptr++; ++ } else ++ cFYI(1, ++ ("Variable field of length %d extends beyond end of smb ", ++ len)); ++ } ++ } else { ++ cERROR(1, ++ (" Security Blob Length extends beyond end of SMB")); ++ } ++ } else { ++ cERROR(1, ("No session structure passed in.")); ++ } ++ } else { ++ cERROR(1, ++ (" Invalid Word count %d: ", ++ smb_buffer_response->WordCount)); ++ rc = -EIO; ++ } ++ ++ if (smb_buffer) ++ cifs_buf_release(smb_buffer); ++ ++ return rc; ++} ++ ++int ++CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ++ const char *tree, struct cifsTconInfo *tcon, ++ const struct nls_table *nls_codepage) ++{ ++ struct smb_hdr *smb_buffer; ++ struct smb_hdr *smb_buffer_response; ++ TCONX_REQ *pSMB; ++ TCONX_RSP *pSMBr; ++ char *bcc_ptr; ++ int rc = 0; ++ int length; ++ ++ if (ses == NULL) ++ return -EIO; ++ ++ smb_buffer = cifs_buf_get(); ++ if (smb_buffer == 0) { ++ return -ENOMEM; ++ } ++ smb_buffer_response = smb_buffer; ++ ++ header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, ++ NULL /*no tid */ , 4 /*wct */ ); ++ smb_buffer->Uid = ses->Suid; ++ pSMB = (TCONX_REQ *) smb_buffer; ++ pSMBr = (TCONX_RSP *) smb_buffer_response; ++ ++ pSMB->AndXCommand = 0xFF; ++ pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); ++ pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ ++ bcc_ptr = &(pSMB->Password[0]); ++ bcc_ptr++; /* skip password */ ++ ++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) ++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; ++ ++ if (ses->capabilities & CAP_STATUS32) { ++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; ++ } ++ if (ses->capabilities & CAP_DFS) { ++ smb_buffer->Flags2 |= SMBFLG2_DFS; ++ } ++ if (ses->capabilities & CAP_UNICODE) { ++ smb_buffer->Flags2 |= SMBFLG2_UNICODE; ++ length = ++ cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage); ++ bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ ++ bcc_ptr += 2; /* skip trailing null */ ++ } else { /* ASCII */ ++ ++ strcpy(bcc_ptr, tree); ++ bcc_ptr += strlen(tree) + 1; ++ } ++ strcpy(bcc_ptr, "?????"); ++ bcc_ptr += strlen("?????"); ++ bcc_ptr += 1; ++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer); ++ smb_buffer->smb_buf_length += BCC(smb_buffer); ++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer)); ++ ++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0); ++ ++ /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ ++ /* above now done in SendReceive */ ++ if ((rc == 0) && (tcon != NULL)) { ++ tcon->tidStatus = CifsGood; ++ tcon->tid = smb_buffer_response->Tid; ++ bcc_ptr = pByteArea(smb_buffer_response); ++ length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); ++ /* skip service field (NB: this field is always ASCII) */ ++ bcc_ptr += length + 1; ++ strncpy(tcon->treeName, tree, MAX_TREE_SIZE); ++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { ++ length = UniStrnlen((wchar_t *) bcc_ptr, 512); ++ if (((long) bcc_ptr + (2 * length)) - ++ (long) pByteArea(smb_buffer_response) <= ++ BCC(smb_buffer_response)) { ++ if(tcon->nativeFileSystem) ++ kfree(tcon->nativeFileSystem); ++ tcon->nativeFileSystem = ++ cifs_kcalloc(length + 2, GFP_KERNEL); ++ cifs_strfromUCS_le(tcon->nativeFileSystem, ++ (wchar_t *) bcc_ptr, ++ length, nls_codepage); ++ bcc_ptr += 2 * length; ++ bcc_ptr[0] = 0; /* null terminate the string */ ++ bcc_ptr[1] = 0; ++ bcc_ptr += 2; ++ } ++ /* else do not bother copying these informational fields */ ++ } else { ++ length = strnlen(bcc_ptr, 1024); ++ if (((long) bcc_ptr + length) - ++ (long) pByteArea(smb_buffer_response) <= ++ BCC(smb_buffer_response)) { ++ if(tcon->nativeFileSystem) ++ kfree(tcon->nativeFileSystem); ++ tcon->nativeFileSystem = ++ cifs_kcalloc(length + 1, GFP_KERNEL); ++ strncpy(tcon->nativeFileSystem, bcc_ptr, ++ length); ++ } ++ /* else do not bother copying these informational fields */ ++ } ++ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); ++ cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); ++ } else if ((rc == 0) && tcon == NULL) { ++ /* all we need to save for IPC$ connection */ ++ ses->ipc_tid = smb_buffer_response->Tid; ++ } ++ ++ if (smb_buffer) ++ cifs_buf_release(smb_buffer); ++ return rc; ++} ++ ++int ++cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) ++{ ++ int rc = 0; ++ int xid; ++ struct cifsSesInfo *ses = NULL; ++ struct task_struct *cifsd_task; ++ ++ xid = GetXid(); ++ ++ if (cifs_sb->tcon) { ++ ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ ++ rc = CIFSSMBTDis(xid, cifs_sb->tcon); ++ if (rc == -EBUSY) { ++ FreeXid(xid); ++ return 0; ++ } ++ tconInfoFree(cifs_sb->tcon); ++ if ((ses) && (ses->server)) { ++ /* save off task so we do not refer to ses later */ ++ cifsd_task = ses->server->tsk; ++ cFYI(1, ("About to do SMBLogoff ")); ++ rc = CIFSSMBLogoff(xid, ses); ++ if (rc == -EBUSY) { ++ FreeXid(xid); ++ return 0; ++ } else if (rc == -ESHUTDOWN) { ++ cFYI(1,("Waking up socket by sending it signal")); ++ send_sig(SIGKILL,cifsd_task,1); ++ rc = 0; ++ } /* else - we have an smb session ++ left on this socket do not kill cifsd */ ++ } else ++ cFYI(1, ("No session or bad tcon")); ++ } ++ ++ cifs_sb->tcon = NULL; ++ if (ses) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ / 2); ++ } ++ if (ses) ++ sesInfoFree(ses); ++ ++ FreeXid(xid); ++ return rc; /* BB check if we should always return zero here */ ++} ++ ++int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, ++ struct nls_table * nls_info) ++{ ++ int rc = 0; ++ char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; ++ int ntlmv2_flag = FALSE; ++ ++ /* what if server changes its buffer size after dropping the session? */ ++ if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ { ++ rc = CIFSSMBNegotiate(xid, pSesInfo); ++ if(rc == -EAGAIN) /* retry only once on 1st time connection */ { ++ rc = CIFSSMBNegotiate(xid, pSesInfo); ++ if(rc == -EAGAIN) ++ rc = -EHOSTDOWN; ++ } ++ if(rc == 0) { ++ spin_lock(&GlobalMid_Lock); ++ if(pSesInfo->server->tcpStatus != CifsExiting) ++ pSesInfo->server->tcpStatus = CifsGood; ++ else ++ rc = -EHOSTDOWN; ++ spin_unlock(&GlobalMid_Lock); ++ ++ } ++ } ++ if (!rc) { ++ pSesInfo->capabilities = pSesInfo->server->capabilities; ++ if(linuxExtEnabled == 0) ++ pSesInfo->capabilities &= (~CAP_UNIX); ++ pSesInfo->sequence_number = 0; ++ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", ++ pSesInfo->server->secMode, ++ pSesInfo->server->capabilities, ++ pSesInfo->server->timeZone)); ++ if (extended_security ++ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) ++ && (pSesInfo->server->secType == NTLMSSP)) { ++ cFYI(1, ("New style sesssetup ")); ++ rc = CIFSSpnegoSessSetup(xid, pSesInfo, ++ NULL /* security blob */, ++ 0 /* blob length */, ++ nls_info); ++ } else if (extended_security ++ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) ++ && (pSesInfo->server->secType == RawNTLMSSP)) { ++ cFYI(1, ("NTLMSSP sesssetup ")); ++ rc = CIFSNTLMSSPNegotiateSessSetup(xid, ++ pSesInfo, ++ &ntlmv2_flag, ++ nls_info); ++ if (!rc) { ++ if(ntlmv2_flag) { ++ char * v2_response; ++ cFYI(1,("Can use more secure NTLM version 2 password hash")); ++ CalcNTLMv2_partial_mac_key(pSesInfo, ++ nls_info); ++ v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL); ++ if(v2_response) { ++ CalcNTLMv2_response(pSesInfo,v2_response); ++/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */ ++ kfree(v2_response); ++ /* BB Put dummy sig in SessSetup PDU? */ ++ } else ++ rc = -ENOMEM; ++ ++ } else { ++ SMBNTencrypt(pSesInfo->password, ++ pSesInfo->server->cryptKey, ++ ntlm_session_key); ++ ++ cifs_calculate_mac_key(pSesInfo->mac_signing_key, ++ ntlm_session_key, ++ pSesInfo->password); ++ } ++ /* for better security the weaker lanman hash not sent ++ in AuthSessSetup so we no longer calculate it */ ++ ++ rc = CIFSNTLMSSPAuthSessSetup(xid, ++ pSesInfo, ++ ntlm_session_key, ++ ntlmv2_flag, ++ nls_info); ++ } ++ } else { /* old style NTLM 0.12 session setup */ ++ SMBNTencrypt(pSesInfo->password, ++ pSesInfo->server->cryptKey, ++ ntlm_session_key); ++ ++ cifs_calculate_mac_key(pSesInfo->mac_signing_key, ++ ntlm_session_key, pSesInfo->password); ++ rc = CIFSSessSetup(xid, pSesInfo, ++ ntlm_session_key, nls_info); ++ } ++ if (rc) { ++ cERROR(1,("Send error in SessSetup = %d",rc)); ++ } else { ++ cFYI(1,("CIFS Session Established successfully")); ++ pSesInfo->status = CifsGood; ++ } ++ } ++ return rc; ++} ++ +diff -urN linux-2.4.29.old/fs/cifs/dir.c linux-2.4.29/fs/cifs/dir.c +--- linux-2.4.29.old/fs/cifs/dir.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/dir.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,425 @@ ++/* ++ * fs/cifs/dir.c ++ * ++ * vfs operations that deal with dentries ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/fs.h> ++#include <linux/stat.h> ++#include <linux/slab.h> ++#include "cifsfs.h" ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_debug.h" ++#include "cifs_fs_sb.h" ++ ++void ++renew_parental_timestamps(struct dentry *direntry) ++{ ++ /* BB check if there is a way to get the kernel to do this or if we really need this */ ++ do { ++ direntry->d_time = jiffies; ++ direntry = direntry->d_parent; ++ } while (!IS_ROOT(direntry)); ++} ++ ++/* Note: caller must free return buffer */ ++char * ++build_path_from_dentry(struct dentry *direntry) ++{ ++ struct dentry *temp; ++ int namelen = 0; ++ char *full_path; ++ ++ if(direntry == NULL) ++ return NULL; /* not much we can do if dentry is freed and ++ we need to reopen the file after it was closed implicitly ++ when the server crashed */ ++ ++cifs_bp_rename_retry: ++ for (temp = direntry; !IS_ROOT(temp);) { ++ namelen += (1 + temp->d_name.len); ++ temp = temp->d_parent; ++ if(temp == NULL) { ++ cERROR(1,("corrupt dentry")); ++ return NULL; ++ } ++ } ++ ++ full_path = kmalloc(namelen+1, GFP_KERNEL); ++ if(full_path == NULL) ++ return full_path; ++ full_path[namelen] = 0; /* trailing null */ ++ ++ for (temp = direntry; !IS_ROOT(temp);) { ++ namelen -= 1 + temp->d_name.len; ++ if (namelen < 0) { ++ break; ++ } else { ++ full_path[namelen] = '\\'; ++ strncpy(full_path + namelen + 1, temp->d_name.name, ++ temp->d_name.len); ++ cFYI(0, (" name: %s ", full_path + namelen)); ++ } ++ temp = temp->d_parent; ++ if(temp == NULL) { ++ cERROR(1,("corrupt dentry")); ++ kfree(full_path); ++ return NULL; ++ } ++ } ++ if (namelen != 0) { ++ cERROR(1, ++ ("We did not end path lookup where we expected namelen is %d", ++ namelen)); ++ /* presumably this is only possible if we were racing with a rename ++ of one of the parent directories (we can not lock the dentries ++ above us to prevent this, but retrying should be harmless) */ ++ kfree(full_path); ++ namelen = 0; ++ goto cifs_bp_rename_retry; ++ } ++ ++ return full_path; ++} ++ ++/* Note: caller must free return buffer */ ++char * ++build_wildcard_path_from_dentry(struct dentry *direntry) ++{ ++ struct dentry *temp; ++ int namelen = 0; ++ char *full_path; ++ ++ if(direntry == NULL) ++ return NULL; /* not much we can do if dentry is freed and ++ we need to reopen the file after it was closed implicitly ++ when the server crashed */ ++ ++cifs_bwp_rename_retry: ++ for (temp = direntry; !IS_ROOT(temp);) { ++ namelen += (1 + temp->d_name.len); ++ temp = temp->d_parent; ++ if(temp == NULL) { ++ cERROR(1,("corrupt dentry")); ++ return NULL; ++ } ++ } ++ ++ full_path = kmalloc(namelen+3, GFP_KERNEL); ++ if(full_path == NULL) ++ return full_path; ++ ++ full_path[namelen] = '\\'; ++ full_path[namelen+1] = '*'; ++ full_path[namelen+2] = 0; /* trailing null */ ++ ++ for (temp = direntry; !IS_ROOT(temp);) { ++ namelen -= 1 + temp->d_name.len; ++ if (namelen < 0) { ++ break; ++ } else { ++ full_path[namelen] = '\\'; ++ strncpy(full_path + namelen + 1, temp->d_name.name, ++ temp->d_name.len); ++ cFYI(0, (" name: %s ", full_path + namelen)); ++ } ++ temp = temp->d_parent; ++ if(temp == NULL) { ++ cERROR(1,("corrupt dentry")); ++ kfree(full_path); ++ return NULL; ++ } ++ } ++ if (namelen != 0) { ++ cERROR(1, ++ ("We did not end path lookup where we expected namelen is %d", ++ namelen)); ++ /* presumably this is only possible if we were racing with a rename ++ of one of the parent directories (we can not lock the dentries ++ above us to prevent this, but retrying should be harmless) */ ++ kfree(full_path); ++ namelen = 0; ++ goto cifs_bwp_rename_retry; ++ } ++ ++ return full_path; ++} ++ ++/* Inode operations in similar order to how they appear in the Linux file fs.h */ ++ ++int ++cifs_create(struct inode *inode, struct dentry *direntry, int mode) ++{ ++ int rc = -ENOENT; ++ int xid; ++ int oplock = 0; /* no sense requested oplock if we are just going to ++ immediately close the file */ ++ __u16 fileHandle; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ FILE_ALL_INFO * buf = NULL; ++ struct inode *newinode = NULL; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ down(&direntry->d_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(direntry); ++ up(&direntry->d_sb->s_vfs_rename_sem); ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ ++ /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */ ++ ++ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); ++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, ++ GENERIC_WRITE, CREATE_NOT_DIR, ++ &fileHandle, &oplock, buf, cifs_sb->local_nls); ++ if (rc) { ++ cFYI(1, ("cifs_create returned 0x%x ", rc)); ++ } else { ++ /* BB for case of overwriting existing file can we use the inode that was ++ passed in rather than creating new one?? */ ++ if (pTcon->ses->capabilities & CAP_UNIX) ++ rc = cifs_get_inode_info_unix(&newinode, full_path, ++ inode->i_sb,xid); ++ else ++ rc = cifs_get_inode_info(&newinode, full_path, ++ buf, inode->i_sb,xid); ++ ++ if (rc != 0) { ++ cFYI(1,("Create worked but get_inode_info failed with rc = %d", ++ rc)); ++ } else { ++ direntry->d_op = &cifs_dentry_ops; ++ d_instantiate(direntry, newinode); ++ } ++ CIFSSMBClose(xid, pTcon, fileHandle); ++ ++ if(newinode) { ++ newinode->i_mode = mode; ++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) ++ CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, ++ (__u64)-1, ++ (__u64)-1, ++ 0 /* dev */, ++ cifs_sb->local_nls); ++ else { /* BB implement via Windows security descriptors */ ++ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ ++ /* in the meantime could set r/o dos attribute when perms are eg: ++ mode & 0222 == 0 */ ++ } ++ } ++ } ++ ++ if (buf) ++ kfree(buf); ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ ++ return rc; ++} ++ ++int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int device_number) ++{ ++ int rc = -EPERM; ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ struct inode * newinode = NULL; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ down(&direntry->d_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(direntry); ++ up(&direntry->d_sb->s_vfs_rename_sem); ++ if(full_path == NULL) ++ rc = -ENOMEM; ++ ++ if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { ++ rc = CIFSSMBUnixSetPerms(xid, pTcon, ++ full_path, mode, current->euid, current->egid, ++ device_number, cifs_sb->local_nls); ++ if(!rc) { ++ rc = cifs_get_inode_info_unix(&newinode, full_path, ++ inode->i_sb,xid); ++ direntry->d_op = &cifs_dentry_ops; ++ if(rc == 0) ++ d_instantiate(direntry, newinode); ++ } ++ } ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ ++ return rc; ++} ++ ++ ++struct dentry * ++cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry) ++{ ++ int xid; ++ int rc = 0; /* to get around spurious gcc warning, set to zero here */ ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct inode *newInode = NULL; ++ char *full_path = NULL; ++ ++ xid = GetXid(); ++ ++ cFYI(1, ++ (" parent inode = 0x%p name is: %s and dentry = 0x%p", ++ parent_dir_inode, direntry->d_name.name, direntry)); ++ ++ /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */ ++ ++ /* check whether path exists */ ++ ++ cifs_sb = CIFS_SB(parent_dir_inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ /* can not grab the rename sem here since it would ++ deadlock in the cases (beginning of sys_rename itself) ++ in which we already have the sb rename sem */ ++ full_path = build_path_from_dentry(direntry); ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ if (direntry->d_inode != NULL) { ++ cFYI(1, (" non-NULL inode in lookup")); ++ } else { ++ cFYI(1, (" NULL inode in lookup")); ++ } ++ cFYI(1, ++ (" Full path: %s inode = 0x%p", full_path, direntry->d_inode)); ++ ++ if (pTcon->ses->capabilities & CAP_UNIX) ++ rc = cifs_get_inode_info_unix(&newInode, full_path, ++ parent_dir_inode->i_sb,xid); ++ else ++ rc = cifs_get_inode_info(&newInode, full_path, NULL, ++ parent_dir_inode->i_sb,xid); ++ ++ if ((rc == 0) && (newInode != NULL)) { ++ direntry->d_op = &cifs_dentry_ops; ++ d_add(direntry, newInode); ++ ++ /* since paths are not looked up by component - the parent directories are presumed to be good here */ ++ renew_parental_timestamps(direntry); ++ ++ } else if (rc == -ENOENT) { ++ rc = 0; ++ d_add(direntry, NULL); ++ } else { ++ cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc)); ++ /* BB special case check for Access Denied - watch security ++ exposure of returning dir info implicitly via different rc ++ if file exists or not but no access BB */ ++ } ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return ERR_PTR(rc); ++} ++ ++int ++cifs_dir_open(struct inode *inode, struct file *file) ++{ /* NB: currently unused since searches are opened in readdir */ ++ int rc = 0; ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ if(file->f_dentry) { ++ down(&file->f_dentry->d_sb->s_vfs_rename_sem); ++ full_path = build_wildcard_path_from_dentry(file->f_dentry); ++ up(&file->f_dentry->d_sb->s_vfs_rename_sem); ++ } else { ++ FreeXid(xid); ++ return -EIO; ++ } ++ ++ cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path)); ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++static int ++cifs_d_revalidate(struct dentry *direntry, int flags) ++{ ++ int isValid = 1; ++ ++/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */ ++ ++ if (direntry->d_inode) { ++ if (cifs_revalidate(direntry)) { ++ /* unlock_kernel(); */ ++ return 0; ++ } ++ } else { ++ cFYI(1, ++ ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p", ++ direntry->d_name.name, direntry)); ++ } ++ ++/* unlock_kernel(); */ ++ ++ return isValid; ++} ++ ++/* static int cifs_d_delete(struct dentry *direntry) ++{ ++ int rc = 0; ++ ++ cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name)); ++ ++ return rc; ++} */ ++ ++struct dentry_operations cifs_dentry_ops = { ++ .d_revalidate = cifs_d_revalidate, ++/* d_delete: cifs_d_delete, *//* not needed except for debugging */ ++ /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ ++}; +diff -urN linux-2.4.29.old/fs/cifs/file.c linux-2.4.29/fs/cifs/file.c +--- linux-2.4.29.old/fs/cifs/file.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/file.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,2185 @@ ++/* ++ * fs/cifs/file.c ++ * ++ * vfs operations that deal with files ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/fs.h> ++#include <linux/stat.h> ++#include <linux/fcntl.h> ++#include <linux/version.h> ++#include <linux/pagemap.h> ++#include <linux/smp_lock.h> ++#include <linux/list.h> ++#include <asm/div64.h> ++#include <linux/mm.h> ++#include <linux/types.h> ++#include "cifsfs.h" ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_unicode.h" ++#include "cifs_debug.h" ++#include "cifs_fs_sb.h" ++ ++int ++cifs_open(struct inode *inode, struct file *file) ++{ ++ int rc = -EACCES; ++ int xid, oplock; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct cifsFileInfo *pCifsFile; ++ struct cifsInodeInfo *pCifsInode; ++ char *full_path = NULL; ++ int desiredAccess = 0x20197; ++ int disposition; ++ __u16 netfid; ++ FILE_ALL_INFO * buf = NULL; ++ time_t temp; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ down(&inode->i_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(file->f_dentry); ++ up(&inode->i_sb->s_vfs_rename_sem); ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ ++ cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); ++ if ((file->f_flags & O_ACCMODE) == O_RDONLY) ++ desiredAccess = GENERIC_READ; ++ else if ((file->f_flags & O_ACCMODE) == O_WRONLY) ++ desiredAccess = GENERIC_WRITE; ++ else if ((file->f_flags & O_ACCMODE) == O_RDWR) { ++ /* GENERIC_ALL is too much permission to request */ ++ /* can cause unnecessary access denied on create */ ++ /* desiredAccess = GENERIC_ALL; */ ++ desiredAccess = GENERIC_READ | GENERIC_WRITE; ++ } ++ ++/********************************************************************* ++ * open flag mapping table: ++ * ++ * POSIX Flag CIFS Disposition ++ * ---------- ---------------- ++ * O_CREAT FILE_OPEN_IF ++ * O_CREAT | O_EXCL FILE_CREATE ++ * O_CREAT | O_TRUNC FILE_OVERWRITE_IF ++ * O_TRUNC FILE_OVERWRITE ++ * none of the above FILE_OPEN ++ * ++ * Note that there is not a direct match between disposition ++ * FILE_SUPERSEDE (ie create whether or not file exists although ++ * O_CREAT | O_TRUNC is similar but truncates the existing ++ * file rather than creating a new file as FILE_SUPERSEDE does ++ * (which uses the attributes / metadata passed in on open call) ++ *? ++ *? O_SYNC is a reasonable match to CIFS writethrough flag ++ *? and the read write flags match reasonably. O_LARGEFILE ++ *? is irrelevant because largefile support is always used ++ *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, ++ * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation ++ *********************************************************************/ ++ ++ /* For 2.4 case, file was already checked for existence ++ before create by vfs lookup and created in create ++ entry point, we are now just opening the newly ++ created file with the right desiredAccess flags */ ++ ++ if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) ++ disposition = FILE_OPEN_IF; ++ else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC)) ++ disposition = FILE_OVERWRITE_IF; ++ else if((file->f_flags & O_CREAT) == O_CREAT) ++ disposition = FILE_OPEN_IF; ++ else ++ disposition = FILE_OPEN; ++ ++ if (oplockEnabled) ++ oplock = REQ_OPLOCK; ++ else ++ oplock = FALSE; ++ ++ /* BB pass O_SYNC flag through on file attributes .. BB */ ++ ++ /* Also refresh inode by passing in file_info buf returned by SMBOpen ++ and calling get_inode_info with returned buf (at least ++ helps non-Unix server case */ ++ ++ /* BB we can not do this if this is the second open of a file ++ and the first handle has writebehind data, we might be ++ able to simply do a filemap_fdatawrite/filemap_fdatawait first */ ++ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); ++ if(buf==0) { ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, ++ CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls); ++ if (rc) { ++ cFYI(1, ("cifs_open returned 0x%x ", rc)); ++ cFYI(1, ("oplock: %d ", oplock)); ++ } else { ++ file->private_data = ++ kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); ++ if (file->private_data) { ++ memset(file->private_data, 0, sizeof(struct cifsFileInfo)); ++ pCifsFile = (struct cifsFileInfo *) file->private_data; ++ pCifsFile->netfid = netfid; ++ pCifsFile->pid = current->pid; ++ init_MUTEX(&pCifsFile->fh_sem); ++ pCifsFile->pfile = file; /* needed for writepage */ ++ pCifsFile->pInode = inode; ++ pCifsFile->invalidHandle = FALSE; ++ pCifsFile->closePend = FALSE; ++ write_lock(&GlobalSMBSeslock); ++ spin_lock(&files_lock); ++ list_add(&pCifsFile->tlist,&pTcon->openFileList); ++ pCifsInode = CIFS_I(file->f_dentry->d_inode); ++ if(pCifsInode) { ++ /* want handles we can use to read with first */ ++ /* in the list so we do not have to walk the */ ++ /* list to search for one in prepare_write */ ++ if ((file->f_flags & O_ACCMODE) == O_WRONLY) { ++ list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList); ++ } else { ++ list_add(&pCifsFile->flist,&pCifsInode->openFileList); ++ } ++ spin_unlock(&files_lock); ++ write_unlock(&GlobalSMBSeslock); ++ if(pCifsInode->clientCanCacheRead) { ++ /* we have the inode open somewhere else ++ no need to discard cache data */ ++ } else { ++ if(buf) { ++ /* BB need same check in cifs_create too? */ ++ ++ /* if not oplocked, invalidate inode pages if mtime ++ or file size changed */ ++ temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); ++ if((file->f_dentry->d_inode->i_mtime == temp) && ++ (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) { ++ cFYI(1,("inode unchanged on server")); ++ } else { ++ if(file->f_dentry->d_inode->i_mapping) { ++ /* BB no need to lock inode until after invalidate*/ ++ /* since namei code should already have it locked?*/ ++ filemap_fdatasync(file->f_dentry->d_inode->i_mapping); ++ } ++ cFYI(1,("invalidating remote inode since open detected it changed")); ++ invalidate_inode_pages(file->f_dentry->d_inode); ++ } ++ } ++ } ++ if (pTcon->ses->capabilities & CAP_UNIX) ++ rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode, ++ full_path, inode->i_sb,xid); ++ else ++ rc = cifs_get_inode_info(&file->f_dentry->d_inode, ++ full_path, buf, inode->i_sb,xid); ++ ++ if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { ++ pCifsInode->clientCanCacheAll = TRUE; ++ pCifsInode->clientCanCacheRead = TRUE; ++ cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); ++ } else if((oplock & 0xF) == OPLOCK_READ) ++ pCifsInode->clientCanCacheRead = TRUE; ++ } else { ++ spin_unlock(&files_lock); ++ write_unlock(&GlobalSMBSeslock); ++ } ++ if(oplock & CIFS_CREATE_ACTION) { ++ /* time to set mode which we can not set earlier due ++ to problems creating new read-only files */ ++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) ++ CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode, ++ (__u64)-1, ++ (__u64)-1, ++ 0 /* dev */, ++ cifs_sb->local_nls); ++ else {/* BB implement via Windows security descriptors */ ++ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ ++ /* in the meantime could set r/o dos attribute when perms are eg: ++ mode & 0222 == 0 */ ++ } ++ } ++ } ++ } ++ ++ if (buf) ++ kfree(buf); ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++/* Try to reaquire byte range locks that were released when session */ ++/* to server was lost */ ++static int cifs_relock_file(struct cifsFileInfo * cifsFile) ++{ ++ int rc = 0; ++ ++/* BB list all locks open on this file and relock */ ++ ++ return rc; ++} ++ ++static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush) ++{ ++ int rc = -EACCES; ++ int xid, oplock; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct cifsFileInfo *pCifsFile; ++ struct cifsInodeInfo *pCifsInode; ++ char *full_path = NULL; ++ int desiredAccess = 0x20197; ++ int disposition = FILE_OPEN; ++ __u16 netfid; ++ ++ if(inode == NULL) ++ return -EBADF; ++ if (file->private_data) { ++ pCifsFile = (struct cifsFileInfo *) file->private_data; ++ } else ++ return -EBADF; ++ ++ xid = GetXid(); ++ down(&pCifsFile->fh_sem); ++ if(pCifsFile->invalidHandle == FALSE) { ++ up(&pCifsFile->fh_sem); ++ FreeXid(xid); ++ return 0; ++ } ++ ++ if(file->f_dentry == NULL) { ++ up(&pCifsFile->fh_sem); ++ cFYI(1,("failed file reopen, no valid name if dentry freed")); ++ FreeXid(xid); ++ return -EBADF; ++ } ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++/* can not grab rename sem here because various ops, including ++those that already have the rename sem can end up causing writepage ++to get called and if the server was down that means we end up here, ++and we can never tell if the caller already has the rename_sem */ ++ full_path = build_path_from_dentry(file->f_dentry); ++ if(full_path == NULL) { ++ up(&pCifsFile->fh_sem); ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ ++ cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path)); ++ if ((file->f_flags & O_ACCMODE) == O_RDONLY) ++ desiredAccess = GENERIC_READ; ++ else if ((file->f_flags & O_ACCMODE) == O_WRONLY) ++ desiredAccess = GENERIC_WRITE; ++ else if ((file->f_flags & O_ACCMODE) == O_RDWR) { ++ /* GENERIC_ALL is too much permission to request */ ++ /* can cause unnecessary access denied on create */ ++ /* desiredAccess = GENERIC_ALL; */ ++ desiredAccess = GENERIC_READ | GENERIC_WRITE; ++ } ++ ++ if (oplockEnabled) ++ oplock = REQ_OPLOCK; ++ else ++ oplock = FALSE; ++ ++ ++ /* Can not refresh inode by passing in file_info buf to be returned ++ by SMBOpen and then calling get_inode_info with returned buf ++ since file might have write behind data that needs to be flushed ++ and server version of file size can be stale. If we ++ knew for sure that inode was not dirty locally we could do this */ ++ ++/* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); ++ if(buf==0) { ++ up(&pCifsFile->fh_sem); ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return -ENOMEM; ++ }*/ ++ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, ++ CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls); ++ if (rc) { ++ up(&pCifsFile->fh_sem); ++ cFYI(1, ("cifs_open returned 0x%x ", rc)); ++ cFYI(1, ("oplock: %d ", oplock)); ++ } else { ++ pCifsFile->netfid = netfid; ++ pCifsFile->invalidHandle = FALSE; ++ up(&pCifsFile->fh_sem); ++ pCifsInode = CIFS_I(inode); ++ if(pCifsInode) { ++ if(can_flush) { ++ filemap_fdatasync(inode->i_mapping); ++ filemap_fdatawait(inode->i_mapping); ++ /* temporarily disable caching while we ++ go to server to get inode info */ ++ pCifsInode->clientCanCacheAll = FALSE; ++ pCifsInode->clientCanCacheRead = FALSE; ++ if (pTcon->ses->capabilities & CAP_UNIX) ++ rc = cifs_get_inode_info_unix(&inode, ++ full_path, inode->i_sb,xid); ++ else ++ rc = cifs_get_inode_info(&inode, ++ full_path, NULL, inode->i_sb,xid); ++ } /* else we are writing out data to server already ++ and could deadlock if we tried to flush data, and ++ since we do not know if we have data that would ++ invalidate the current end of file on the server ++ we can not go to the server to get the new ++ inod info */ ++ if((oplock & 0xF) == OPLOCK_EXCLUSIVE) { ++ pCifsInode->clientCanCacheAll = TRUE; ++ pCifsInode->clientCanCacheRead = TRUE; ++ cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode)); ++ } else if((oplock & 0xF) == OPLOCK_READ) { ++ pCifsInode->clientCanCacheRead = TRUE; ++ pCifsInode->clientCanCacheAll = FALSE; ++ } else { ++ pCifsInode->clientCanCacheRead = FALSE; ++ pCifsInode->clientCanCacheAll = FALSE; ++ } ++ cifs_relock_file(pCifsFile); ++ } ++ } ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_close(struct inode *inode, struct file *file) ++{ ++ int rc = 0; ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct cifsFileInfo *pSMBFile = ++ (struct cifsFileInfo *) file->private_data; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ if (pSMBFile) { ++ pSMBFile->closePend = TRUE; ++ spin_lock(&files_lock); ++ if(pTcon) { ++ /* no sense reconnecting to close a file that is ++ already closed */ ++ if (pTcon->tidStatus != CifsNeedReconnect) { ++ spin_unlock(&files_lock); ++ rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid); ++ spin_lock(&files_lock); ++ } ++ } ++ list_del(&pSMBFile->flist); ++ list_del(&pSMBFile->tlist); ++ spin_unlock(&files_lock); ++ if(pSMBFile->search_resume_name) ++ kfree(pSMBFile->search_resume_name); ++ kfree(file->private_data); ++ file->private_data = NULL; ++ } else ++ rc = -EBADF; ++ ++ if(list_empty(&(CIFS_I(inode)->openFileList))) { ++ cFYI(1,("closing last open instance for inode %p",inode)); ++ /* if the file is not open we do not know if we can cache ++ info on this inode, much less write behind and read ahead */ ++ CIFS_I(inode)->clientCanCacheRead = FALSE; ++ CIFS_I(inode)->clientCanCacheAll = FALSE; ++ } ++ if((rc ==0) && CIFS_I(inode)->write_behind_rc) ++ rc = CIFS_I(inode)->write_behind_rc; ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_closedir(struct inode *inode, struct file *file) ++{ ++ int rc = 0; ++ int xid; ++ struct cifsFileInfo *pSMBFileStruct = ++ (struct cifsFileInfo *) file->private_data; ++ ++ cFYI(1, ("Closedir inode = 0x%p with ", inode)); ++ ++ xid = GetXid(); ++ ++ if (pSMBFileStruct) { ++ cFYI(1, ("Freeing private data in close dir")); ++ kfree(file->private_data); ++ file->private_data = NULL; ++ } ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) ++{ ++ int rc, xid; ++ __u32 lockType = LOCKING_ANDX_LARGE_FILES; ++ __u32 numLock = 0; ++ __u32 numUnlock = 0; ++ __u64 length; ++ int wait_flag = FALSE; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ length = 1 + pfLock->fl_end - pfLock->fl_start; ++ ++ rc = -EACCES; ++ ++ xid = GetXid(); ++ ++ cFYI(1, ++ ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld", ++ cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start, ++ pfLock->fl_end)); ++ ++ if (pfLock->fl_flags & FL_POSIX) ++ cFYI(1, ("Posix ")); ++ if (pfLock->fl_flags & FL_FLOCK) ++ cFYI(1, ("Flock ")); ++/* if (pfLock->fl_flags & FL_SLEEP) { ++ cFYI(1, ("Blocking lock ")); ++ wait_flag = TRUE; ++ } */ ++ if (pfLock->fl_flags & FL_ACCESS) ++ cFYI(1, ("Process suspended by mandatory locking - not implemented yet ")); ++ if (pfLock->fl_flags & FL_LEASE) ++ cFYI(1, ("Lease on file - not implemented yet")); ++ if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_ACCESS | FL_LEASE))) ++ cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags)); ++ ++ if (pfLock->fl_type == F_WRLCK) { ++ cFYI(1, ("F_WRLCK ")); ++ numLock = 1; ++ } else if (pfLock->fl_type == F_UNLCK) { ++ cFYI(1, ("F_UNLCK ")); ++ numUnlock = 1; ++ } else if (pfLock->fl_type == F_RDLCK) { ++ cFYI(1, ("F_RDLCK ")); ++ lockType |= LOCKING_ANDX_SHARED_LOCK; ++ numLock = 1; ++ } else if (pfLock->fl_type == F_EXLCK) { ++ cFYI(1, ("F_EXLCK ")); ++ numLock = 1; ++ } else if (pfLock->fl_type == F_SHLCK) { ++ cFYI(1, ("F_SHLCK ")); ++ lockType |= LOCKING_ANDX_SHARED_LOCK; ++ numLock = 1; ++ } else ++ cFYI(1, ("Unknown type of lock ")); ++ ++ cifs_sb = CIFS_SB(file->f_dentry->d_sb); ++ pTcon = cifs_sb->tcon; ++ ++ if (file->private_data == NULL) { ++ FreeXid(xid); ++ return -EBADF; ++ } ++ ++ if (IS_GETLK(cmd)) { ++ rc = CIFSSMBLock(xid, pTcon, ++ ((struct cifsFileInfo *) file-> ++ private_data)->netfid, ++ length, ++ pfLock->fl_start, 0, 1, lockType, ++ 0 /* wait flag */ ); ++ if (rc == 0) { ++ rc = CIFSSMBLock(xid, pTcon, ++ ((struct cifsFileInfo *) file-> ++ private_data)->netfid, ++ length, ++ pfLock->fl_start, 1 /* numUnlock */ , ++ 0 /* numLock */ , lockType, ++ 0 /* wait flag */ ); ++ pfLock->fl_type = F_UNLCK; ++ if (rc != 0) ++ cERROR(1, ++ ("Error unlocking previously locked range %d during test of lock ", ++ rc)); ++ rc = 0; ++ ++ } else { ++ /* if rc == ERR_SHARING_VIOLATION ? */ ++ rc = 0; /* do not change lock type to unlock since range in use */ ++ } ++ ++ FreeXid(xid); ++ return rc; ++ } ++ ++ rc = CIFSSMBLock(xid, pTcon, ++ ((struct cifsFileInfo *) file->private_data)-> ++ netfid, length, ++ pfLock->fl_start, numUnlock, numLock, lockType, ++ wait_flag); ++ FreeXid(xid); ++ return rc; ++} ++ ++ssize_t ++cifs_write(struct file * file, const char *write_data, ++ size_t write_size, loff_t * poffset) ++{ ++ int rc = 0; ++ unsigned int bytes_written = 0; ++ unsigned int total_written; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ int xid, long_op; ++ struct cifsFileInfo * open_file; ++ ++ if(file->f_dentry == NULL) ++ return -EBADF; ++ ++ cifs_sb = CIFS_SB(file->f_dentry->d_sb); ++ if(cifs_sb == NULL) { ++ return -EBADF; ++ } ++ pTcon = cifs_sb->tcon; ++ ++ /*cFYI(1, ++ (" write %d bytes to offset %lld of %s", write_size, ++ *poffset, file->f_dentry->d_name.name)); */ ++ ++ if (file->private_data == NULL) { ++ return -EBADF; ++ } else { ++ open_file = (struct cifsFileInfo *) file->private_data; ++ } ++ ++ xid = GetXid(); ++ if(file->f_dentry->d_inode == NULL) { ++ FreeXid(xid); ++ return -EBADF; ++ } ++ ++ if (*poffset > file->f_dentry->d_inode->i_size) ++ long_op = 2; /* writes past end of file can take a long time */ ++ else ++ long_op = 1; ++ ++ for (total_written = 0; write_size > total_written; ++ total_written += bytes_written) { ++ rc = -EAGAIN; ++ while(rc == -EAGAIN) { ++ if(file->private_data == NULL) { ++ /* file has been closed on us */ ++ FreeXid(xid); ++ /* if we have gotten here we have written some data ++ and blocked, and the file has been freed on us ++ while we blocked so return what we managed to write */ ++ return total_written; ++ } ++ if(open_file->closePend) { ++ FreeXid(xid); ++ if(total_written) ++ return total_written; ++ else ++ return -EBADF; ++ } ++ if (open_file->invalidHandle) { ++ if((file->f_dentry == NULL) || ++ (file->f_dentry->d_inode == NULL)) { ++ FreeXid(xid); ++ return total_written; ++ } ++ /* we could deadlock if we called ++ filemap_fdatawait from here so tell ++ reopen_file not to flush data to server now */ ++ rc = cifs_reopen_file(file->f_dentry->d_inode, ++ file,FALSE); ++ if(rc != 0) ++ break; ++ } ++ ++ rc = CIFSSMBWrite(xid, pTcon, ++ open_file->netfid, ++ write_size - total_written, *poffset, ++ &bytes_written, ++ write_data + total_written, long_op); ++ } ++ if (rc || (bytes_written == 0)) { ++ if (total_written) ++ break; ++ else { ++ FreeXid(xid); ++ return rc; ++ } ++ } else ++ *poffset += bytes_written; ++ long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */ ++ } ++ ++#ifdef CONFIG_CIFS_STATS ++ if(total_written > 0) { ++ atomic_inc(&pTcon->num_writes); ++ spin_lock(&pTcon->stat_lock); ++ pTcon->bytes_written += total_written; ++ spin_unlock(&pTcon->stat_lock); ++ } ++#endif ++ ++ /* since the write may have blocked check these pointers again */ ++ if(file->f_dentry) { ++ if(file->f_dentry->d_inode) { ++ file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime = ++ CURRENT_TIME; ++ if (total_written > 0) { ++ if (*poffset > file->f_dentry->d_inode->i_size) ++ file->f_dentry->d_inode->i_size = *poffset; ++ } ++ mark_inode_dirty_sync(file->f_dentry->d_inode); ++ } ++ } ++ FreeXid(xid); ++ return total_written; ++} ++ ++static int ++cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) ++{ ++ struct address_space *mapping = page->mapping; ++ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; ++ char * write_data; ++ int rc = -EFAULT; ++ int bytes_written = 0; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct inode *inode; ++ struct cifsInodeInfo *cifsInode; ++ struct cifsFileInfo *open_file = NULL; ++ struct list_head *tmp; ++ struct list_head *tmp1; ++ ++ if (!mapping) { ++ return -EFAULT; ++ } else if(!mapping->host) { ++ return -EFAULT; ++ } ++ ++ inode = page->mapping->host; ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ offset += (loff_t)from; ++ write_data = kmap(page); ++ write_data += from; ++ ++ if((to > PAGE_CACHE_SIZE) || (from > to)) { ++ kunmap(page); ++ return -EIO; ++ } ++ ++ /* racing with truncate? */ ++ if(offset > mapping->host->i_size) { ++ kunmap(page); ++ return 0; /* don't care */ ++ } ++ ++ /* check to make sure that we are not extending the file */ ++ if(mapping->host->i_size - offset < (loff_t)to) ++ to = (unsigned)(mapping->host->i_size - offset); ++ ++ ++ cifsInode = CIFS_I(mapping->host); ++ read_lock(&GlobalSMBSeslock); ++ /* BB we should start at the end */ ++ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { ++ open_file = list_entry(tmp,struct cifsFileInfo, flist); ++ if(open_file->closePend) ++ continue; ++ /* We check if file is open for writing first */ ++ if((open_file->pfile) && ++ ((open_file->pfile->f_flags & O_RDWR) || ++ (open_file->pfile->f_flags & O_WRONLY))) { ++ read_unlock(&GlobalSMBSeslock); ++ bytes_written = cifs_write(open_file->pfile, write_data, ++ to-from, &offset); ++ read_lock(&GlobalSMBSeslock); ++ /* Does mm or vfs already set times? */ ++ inode->i_atime = inode->i_mtime = CURRENT_TIME; ++ if ((bytes_written > 0) && (offset)) { ++ rc = 0; ++ } else if(bytes_written < 0) { ++ if(rc == -EBADF) { ++ /* have seen a case in which ++ kernel seemed to have closed/freed a file ++ even with writes active so we might as well ++ see if there are other file structs to try ++ for the same inode before giving up */ ++ continue; ++ } else ++ rc = bytes_written; ++ } ++ break; /* now that we found a valid file handle ++ and tried to write to it we are done, no ++ sense continuing to loop looking for another */ ++ } ++ if(tmp->next == NULL) { ++ cFYI(1,("File instance %p removed",tmp)); ++ break; ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ if(open_file == NULL) { ++ cFYI(1,("No writeable filehandles for inode")); ++ rc = -EIO; ++ } ++ ++ kunmap(page); ++ return rc; ++} ++ ++#if 0 ++static int ++cifs_writepages(struct address_space *mapping, struct writeback_control *wbc) ++{ ++ int rc = -EFAULT; ++ int xid; ++ ++ xid = GetXid(); ++/* call 16K write then Setpageuptodate */ ++ FreeXid(xid); ++ return rc; ++} ++#endif ++ ++static int ++cifs_writepage(struct page* page) ++{ ++ int rc = -EFAULT; ++ int xid; ++ ++ xid = GetXid(); ++/* BB add check for wbc flags */ ++ page_cache_get(page); ++ if (!Page_Uptodate(page)) { ++ cFYI(1,("ppw - page not up to date")); ++ } ++ ++ rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE); ++ SetPageUptodate(page); /* BB add check for error and Clearuptodate? */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ unlock_page(page); ++#else ++ UnlockPage(page); ++#endif ++ page_cache_release(page); ++ FreeXid(xid); ++ return rc; ++} ++ ++static int ++cifs_commit_write(struct file *file, struct page *page, unsigned offset, ++ unsigned to) ++{ ++ int xid; ++ int rc = 0; ++ struct inode *inode = page->mapping->host; ++ loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; ++ char * page_data; ++ ++ xid = GetXid(); ++ cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to)); ++ if (position > inode->i_size){ ++ inode->i_size = position; ++ /*if (file->private_data == NULL) { ++ rc = -EBADF; ++ } else { ++ open_file = (struct cifsFileInfo *)file->private_data; ++ cifs_sb = CIFS_SB(inode->i_sb); ++ rc = -EAGAIN; ++ while(rc == -EAGAIN) { ++ if((open_file->invalidHandle) && ++ (!open_file->closePend)) { ++ rc = cifs_reopen_file(file->f_dentry->d_inode,file); ++ if(rc != 0) ++ break; ++ } ++ if(!open_file->closePend) { ++ rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon, ++ position, open_file->netfid, ++ open_file->pid,FALSE); ++ } else { ++ rc = -EBADF; ++ break; ++ } ++ } ++ cFYI(1,(" SetEOF (commit write) rc = %d",rc)); ++ }*/ ++ } ++ if (!Page_Uptodate(page)) { ++ position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset; ++ /* can not rely on (or let) writepage write this data */ ++ if(to < offset) { ++ cFYI(1,("Illegal offsets, can not copy from %d to %d", ++ offset,to)); ++ FreeXid(xid); ++ return rc; ++ } ++ /* this is probably better than directly calling ++ partialpage_write since in this function ++ the file handle is known which we might as well ++ leverage */ ++ /* BB check if anything else missing out of ppw */ ++ /* such as updating last write time */ ++ page_data = kmap(page); ++ rc = cifs_write(file, page_data+offset,to-offset, ++ &position); ++ if(rc > 0) ++ rc = 0; ++ /* else if rc < 0 should we set writebehind rc? */ ++ kunmap(page); ++ } else { ++ set_page_dirty(page); ++ } ++ ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_fsync(struct file *file, struct dentry *dentry, int datasync) ++{ ++ int xid; ++ int rc = 0; ++ struct inode * inode = file->f_dentry->d_inode; ++ ++ xid = GetXid(); ++ ++ cFYI(1, ("Sync file - name: %s datasync: 0x%x ", ++ dentry->d_name.name, datasync)); ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) ++ rc = filemap_fdatasync(inode->i_mapping); ++#else ++ filemap_fdatasync(inode->i_mapping); ++#endif ++ if(rc == 0) ++ CIFS_I(inode)->write_behind_rc = 0; ++ FreeXid(xid); ++ return rc; ++} ++ ++static int ++cifs_sync_page(struct page *page) ++{ ++ struct address_space *mapping; ++ struct inode *inode; ++ unsigned long index = page->index; ++ unsigned int rpages = 0; ++ int rc = 0; ++ ++ cFYI(1,("sync page %p",page)); ++ mapping = page->mapping; ++ if (!mapping) ++ return 0; ++ inode = mapping->host; ++ if (!inode) ++ return 0; ++ ++/* fill in rpages then ++ result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */ ++ ++ cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); ++ ++ if (rc < 0) ++ return rc; ++ return 0; ++} ++ ++/* ++ * As file closes, flush all cached write data for this inode checking ++ * for write behind errors. ++ * ++ */ ++int cifs_flush(struct file *file) ++{ ++ struct inode * inode = file->f_dentry->d_inode; ++ int rc = 0; ++ ++ /* Rather than do the steps manually: */ ++ /* lock the inode for writing */ ++ /* loop through pages looking for write behind data (dirty pages) */ ++ /* coalesce into contiguous 16K (or smaller) chunks to write to server */ ++ /* send to server (prefer in parallel) */ ++ /* deal with writebehind errors */ ++ /* unlock inode for writing */ ++ /* filemapfdatawrite appears easier for the time being */ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17)) ++ rc = filemap_fdatasync(inode->i_mapping); ++#else ++ filemap_fdatasync(inode->i_mapping); ++#endif ++ if(rc == 0) /* reset wb rc if we were able to write out dirty pages */ ++ CIFS_I(inode)->write_behind_rc = 0; ++ ++ cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc)); ++ ++ return rc; ++} ++ ++ ++ssize_t ++cifs_read(struct file * file, char *read_data, size_t read_size, ++ loff_t * poffset) ++{ ++ int rc = -EACCES; ++ unsigned int bytes_read = 0; ++ unsigned int total_read; ++ unsigned int current_read_size; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ int xid; ++ char * current_offset; ++ struct cifsFileInfo * open_file; ++ ++ xid = GetXid(); ++ cifs_sb = CIFS_SB(file->f_dentry->d_sb); ++ pTcon = cifs_sb->tcon; ++ ++ if (file->private_data == NULL) { ++ FreeXid(xid); ++ return -EBADF; ++ } ++ open_file = (struct cifsFileInfo *)file->private_data; ++ ++ if((file->f_flags & O_ACCMODE) == O_WRONLY) { ++ cFYI(1,("attempting read on write only file instance")); ++ } ++ ++ for (total_read = 0,current_offset=read_data; read_size > total_read; ++ total_read += bytes_read,current_offset+=bytes_read) { ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) ++ current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize); ++#else ++ current_read_size = min(read_size - total_read,cifs_sb->rsize); ++#endif ++ rc = -EAGAIN; ++ while(rc == -EAGAIN) { ++ if ((open_file->invalidHandle) && (!open_file->closePend)) { ++ rc = cifs_reopen_file(file->f_dentry->d_inode, ++ file,TRUE); ++ if(rc != 0) ++ break; ++ } ++ ++ rc = CIFSSMBRead(xid, pTcon, ++ open_file->netfid, ++ current_read_size, *poffset, ++ &bytes_read, ¤t_offset); ++ } ++ if (rc || (bytes_read == 0)) { ++ if (total_read) { ++ break; ++ } else { ++ FreeXid(xid); ++ return rc; ++ } ++ } else { ++#ifdef CONFIG_CIFS_STATS ++ atomic_inc(&pTcon->num_reads); ++ spin_lock(&pTcon->stat_lock); ++ pTcon->bytes_read += total_read; ++ spin_unlock(&pTcon->stat_lock); ++#endif ++ *poffset += bytes_read; ++ } ++ } ++ FreeXid(xid); ++ return total_read; ++} ++ ++int cifs_file_mmap(struct file * file, struct vm_area_struct * vma) ++{ ++ struct dentry * dentry = file->f_dentry; ++ int rc, xid; ++ ++ xid = GetXid(); ++ rc = cifs_revalidate(dentry); ++ if (rc) { ++ cFYI(1,("Validation prior to mmap failed, error=%d", rc)); ++ FreeXid(xid); ++ return rc; ++ } ++ rc = generic_file_mmap(file, vma); ++ FreeXid(xid); ++ return rc; ++} ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) ++static void cifs_copy_cache_pages(struct address_space *mapping, ++ struct list_head *pages, int bytes_read, ++ char *data,struct pagevec * plru_pvec) ++{ ++ struct page *page; ++ char * target; ++ ++ while (bytes_read > 0) { ++ if(list_empty(pages)) ++ break; ++ ++ page = list_entry(pages->prev, struct page, lru); ++ list_del(&page->lru); ++ ++ if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) { ++ page_cache_release(page); ++ cFYI(1,("Add page cache failed")); ++ continue; ++ } ++ ++ target = kmap_atomic(page,KM_USER0); ++ ++ if(PAGE_CACHE_SIZE > bytes_read) { ++ memcpy(target,data,bytes_read); ++ /* zero the tail end of this partial page */ ++ memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read); ++ bytes_read = 0; ++ } else { ++ memcpy(target,data,PAGE_CACHE_SIZE); ++ bytes_read -= PAGE_CACHE_SIZE; ++ } ++ kunmap_atomic(target,KM_USER0); ++ ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ unlock_page(page); ++ if (!pagevec_add(plru_pvec, page)) ++ __pagevec_lru_add(plru_pvec); ++ data += PAGE_CACHE_SIZE; ++ } ++ return; ++} ++ ++ ++static int ++cifs_readpages(struct file *file, struct address_space *mapping, ++ struct list_head *page_list, unsigned num_pages) ++{ ++ int rc = -EACCES; ++ int xid; ++ loff_t offset; ++ struct page * page; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ int bytes_read = 0; ++ unsigned int read_size,i; ++ char * smb_read_data = NULL; ++ struct smb_com_read_rsp * pSMBr; ++ struct pagevec lru_pvec; ++ struct cifsFileInfo * open_file; ++ ++ xid = GetXid(); ++ if (file->private_data == NULL) { ++ FreeXid(xid); ++ return -EBADF; ++ } ++ open_file = (struct cifsFileInfo *)file->private_data; ++ cifs_sb = CIFS_SB(file->f_dentry->d_sb); ++ pTcon = cifs_sb->tcon; ++ ++ pagevec_init(&lru_pvec, 0); ++ ++ for(i = 0;i<num_pages;) { ++ unsigned contig_pages; ++ struct page * tmp_page; ++ unsigned long expected_index; ++ ++ if(list_empty(page_list)) { ++ break; ++ } ++ page = list_entry(page_list->prev, struct page, lru); ++ offset = (loff_t)page->index << PAGE_CACHE_SHIFT; ++ ++ /* count adjacent pages that we will read into */ ++ contig_pages = 0; ++ expected_index = list_entry(page_list->prev,struct page,lru)->index; ++ list_for_each_entry_reverse(tmp_page,page_list,lru) { ++ if(tmp_page->index == expected_index) { ++ contig_pages++; ++ expected_index++; ++ } else { ++ break; ++ } ++ } ++ if(contig_pages + i > num_pages) { ++ contig_pages = num_pages - i; ++ } ++ ++ /* for reads over a certain size could initiate async read ahead */ ++ ++ read_size = contig_pages * PAGE_CACHE_SIZE; ++ /* Read size needs to be in multiples of one page */ ++ read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK); ++ ++ rc = -EAGAIN; ++ while(rc == -EAGAIN) { ++ if ((open_file->invalidHandle) && (!open_file->closePend)) { ++ rc = cifs_reopen_file(file->f_dentry->d_inode, ++ file, TRUE); ++ if(rc != 0) ++ break; ++ } ++ ++ rc = CIFSSMBRead(xid, pTcon, ++ open_file->netfid, ++ read_size, offset, ++ &bytes_read, &smb_read_data); ++ /* BB need to check return code here */ ++ if(rc== -EAGAIN) { ++ if(smb_read_data) { ++ cifs_buf_release(smb_read_data); ++ smb_read_data = NULL; ++ } ++ } ++ } ++ if ((rc < 0) || (smb_read_data == NULL)) { ++ cFYI(1,("Read error in readpages: %d",rc)); ++ /* clean up remaing pages off list */ ++ while (!list_empty(page_list) && (i < num_pages)) { ++ page = list_entry(page_list->prev, struct page, lru); ++ list_del(&page->lru); ++ page_cache_release(page); ++ } ++ break; ++ } else if (bytes_read > 0) { ++ pSMBr = (struct smb_com_read_rsp *)smb_read_data; ++ cifs_copy_cache_pages(mapping, page_list, bytes_read, ++ smb_read_data + 4 /* RFC1001 hdr */ + ++ le16_to_cpu(pSMBr->DataOffset), &lru_pvec); ++ ++ i += bytes_read >> PAGE_CACHE_SHIFT; ++#ifdef CONFIG_CIFS_STATS ++ atomic_inc(&pTcon->num_reads); ++ spin_lock(&pTcon->stat_lock); ++ pTcon->bytes_read += bytes_read; ++ spin_unlock(&pTcon->stat_lock); ++#endif ++ if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { ++ cFYI(1,("Partial page %d of %d read to cache",i++,num_pages)); ++ ++ i++; /* account for partial page */ ++ ++ /* server copy of file can have smaller size than client */ ++ /* BB do we need to verify this common case ? this case is ok - ++ if we are at server EOF we will hit it on next read */ ++ ++ /* while(!list_empty(page_list) && (i < num_pages)) { ++ page = list_entry(page_list->prev,struct page, list); ++ list_del(&page->list); ++ page_cache_release(page); ++ } ++ break; */ ++ } ++ } else { ++ cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset)); ++ /* BB turn off caching and do new lookup on file size at server? */ ++ while (!list_empty(page_list) && (i < num_pages)) { ++ page = list_entry(page_list->prev, struct page, lru); ++ list_del(&page->lru); ++ page_cache_release(page); /* BB removeme - replace with zero of page? */ ++ } ++ break; ++ } ++ if(smb_read_data) { ++ cifs_buf_release(smb_read_data); ++ smb_read_data = NULL; ++ } ++ bytes_read = 0; ++ } ++ ++ pagevec_lru_add(&lru_pvec); ++ ++/* need to free smb_read_data buf before exit */ ++ if(smb_read_data) { ++ cifs_buf_release(smb_read_data); ++ smb_read_data = NULL; ++ } ++ ++ FreeXid(xid); ++ return rc; ++} ++#endif ++ ++static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset) ++{ ++ char * read_data; ++ int rc; ++ ++ page_cache_get(page); ++ read_data = kmap(page); ++ /* for reads over a certain size could initiate async read ahead */ ++ ++ rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset); ++ ++ if (rc < 0) ++ goto io_error; ++ else { ++ cFYI(1,("Bytes read %d ",rc)); ++ } ++ ++ file->f_dentry->d_inode->i_atime = CURRENT_TIME; ++ ++ if(PAGE_CACHE_SIZE > rc) { ++ memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc); ++ } ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ rc = 0; ++ ++io_error: ++ kunmap(page); ++ page_cache_release(page); ++ return rc; ++} ++ ++static int ++cifs_readpage(struct file *file, struct page *page) ++{ ++ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; ++ int rc = -EACCES; ++ int xid; ++ ++ xid = GetXid(); ++ ++ if (file->private_data == NULL) { ++ FreeXid(xid); ++ return -EBADF; ++ } ++ ++ cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset)); ++ ++ rc = cifs_readpage_worker(file,page,&offset); ++ ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20)) ++ unlock_page(page); ++#else ++ UnlockPage(page); ++#endif ++ ++ FreeXid(xid); ++ return rc; ++} ++ ++/* We do not want to update the file size from server for inodes ++ open for write - to avoid races with writepage extending ++ the file - in the future we could consider allowing ++ refreshing the inode only on increases in the file size ++ but this is tricky to do without racing with writebehind ++ page caching in the current Linux kernel design */ ++ ++int is_size_safe_to_change(struct cifsInodeInfo * cifsInode) ++{ ++ struct list_head *tmp; ++ struct list_head *tmp1; ++ struct cifsFileInfo *open_file = NULL; ++ int rc = TRUE; ++ ++ if(cifsInode == NULL) ++ return rc; ++ ++ read_lock(&GlobalSMBSeslock); ++ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { ++ open_file = list_entry(tmp,struct cifsFileInfo, flist); ++ if(open_file == NULL) ++ break; ++ if(open_file->closePend) ++ continue; ++ /* We check if file is open for writing, ++ BB we could supplement this with a check to see if file size ++ changes have been flushed to server - ie inode metadata dirty */ ++ if((open_file->pfile) && ++ ((open_file->pfile->f_flags & O_RDWR) || ++ (open_file->pfile->f_flags & O_WRONLY))) { ++ rc = FALSE; ++ break; ++ } ++ if(tmp->next == NULL) { ++ cFYI(1,("File instance %p removed",tmp)); ++ break; ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ return rc; ++} ++ ++ ++void ++fill_in_inode(struct inode *tmp_inode, ++ FILE_DIRECTORY_INFO * pfindData, int *pobject_type) ++{ ++ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); ++ struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); ++ ++ pfindData->ExtFileAttributes = ++ le32_to_cpu(pfindData->ExtFileAttributes); ++ pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); ++ pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); ++ cifsInfo->cifsAttrs = pfindData->ExtFileAttributes; ++ cifsInfo->time = jiffies; ++ ++ /* Linux can not store file creation time unfortunately so ignore it */ ++ tmp_inode->i_atime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); ++ tmp_inode->i_mtime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); ++ tmp_inode->i_ctime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); ++ /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ ++ /* 2767 perms - indicate mandatory locking */ ++ /* BB fill in uid and gid here? with help from winbind? ++ or retrieve from NTFS stream extended attribute */ ++ if(atomic_read(&cifsInfo->inUse) == 0) { ++ tmp_inode->i_uid = cifs_sb->mnt_uid; ++ tmp_inode->i_gid = cifs_sb->mnt_gid; ++ /* set default mode. will override for dirs below */ ++ tmp_inode->i_mode = cifs_sb->mnt_file_mode; ++ } ++ ++ cFYI(0, ++ ("CIFS FFIRST: Attributes came in as 0x%x", ++ pfindData->ExtFileAttributes)); ++ if (pfindData->ExtFileAttributes & ATTR_REPARSE) { ++ *pobject_type = DT_LNK; ++ /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */ ++ tmp_inode->i_mode |= S_IFLNK; ++ } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) { ++ *pobject_type = DT_DIR; ++ /* override default perms since we do not lock dirs */ ++ if(atomic_read(&cifsInfo->inUse) == 0) { ++ tmp_inode->i_mode = cifs_sb->mnt_dir_mode; ++ } ++ tmp_inode->i_mode |= S_IFDIR; ++ } else { ++ *pobject_type = DT_REG; ++ tmp_inode->i_mode |= S_IFREG; ++ if(pfindData->ExtFileAttributes & ATTR_READONLY) ++ tmp_inode->i_mode &= ~(S_IWUGO); ++ ++ }/* could add code here - to validate if device or weird share type? */ ++ ++ /* can not fill in nlink here as in qpathinfo version and Unx search */ ++ if(atomic_read(&cifsInfo->inUse) == 0) { ++ atomic_set(&cifsInfo->inUse,1); ++ } ++ if(is_size_safe_to_change(cifsInfo)) { ++ /* can not safely change the file size here if the ++ client is writing to it due to potential races */ ++ tmp_inode->i_size = pfindData->EndOfFile; ++ ++ /* 512 bytes (2**9) is the fake blocksize that must be used */ ++ /* for this calculation, even though the reported blocksize is larger */ ++ tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9; ++ } ++ ++ if (pfindData->AllocationSize < pfindData->EndOfFile) ++ cFYI(1, ("Possible sparse file: allocation size less than end of file ")); ++ cFYI(1, ++ ("File Size %ld and blocks %ld and blocksize %ld", ++ (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks, ++ tmp_inode->i_blksize)); ++ if (S_ISREG(tmp_inode->i_mode)) { ++ cFYI(1, (" File inode ")); ++ tmp_inode->i_op = &cifs_file_inode_ops; ++ tmp_inode->i_fop = &cifs_file_ops; ++ tmp_inode->i_data.a_ops = &cifs_addr_ops; ++ } else if (S_ISDIR(tmp_inode->i_mode)) { ++ cFYI(1, (" Directory inode")); ++ tmp_inode->i_op = &cifs_dir_inode_ops; ++ tmp_inode->i_fop = &cifs_dir_ops; ++ } else if (S_ISLNK(tmp_inode->i_mode)) { ++ cFYI(1, (" Symbolic Link inode ")); ++ tmp_inode->i_op = &cifs_symlink_inode_ops; ++ } else { ++ cFYI(1, (" Init special inode ")); ++ init_special_inode(tmp_inode, tmp_inode->i_mode, ++ kdev_t_to_nr(tmp_inode->i_rdev)); ++ } ++} ++ ++void ++unix_fill_in_inode(struct inode *tmp_inode, ++ FILE_UNIX_INFO * pfindData, int *pobject_type) ++{ ++ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); ++ cifsInfo->time = jiffies; ++ atomic_inc(&cifsInfo->inUse); ++ ++ tmp_inode->i_atime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); ++ tmp_inode->i_mtime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime)); ++ tmp_inode->i_ctime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); ++ ++ tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); ++ pfindData->Type = le32_to_cpu(pfindData->Type); ++ if (pfindData->Type == UNIX_FILE) { ++ *pobject_type = DT_REG; ++ tmp_inode->i_mode |= S_IFREG; ++ } else if (pfindData->Type == UNIX_SYMLINK) { ++ *pobject_type = DT_LNK; ++ tmp_inode->i_mode |= S_IFLNK; ++ } else if (pfindData->Type == UNIX_DIR) { ++ *pobject_type = DT_DIR; ++ tmp_inode->i_mode |= S_IFDIR; ++ } else if (pfindData->Type == UNIX_CHARDEV) { ++ *pobject_type = DT_CHR; ++ tmp_inode->i_mode |= S_IFCHR; ++ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), ++ le64_to_cpu(pfindData->DevMinor) & MINORMASK); ++ } else if (pfindData->Type == UNIX_BLOCKDEV) { ++ *pobject_type = DT_BLK; ++ tmp_inode->i_mode |= S_IFBLK; ++ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor), ++ le64_to_cpu(pfindData->DevMinor) & MINORMASK); ++ } else if (pfindData->Type == UNIX_FIFO) { ++ *pobject_type = DT_FIFO; ++ tmp_inode->i_mode |= S_IFIFO; ++ } else if (pfindData->Type == UNIX_SOCKET) { ++ *pobject_type = DT_SOCK; ++ tmp_inode->i_mode |= S_IFSOCK; ++ } ++ ++ tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); ++ tmp_inode->i_gid = le64_to_cpu(pfindData->Gid); ++ tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks); ++ ++ pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes); ++ if(is_size_safe_to_change(cifsInfo)) { ++ /* can not safely change the file size here if the ++ client is writing to it due to potential races */ ++ pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile); ++ tmp_inode->i_size = pfindData->EndOfFile; ++ ++ /* 512 bytes (2**9) is the fake blocksize that must be used */ ++ /* for this calculation, not the real blocksize */ ++ tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9; ++ } ++ ++ if (S_ISREG(tmp_inode->i_mode)) { ++ cFYI(1, ("File inode")); ++ tmp_inode->i_op = &cifs_file_inode_ops; ++ tmp_inode->i_fop = &cifs_file_ops; ++ tmp_inode->i_data.a_ops = &cifs_addr_ops; ++ } else if (S_ISDIR(tmp_inode->i_mode)) { ++ cFYI(1, ("Directory inode")); ++ tmp_inode->i_op = &cifs_dir_inode_ops; ++ tmp_inode->i_fop = &cifs_dir_ops; ++ } else if (S_ISLNK(tmp_inode->i_mode)) { ++ cFYI(1, ("Symbolic Link inode")); ++ tmp_inode->i_op = &cifs_symlink_inode_ops; ++/* tmp_inode->i_fop = *//* do not need to set to anything */ ++ } else { ++ cFYI(1, ("Special inode")); ++ init_special_inode(tmp_inode, tmp_inode->i_mode, ++ kdev_t_to_nr(tmp_inode->i_rdev)); ++ } ++} ++ ++static void ++construct_dentry(struct qstr *qstring, struct file *file, ++ struct inode **ptmp_inode, struct dentry **pnew_dentry) ++{ ++ struct dentry *tmp_dentry; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct cifsInodeInfo *pCifsI; ++ ++ cFYI(1, ("For %s ", qstring->name)); ++ cifs_sb = CIFS_SB(file->f_dentry->d_sb); ++ pTcon = cifs_sb->tcon; ++ ++ qstring->hash = full_name_hash(qstring->name, qstring->len); ++ tmp_dentry = d_lookup(file->f_dentry, qstring); ++ if (tmp_dentry) { ++ cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode)); ++ *ptmp_inode = tmp_dentry->d_inode; ++ /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */ ++ if(*ptmp_inode == NULL) { ++ *ptmp_inode = new_inode(file->f_dentry->d_sb); ++ if(*ptmp_inode == NULL) ++ return; ++ d_instantiate(tmp_dentry, *ptmp_inode); ++ insert_inode_hash(*ptmp_inode); ++ pCifsI = CIFS_I(*ptmp_inode); ++ INIT_LIST_HEAD(&pCifsI->openFileList); ++ /* can not enable caching for this inode ++ until a file instance is open and we ++ can check the oplock flag on the open ++ response */ ++ (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) ++ (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ ++#endif ++ pCifsI->clientCanCacheRead = FALSE; ++ pCifsI->clientCanCacheAll = FALSE; ++ pCifsI->time = 0; ++ /* do not need to set cifs Attrs since ++ they are about to be overwritten ++ in fill_in_inode */ ++ atomic_set(&pCifsI->inUse, 0); ++ } ++ } else { ++ tmp_dentry = d_alloc(file->f_dentry, qstring); ++ if(tmp_dentry == NULL) { ++ cERROR(1,("Failed allocating dentry")); ++ return; ++ } ++ ++ if(ptmp_inode) { ++ *ptmp_inode = new_inode(file->f_dentry->d_sb); ++ if(*ptmp_inode == NULL) ++ return; ++ pCifsI = CIFS_I(*ptmp_inode); ++ insert_inode_hash(*ptmp_inode); ++ INIT_LIST_HEAD(&pCifsI->openFileList); ++ /* can not enable caching for this inode ++ until a file instance is open and we ++ can check the oplock flag on the open ++ response */ ++ (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) ++ (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ ++#endif ++ pCifsI->clientCanCacheRead = FALSE; ++ pCifsI->clientCanCacheAll = FALSE; ++ pCifsI->time = 0; ++ /* do not need to set cifs Attrs since ++ they are about to be overwritten ++ in fill_in_inode */ ++ atomic_set(&pCifsI->inUse, 0); ++ } ++ tmp_dentry->d_op = &cifs_dentry_ops; ++ d_instantiate(tmp_dentry, *ptmp_inode); ++ d_rehash(tmp_dentry); ++ } ++ ++ tmp_dentry->d_time = jiffies; ++ *pnew_dentry = tmp_dentry; ++} ++ ++static void reset_resume_key(struct file * dir_file, ++ unsigned char * filename, ++ unsigned int len,int Unicode,struct nls_table * nls_tab) { ++ struct cifsFileInfo *cifsFile; ++ ++ cifsFile = (struct cifsFileInfo *)dir_file->private_data; ++ if(cifsFile == NULL) ++ return; ++ if(cifsFile->search_resume_name) { ++ kfree(cifsFile->search_resume_name); ++ } ++ ++ if(Unicode) ++ len *= 2; ++ cifsFile->resume_name_length = len; ++ ++ cifsFile->search_resume_name = ++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL); ++ ++ if(cifsFile->search_resume_name == NULL) { ++ cERROR(1,("failed new resume key allocate, length %d", ++ cifsFile->resume_name_length)); ++ return; ++ } ++ if(Unicode) ++ cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name, ++ filename, len, nls_tab); ++ else ++ memcpy(cifsFile->search_resume_name, filename, ++ cifsFile->resume_name_length); ++ cFYI(1,("Reset resume key to: %s with len %d",filename,len)); ++ return; ++} ++ ++ ++ ++static int ++cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData, ++ struct file *file, filldir_t filldir, void *direntry) ++{ ++ struct inode *tmp_inode; ++ struct dentry *tmp_dentry; ++ int object_type,rc; ++ ++ pqstring->name = pfindData->FileName; ++ pqstring->len = pfindData->FileNameLength; ++ ++ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); ++ if((tmp_inode == NULL) || (tmp_dentry == NULL)) { ++ return -ENOMEM; ++ } ++ fill_in_inode(tmp_inode, pfindData, &object_type); ++ rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos, ++ tmp_inode->i_ino, object_type); ++ if(rc) { ++ /* due to readdir error we need to recalculate resume ++ key so next readdir will restart on right entry */ ++ cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName)); ++ } ++ dput(tmp_dentry); ++ return rc; ++} ++ ++static int ++cifs_filldir_unix(struct qstr *pqstring, ++ FILE_UNIX_INFO * pUnixFindData, struct file *file, ++ filldir_t filldir, void *direntry) ++{ ++ struct inode *tmp_inode; ++ struct dentry *tmp_dentry; ++ int object_type, rc; ++ ++ pqstring->name = pUnixFindData->FileName; ++ pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF); ++ ++ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry); ++ if((tmp_inode == NULL) || (tmp_dentry == NULL)) { ++ return -ENOMEM; ++ } ++ ++ unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type); ++ rc = filldir(direntry, pUnixFindData->FileName, pqstring->len, ++ file->f_pos, tmp_inode->i_ino, object_type); ++ if(rc) { ++ /* due to readdir error we need to recalculate resume ++ key so next readdir will restart on right entry */ ++ cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName)); ++ } ++ dput(tmp_dentry); ++ return rc; ++} ++ ++int ++cifs_readdir(struct file *file, void *direntry, filldir_t filldir) ++{ ++ int rc = 0; ++ int xid; ++ int Unicode = FALSE; ++ int UnixSearch = FALSE; ++ unsigned int bufsize, i; ++ __u16 searchHandle; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct cifsFileInfo *cifsFile = NULL; ++ char *full_path = NULL; ++ char *data; ++ struct qstr qstring; ++ T2_FFIRST_RSP_PARMS findParms; ++ T2_FNEXT_RSP_PARMS findNextParms; ++ FILE_DIRECTORY_INFO *pfindData; ++ FILE_DIRECTORY_INFO *lastFindData; ++ FILE_UNIX_INFO *pfindDataUnix; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(file->f_dentry->d_sb); ++ pTcon = cifs_sb->tcon; ++ bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; ++ if(bufsize > CIFS_MAX_MSGSIZE) { ++ FreeXid(xid); ++ return -EIO; ++ } ++ data = kmalloc(bufsize, GFP_KERNEL); ++ pfindData = (FILE_DIRECTORY_INFO *) data; ++ ++ if(file->f_dentry == NULL) { ++ FreeXid(xid); ++ return -EIO; ++ } ++ down(&file->f_dentry->d_sb->s_vfs_rename_sem); ++ full_path = build_wildcard_path_from_dentry(file->f_dentry); ++ up(&file->f_dentry->d_sb->s_vfs_rename_sem); ++ ++ ++ cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos)); ++ ++ switch ((int) file->f_pos) { ++ case 0: ++ if (filldir(direntry, ".", 1, file->f_pos, ++ file->f_dentry->d_inode->i_ino, DT_DIR) < 0) { ++ cERROR(1, ("Filldir for current dir failed ")); ++ break; ++ } ++ file->f_pos++; ++ /* fallthrough */ ++ case 1: ++ if (filldir(direntry, "..", 2, file->f_pos, ++ file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { ++ cERROR(1, ("Filldir for parent dir failed ")); ++ break; ++ } ++ file->f_pos++; ++ /* fallthrough */ ++ case 2: ++ if (file->private_data != NULL) { ++ cifsFile = ++ (struct cifsFileInfo *) file->private_data; ++ if (cifsFile->endOfSearch) { ++ if(cifsFile->emptyDir) { ++ cFYI(1, ("End of search, empty dir")); ++ rc = 0; ++ break; ++ } ++ } else { ++ cifsFile->invalidHandle = TRUE; ++ CIFSFindClose(xid, pTcon, cifsFile->netfid); ++ } ++ if(cifsFile->search_resume_name) { ++ kfree(cifsFile->search_resume_name); ++ cifsFile->search_resume_name = NULL; ++ } ++ } ++ rc = CIFSFindFirst(xid, pTcon, full_path, pfindData, ++ &findParms, cifs_sb->local_nls, ++ &Unicode, &UnixSearch); ++ cFYI(1, ("Count: %d End: %d ", findParms.SearchCount, ++ findParms.EndofSearch)); ++ ++ if (rc == 0) { ++ searchHandle = findParms.SearchHandle; ++ if(file->private_data == NULL) ++ file->private_data = ++ kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL); ++ if (file->private_data) { ++ memset(file->private_data, 0, ++ sizeof (struct cifsFileInfo)); ++ cifsFile = ++ (struct cifsFileInfo *) file->private_data; ++ cifsFile->netfid = searchHandle; ++ cifsFile->invalidHandle = FALSE; ++ init_MUTEX(&cifsFile->fh_sem); ++ } else { ++ rc = -ENOMEM; ++ break; ++ } ++ ++ renew_parental_timestamps(file->f_dentry); ++ lastFindData = ++ (FILE_DIRECTORY_INFO *) ((char *) pfindData + ++ findParms.LastNameOffset); ++ if((char *)lastFindData > (char *)pfindData + bufsize) { ++ cFYI(1,("last search entry past end of packet")); ++ rc = -EIO; ++ break; ++ } ++ /* Offset of resume key same for levels 257 and 514 */ ++ cifsFile->resume_key = lastFindData->FileIndex; ++ if(UnixSearch == FALSE) { ++ cifsFile->resume_name_length = ++ le32_to_cpu(lastFindData->FileNameLength); ++ if(cifsFile->resume_name_length > bufsize - 64) { ++ cFYI(1,("Illegal resume file name length %d", ++ cifsFile->resume_name_length)); ++ rc = -ENOMEM; ++ break; ++ } ++ cifsFile->search_resume_name = ++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL); ++ cFYI(1,("Last file: %s with name %d bytes long", ++ lastFindData->FileName, ++ cifsFile->resume_name_length)); ++ memcpy(cifsFile->search_resume_name, ++ lastFindData->FileName, ++ cifsFile->resume_name_length); ++ } else { ++ pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; ++ if (Unicode == TRUE) { ++ for(i=0;(pfindDataUnix->FileName[i] ++ | pfindDataUnix->FileName[i+1]); ++ i+=2) { ++ if(i > bufsize-64) ++ break; ++ } ++ cifsFile->resume_name_length = i + 2; ++ } else { ++ cifsFile->resume_name_length = ++ strnlen(pfindDataUnix->FileName, ++ bufsize-63); ++ } ++ if(cifsFile->resume_name_length > bufsize - 64) { ++ cFYI(1,("Illegal resume file name length %d", ++ cifsFile->resume_name_length)); ++ rc = -ENOMEM; ++ break; ++ } ++ cifsFile->search_resume_name = ++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL); ++ cFYI(1,("Last file: %s with name %d bytes long", ++ pfindDataUnix->FileName, ++ cifsFile->resume_name_length)); ++ memcpy(cifsFile->search_resume_name, ++ pfindDataUnix->FileName, ++ cifsFile->resume_name_length); ++ } ++ for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) { ++ if (UnixSearch == FALSE) { ++ pfindData->FileNameLength = ++ le32_to_cpu(pfindData->FileNameLength); ++ if (Unicode == TRUE) ++ pfindData->FileNameLength = ++ cifs_strfromUCS_le ++ (pfindData->FileName, ++ (wchar_t *) ++ pfindData->FileName, ++ (pfindData-> ++ FileNameLength) / 2, ++ cifs_sb->local_nls); ++ qstring.len = pfindData->FileNameLength; ++ if (((qstring.len != 1) ++ || (pfindData->FileName[0] != '.')) ++ && ((qstring.len != 2) ++ || (pfindData-> ++ FileName[0] != '.') ++ || (pfindData-> ++ FileName[1] != '.'))) { ++ if(cifs_filldir(&qstring, ++ pfindData, ++ file, filldir, ++ direntry)) { ++ /* do not end search if ++ kernel not ready to take ++ remaining entries yet */ ++ reset_resume_key(file, pfindData->FileName,qstring.len, ++ Unicode, cifs_sb->local_nls); ++ findParms.EndofSearch = 0; ++ break; ++ } ++ file->f_pos++; ++ } ++ } else { /* UnixSearch */ ++ pfindDataUnix = ++ (FILE_UNIX_INFO *) pfindData; ++ if (Unicode == TRUE) ++ qstring.len = ++ cifs_strfromUCS_le ++ (pfindDataUnix->FileName, ++ (wchar_t *) ++ pfindDataUnix->FileName, ++ MAX_PATHCONF, ++ cifs_sb->local_nls); ++ else ++ qstring.len = ++ strnlen(pfindDataUnix-> ++ FileName, ++ MAX_PATHCONF); ++ if (((qstring.len != 1) ++ || (pfindDataUnix-> ++ FileName[0] != '.')) ++ && ((qstring.len != 2) ++ || (pfindDataUnix-> ++ FileName[0] != '.') ++ || (pfindDataUnix-> ++ FileName[1] != '.'))) { ++ if(cifs_filldir_unix(&qstring, ++ pfindDataUnix, ++ file, ++ filldir, ++ direntry)) { ++ /* do not end search if ++ kernel not ready to take ++ remaining entries yet */ ++ findParms.EndofSearch = 0; ++ reset_resume_key(file, pfindDataUnix->FileName, ++ qstring.len,Unicode,cifs_sb->local_nls); ++ break; ++ } ++ file->f_pos++; ++ } ++ } ++ /* works also for Unix ff struct since first field of both */ ++ pfindData = ++ (FILE_DIRECTORY_INFO *) ((char *) pfindData ++ + le32_to_cpu(pfindData->NextEntryOffset)); ++ /* BB also should check to make sure that pointer is not beyond the end of the SMB */ ++ /* if(pfindData > lastFindData) rc = -EIO; break; */ ++ } /* end for loop */ ++ if ((findParms.EndofSearch != 0) && cifsFile) { ++ cifsFile->endOfSearch = TRUE; ++ if(findParms.SearchCount == 2) ++ cifsFile->emptyDir = TRUE; ++ } ++ } else { ++ if (cifsFile) ++ cifsFile->endOfSearch = TRUE; ++ /* unless parent directory gone do not return error */ ++ rc = 0; ++ } ++ break; ++ default: ++ if (file->private_data == NULL) { ++ rc = -EBADF; ++ cFYI(1, ++ ("Readdir on closed srch, pos = %lld", ++ file->f_pos)); ++ } else { ++ cifsFile = (struct cifsFileInfo *) file->private_data; ++ if (cifsFile->endOfSearch) { ++ rc = 0; ++ cFYI(1, ("End of search ")); ++ break; ++ } ++ searchHandle = cifsFile->netfid; ++ rc = CIFSFindNext(xid, pTcon, pfindData, ++ &findNextParms, searchHandle, ++ cifsFile->search_resume_name, ++ cifsFile->resume_name_length, ++ cifsFile->resume_key, ++ &Unicode, &UnixSearch); ++ cFYI(1,("Count: %d End: %d ", ++ findNextParms.SearchCount, ++ findNextParms.EndofSearch)); ++ if ((rc == 0) && (findNextParms.SearchCount != 0)) { ++ /* BB save off resume key, key name and name length */ ++ lastFindData = ++ (FILE_DIRECTORY_INFO *) ((char *) pfindData ++ + findNextParms.LastNameOffset); ++ if((char *)lastFindData > (char *)pfindData + bufsize) { ++ cFYI(1,("last search entry past end of packet")); ++ rc = -EIO; ++ break; ++ } ++ /* Offset of resume key same for levels 257 and 514 */ ++ cifsFile->resume_key = lastFindData->FileIndex; ++ ++ if(UnixSearch == FALSE) { ++ cifsFile->resume_name_length = ++ le32_to_cpu(lastFindData->FileNameLength); ++ if(cifsFile->resume_name_length > bufsize - 64) { ++ cFYI(1,("Illegal resume file name length %d", ++ cifsFile->resume_name_length)); ++ rc = -ENOMEM; ++ break; ++ } ++ /* Free the memory allocated by previous findfirst ++ or findnext call - we can not reuse the memory since ++ the resume name may not be same string length */ ++ if(cifsFile->search_resume_name) ++ kfree(cifsFile->search_resume_name); ++ cifsFile->search_resume_name = ++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL); ++ cFYI(1,("Last file: %s with name %d bytes long", ++ lastFindData->FileName, ++ cifsFile->resume_name_length)); ++ memcpy(cifsFile->search_resume_name, ++ lastFindData->FileName, ++ cifsFile->resume_name_length); ++ } else { ++ pfindDataUnix = (FILE_UNIX_INFO *)lastFindData; ++ if (Unicode == TRUE) { ++ for(i=0;(pfindDataUnix->FileName[i] ++ | pfindDataUnix->FileName[i+1]); ++ i+=2) { ++ if(i > bufsize-64) ++ break; ++ } ++ cifsFile->resume_name_length = i + 2; ++ } else { ++ cifsFile->resume_name_length = ++ strnlen(pfindDataUnix-> ++ FileName, ++ MAX_PATHCONF); ++ } ++ if(cifsFile->resume_name_length > bufsize - 64) { ++ cFYI(1,("Illegal resume file name length %d", ++ cifsFile->resume_name_length)); ++ rc = -ENOMEM; ++ break; ++ } ++ /* Free the memory allocated by previous findfirst ++ or findnext call - we can not reuse the memory since ++ the resume name may not be same string length */ ++ if(cifsFile->search_resume_name) ++ kfree(cifsFile->search_resume_name); ++ cifsFile->search_resume_name = ++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL); ++ cFYI(1,("fnext last file: %s with name %d bytes long", ++ pfindDataUnix->FileName, ++ cifsFile->resume_name_length)); ++ memcpy(cifsFile->search_resume_name, ++ pfindDataUnix->FileName, ++ cifsFile->resume_name_length); ++ } ++ ++ for (i = 0; i < findNextParms.SearchCount; i++) { ++ pfindData->FileNameLength = ++ le32_to_cpu(pfindData-> ++ FileNameLength); ++ if (UnixSearch == FALSE) { ++ if (Unicode == TRUE) ++ pfindData->FileNameLength = ++ cifs_strfromUCS_le ++ (pfindData->FileName, ++ (wchar_t *) ++ pfindData->FileName, ++ (pfindData->FileNameLength)/ 2, ++ cifs_sb->local_nls); ++ qstring.len = ++ pfindData->FileNameLength; ++ if (((qstring.len != 1) ++ || (pfindData->FileName[0] != '.')) ++ && ((qstring.len != 2) ++ || (pfindData->FileName[0] != '.') ++ || (pfindData->FileName[1] != ++ '.'))) { ++ if(cifs_filldir ++ (&qstring, ++ pfindData, ++ file, filldir, ++ direntry)) { ++ /* do not end search if ++ kernel not ready to take ++ remaining entries yet */ ++ findNextParms.EndofSearch = 0; ++ reset_resume_key(file, pfindData->FileName,qstring.len, ++ Unicode,cifs_sb->local_nls); ++ break; ++ } ++ file->f_pos++; ++ } ++ } else { /* UnixSearch */ ++ pfindDataUnix = ++ (FILE_UNIX_INFO *) ++ pfindData; ++ if (Unicode == TRUE) ++ qstring.len = ++ cifs_strfromUCS_le ++ (pfindDataUnix->FileName, ++ (wchar_t *) ++ pfindDataUnix->FileName, ++ MAX_PATHCONF, ++ cifs_sb->local_nls); ++ else ++ qstring.len = ++ strnlen ++ (pfindDataUnix-> ++ FileName, ++ MAX_PATHCONF); ++ if (((qstring.len != 1) ++ || (pfindDataUnix-> ++ FileName[0] != '.')) ++ && ((qstring.len != 2) ++ || (pfindDataUnix-> ++ FileName[0] != '.') ++ || (pfindDataUnix-> ++ FileName[1] != ++ '.'))) { ++ if(cifs_filldir_unix ++ (&qstring, ++ pfindDataUnix, ++ file, filldir, ++ direntry)) { ++ /* do not end search if ++ kernel not ready to take ++ remaining entries yet */ ++ findNextParms.EndofSearch = 0; ++ reset_resume_key(file, pfindDataUnix->FileName,qstring.len, ++ Unicode,cifs_sb->local_nls); ++ break; ++ } ++ file->f_pos++; ++ } ++ } ++ pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */ ++ /* BB also should check to make sure that pointer is not beyond the end of the SMB */ ++ } /* end for loop */ ++ if (findNextParms.EndofSearch != 0) { ++ cifsFile->endOfSearch = TRUE; ++ } ++ } else { ++ cifsFile->endOfSearch = TRUE; ++ rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */ ++ } ++ } ++ } /* end switch */ ++ if (data) ++ kfree(data); ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ ++ return rc; ++} ++int cifs_prepare_write(struct file *file, struct page *page, ++ unsigned from, unsigned to) ++{ ++ int rc = 0; ++ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT; ++ cFYI(1,("prepare write for page %p from %d to %d",page,from,to)); ++ if (!Page_Uptodate(page)) { ++ /* if (to - from != PAGE_CACHE_SIZE) { ++ void *kaddr = kmap_atomic(page, KM_USER0); ++ memset(kaddr, 0, from); ++ memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); ++ flush_dcache_page(page); ++ kunmap_atomic(kaddr, KM_USER0); ++ } */ ++ /* If we are writing a full page it will be up to date, ++ no need to read from the server */ ++ if((to==PAGE_CACHE_SIZE) && (from == 0)) ++ SetPageUptodate(page); ++ ++ /* might as well read a page, it is fast enough */ ++ if((file->f_flags & O_ACCMODE) != O_WRONLY) { ++ rc = cifs_readpage_worker(file,page,&offset); ++ } else { ++ /* should we try using another ++ file handle if there is one - how would we lock it ++ to prevent close of that handle racing with this read? */ ++ /* In any case this will be written out by commit_write */ ++ } ++ } ++ ++ /* BB should we pass any errors back? e.g. if we do not have read access to the file */ ++ return 0; ++} ++ ++ ++struct address_space_operations cifs_addr_ops = { ++ .readpage = cifs_readpage, ++/* .readpages = cifs_readpages, */ ++ .writepage = cifs_writepage, ++ .prepare_write = cifs_prepare_write, ++ .commit_write = cifs_commit_write, ++ .sync_page = cifs_sync_page, ++ /*.direct_IO = */ ++}; +diff -urN linux-2.4.29.old/fs/cifs/inode.c linux-2.4.29/fs/cifs/inode.c +--- linux-2.4.29.old/fs/cifs/inode.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/inode.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,1079 @@ ++/* ++ * fs/cifs/inode.c ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/fs.h> ++#include <linux/stat.h> ++#include <linux/pagemap.h> ++#include <linux/version.h> ++#include <asm/div64.h> ++#include "cifsfs.h" ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_debug.h" ++#include "cifs_fs_sb.h" ++ ++extern int is_size_safe_to_change(struct cifsInodeInfo *); ++ ++struct inode * get_cifs_inode(struct super_block * sb) ++{ ++ struct inode * newinode; ++ newinode = new_inode(sb); ++ cFYI(1,("got new inode %p",newinode)); ++ if(newinode) { ++ struct cifsInodeInfo * cifsInfo = CIFS_I(newinode); ++ cifsInfo->clientCanCacheRead = FALSE; ++ cifsInfo->clientCanCacheAll = FALSE; ++ INIT_LIST_HEAD(&cifsInfo->openFileList); ++ cifsInfo->cifsAttrs = 0x20; /* default */ ++ newinode->i_blksize = CIFS_MAX_MSGSIZE; ++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15)) ++ newinode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ ++#endif ++ atomic_set(&cifsInfo->inUse, 0); ++ cifsInfo->time = 0; ++ insert_inode_hash(newinode); ++ } ++ return newinode; ++ ++} ++ ++int ++cifs_get_inode_info_unix(struct inode **pinode, ++ const unsigned char *search_path, ++ struct super_block *sb,int xid) ++{ ++ int rc = 0; ++ FILE_UNIX_BASIC_INFO findData; ++ struct cifsTconInfo *pTcon; ++ struct inode *inode; ++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ++ char *tmp_path; ++ ++ pTcon = cifs_sb->tcon; ++ cFYI(1, (" Getting info on %s ", search_path)); ++ /* we could have done a find first instead but this returns more info */ ++ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, ++ cifs_sb->local_nls); ++ /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */ ++ if (rc) { ++ if (rc == -EREMOTE) { ++ tmp_path = ++ kmalloc(strnlen ++ (pTcon->treeName, ++ MAX_TREE_SIZE + 1) + ++ strnlen(search_path, MAX_PATHCONF) + 1, ++ GFP_KERNEL); ++ if (tmp_path == NULL) { ++ return -ENOMEM; ++ } ++ /* have to skip first of the double backslash of UNC name */ ++ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); ++ strncat(tmp_path, search_path, MAX_PATHCONF); ++ rc = connect_to_dfs_path(xid, pTcon->ses, ++ /* treename + */ tmp_path, ++ cifs_sb->local_nls); ++ kfree(tmp_path); ++ ++ /* BB fix up inode etc. */ ++ } else if (rc) { ++ return rc; ++ } ++ ++ } else { ++ struct cifsInodeInfo *cifsInfo; ++ ++ /* get new inode */ ++ if (*pinode == NULL) { ++ *pinode = get_cifs_inode(sb); ++ } ++ if(*pinode == NULL) { ++ return -ENOMEM; ++ } ++ ++ inode = *pinode; ++ cifsInfo = CIFS_I(inode); ++ ++ cFYI(1, (" Old time %ld ", cifsInfo->time)); ++ cifsInfo->time = jiffies; ++ cFYI(1, (" New time %ld ", cifsInfo->time)); ++ atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */ ++ ++ inode->i_atime = ++ cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime)); ++ inode->i_mtime = ++ cifs_NTtimeToUnix(le64_to_cpu ++ (findData.LastModificationTime)); ++ inode->i_ctime = ++ cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); ++ inode->i_mode = le64_to_cpu(findData.Permissions); ++ findData.Type = le32_to_cpu(findData.Type); ++ if (findData.Type == UNIX_FILE) { ++ inode->i_mode |= S_IFREG; ++ } else if (findData.Type == UNIX_SYMLINK) { ++ inode->i_mode |= S_IFLNK; ++ } else if (findData.Type == UNIX_DIR) { ++ inode->i_mode |= S_IFDIR; ++ } else if (findData.Type == UNIX_CHARDEV) { ++ inode->i_mode |= S_IFCHR; ++ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), ++ le64_to_cpu(findData.DevMinor) & MINORMASK); ++ } else if (findData.Type == UNIX_BLOCKDEV) { ++ inode->i_mode |= S_IFBLK; ++ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor), ++ le64_to_cpu(findData.DevMinor) & MINORMASK); ++ } else if (findData.Type == UNIX_FIFO) { ++ inode->i_mode |= S_IFIFO; ++ } else if (findData.Type == UNIX_SOCKET) { ++ inode->i_mode |= S_IFSOCK; ++ } ++ inode->i_uid = le64_to_cpu(findData.Uid); ++ inode->i_gid = le64_to_cpu(findData.Gid); ++ inode->i_nlink = le64_to_cpu(findData.Nlinks); ++ findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes); ++ findData.EndOfFile = le64_to_cpu(findData.EndOfFile); ++ ++ if(is_size_safe_to_change(cifsInfo)) { ++ /* can not safely change the file size here if the ++ client is writing to it due to potential races */ ++ inode->i_size = findData.EndOfFile; ++/* blksize needs to be multiple of two. So safer to default to blksize ++ and blkbits set in superblock so 2**blkbits and blksize will match */ ++/* inode->i_blksize = ++ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ ++ ++ /* This seems incredibly stupid but it turns out that ++ i_blocks is not related to (i_size / i_blksize), instead a ++ size of 512 is required to be used for calculating num blocks */ ++ ++ ++/* inode->i_blocks = ++ (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/ ++ ++ /* 512 bytes (2**9) is the fake blocksize that must be used */ ++ /* for this calculation */ ++ inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9; ++ } ++ ++ if (findData.NumOfBytes < findData.EndOfFile) ++ cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file ")); ++ cFYI(1, ++ ("Size %ld and blocks %ld ", ++ (unsigned long) inode->i_size, inode->i_blocks)); ++ if (S_ISREG(inode->i_mode)) { ++ cFYI(1, (" File inode ")); ++ inode->i_op = &cifs_file_inode_ops; ++ inode->i_fop = &cifs_file_ops; ++ inode->i_data.a_ops = &cifs_addr_ops; ++ } else if (S_ISDIR(inode->i_mode)) { ++ cFYI(1, (" Directory inode")); ++ inode->i_op = &cifs_dir_inode_ops; ++ inode->i_fop = &cifs_dir_ops; ++ } else if (S_ISLNK(inode->i_mode)) { ++ cFYI(1, (" Symbolic Link inode ")); ++ inode->i_op = &cifs_symlink_inode_ops; ++/* tmp_inode->i_fop = *//* do not need to set to anything */ ++ } else { ++ cFYI(1, (" Init special inode ")); ++ init_special_inode(inode, inode->i_mode, ++ kdev_t_to_nr(inode->i_rdev)); ++ } ++ } ++ return rc; ++} ++ ++int ++cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, ++ FILE_ALL_INFO * pfindData, struct super_block *sb, int xid) ++{ ++ int rc = 0; ++ struct cifsTconInfo *pTcon; ++ struct inode *inode; ++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb); ++ char *tmp_path; ++ char *buf = NULL; ++ ++ pTcon = cifs_sb->tcon; ++ cFYI(1,("Getting info on %s ", search_path)); ++ ++ if((pfindData == NULL) && (*pinode != NULL)) { ++ if(CIFS_I(*pinode)->clientCanCacheRead) { ++ cFYI(1,("No need to revalidate inode sizes on cached file ")); ++ return rc; ++ } ++ } ++ ++ /* if file info not passed in then get it from server */ ++ if(pfindData == NULL) { ++ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); ++ pfindData = (FILE_ALL_INFO *)buf; ++ /* could do find first instead but this returns more info */ ++ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, ++ cifs_sb->local_nls); ++ } ++ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ ++ if (rc) { ++ if (rc == -EREMOTE) { ++ tmp_path = ++ kmalloc(strnlen ++ (pTcon->treeName, ++ MAX_TREE_SIZE + 1) + ++ strnlen(search_path, MAX_PATHCONF) + 1, ++ GFP_KERNEL); ++ if (tmp_path == NULL) { ++ if(buf) ++ kfree(buf); ++ return -ENOMEM; ++ } ++ ++ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); ++ strncat(tmp_path, search_path, MAX_PATHCONF); ++ rc = connect_to_dfs_path(xid, pTcon->ses, ++ /* treename + */ tmp_path, ++ cifs_sb->local_nls); ++ kfree(tmp_path); ++ /* BB fix up inode etc. */ ++ } else if (rc) { ++ if(buf) ++ kfree(buf); ++ return rc; ++ } ++ } else { ++ struct cifsInodeInfo *cifsInfo; ++ ++ /* get new inode */ ++ if (*pinode == NULL) { ++ *pinode = get_cifs_inode(sb); ++ } ++ if(*pinode == NULL) ++ return -ENOMEM; ++ inode = *pinode; ++ cifsInfo = CIFS_I(inode); ++ pfindData->Attributes = le32_to_cpu(pfindData->Attributes); ++ cifsInfo->cifsAttrs = pfindData->Attributes; ++ cFYI(1, (" Old time %ld ", cifsInfo->time)); ++ cifsInfo->time = jiffies; ++ cFYI(1, (" New time %ld ", cifsInfo->time)); ++ ++/* blksize needs to be multiple of two. So safer to default to blksize ++ and blkbits set in superblock so 2**blkbits and blksize will match */ ++/* inode->i_blksize = ++ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ ++ ++ /* Linux can not store file creation time unfortunately so we ignore it */ ++ inode->i_atime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); ++ inode->i_mtime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); ++ inode->i_ctime = ++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); ++ cFYI(0, ++ (" Attributes came in as 0x%x ", pfindData->Attributes)); ++ ++ /* set default mode. will override for dirs below */ ++ if(atomic_read(&cifsInfo->inUse) == 0) ++ /* new inode, can safely set these fields */ ++ inode->i_mode = cifs_sb->mnt_file_mode; ++ ++ if (pfindData->Attributes & ATTR_REPARSE) { ++ /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */ ++ inode->i_mode |= S_IFLNK; ++ } else if (pfindData->Attributes & ATTR_DIRECTORY) { ++ /* override default perms since we do not do byte range locking on dirs */ ++ inode->i_mode = cifs_sb->mnt_dir_mode; ++ inode->i_mode |= S_IFDIR; ++ } else { ++ inode->i_mode |= S_IFREG; ++ /* treat the dos attribute of read-only as read-only mode e.g. 555 */ ++ if(cifsInfo->cifsAttrs & ATTR_READONLY) ++ inode->i_mode &= ~(S_IWUGO); ++ /* BB add code here - validate if device or weird share or device type? */ ++ } ++ if(is_size_safe_to_change(cifsInfo)) { ++ /* can not safely change the file size here if the ++ client is writing to it due to potential races */ ++ inode->i_size = le64_to_cpu(pfindData->EndOfFile); ++ ++ /* 512 bytes (2**9) is the fake blocksize that must be used */ ++ /* for this calculation */ ++ inode->i_blocks = (512 - 1 + pfindData->AllocationSize) ++ >> 9; ++ } ++ pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize); ++ ++ cFYI(1, ++ (" Size %ld and blocks %ld ", ++ (unsigned long) inode->i_size, inode->i_blocks)); ++ inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks); ++ ++ /* BB fill in uid and gid here? with help from winbind? ++ or retrieve from NTFS stream extended attribute */ ++ if(atomic_read(&cifsInfo->inUse) == 0) { ++ inode->i_uid = cifs_sb->mnt_uid; ++ inode->i_gid = cifs_sb->mnt_gid; ++ /* set so we do not keep refreshing these fields with ++ bad data after user has changed them in memory */ ++ atomic_set(&cifsInfo->inUse,1); ++ } ++ ++ if (S_ISREG(inode->i_mode)) { ++ cFYI(1, (" File inode ")); ++ inode->i_op = &cifs_file_inode_ops; ++ inode->i_fop = &cifs_file_ops; ++ inode->i_data.a_ops = &cifs_addr_ops; ++ } else if (S_ISDIR(inode->i_mode)) { ++ cFYI(1, (" Directory inode ")); ++ inode->i_op = &cifs_dir_inode_ops; ++ inode->i_fop = &cifs_dir_ops; ++ } else if (S_ISLNK(inode->i_mode)) { ++ cFYI(1, (" Symbolic Link inode ")); ++ inode->i_op = &cifs_symlink_inode_ops; ++ } else { ++ init_special_inode(inode, inode->i_mode, ++ kdev_t_to_nr(inode->i_rdev)); ++ } ++ } ++ if(buf) ++ kfree(buf); ++ return rc; ++} ++ ++void ++cifs_read_inode(struct inode *inode) ++{ /* gets root inode */ ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsInodeInfo *cifs_inode; ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ xid = GetXid(); ++ ++ cifs_inode = CIFS_I(inode); ++ cifs_inode->cifsAttrs = ATTR_DIRECTORY; ++ atomic_set(&cifs_inode->inUse, 0); ++ cifs_inode->time = 0; ++ inode->i_blksize = CIFS_MAX_MSGSIZE; ++ inode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ ++ ++ INIT_LIST_HEAD(&cifs_inode->openFileList); ++ ++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) ++ cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid); ++ else ++ cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid); ++ /* can not call macro FreeXid here since in a void func */ ++ _FreeXid(xid); ++} ++ ++int ++cifs_unlink(struct inode *inode, struct dentry *direntry) ++{ ++ int rc = 0; ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ struct cifsInodeInfo *cifsInode; ++ FILE_BASIC_INFO * pinfo_buf; ++ ++ cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++/* Unlink can be called from rename so we can not grab ++ the sem here since we deadlock otherwise */ ++/* down(&direntry->d_sb->s_vfs_rename_sem);*/ ++ full_path = build_path_from_dentry(direntry); ++/* up(&direntry->d_sb->s_vfs_rename_sem);*/ ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); ++ ++ if (!rc) { ++ direntry->d_inode->i_nlink--; ++ } else if (rc == -ENOENT) { ++ d_drop(direntry); ++ } else if (rc == -ETXTBSY) { ++ int oplock = FALSE; ++ __u16 netfid; ++ ++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, ++ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, ++ &netfid, &oplock, NULL, cifs_sb->local_nls); ++ if(rc==0) { ++ CIFSSMBRenameOpenFile(xid,pTcon,netfid, ++ NULL, cifs_sb->local_nls); ++ CIFSSMBClose(xid, pTcon, netfid); ++ direntry->d_inode->i_nlink--; ++ } ++ } else if (rc == -EACCES) { ++ /* try only if r/o attribute set in local lookup data? */ ++ pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL); ++ if(pinfo_buf) { ++ memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO)); ++ /* ATTRS set to normal clears r/o bit */ ++ pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL); ++ rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf, ++ cifs_sb->local_nls); ++ kfree(pinfo_buf); ++ } ++ if(rc==0) { ++ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls); ++ if (!rc) { ++ direntry->d_inode->i_nlink--; ++ } else if (rc == -ETXTBSY) { ++ int oplock = FALSE; ++ __u16 netfid; ++ ++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE, ++ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE, ++ &netfid, &oplock, NULL, cifs_sb->local_nls); ++ if(rc==0) { ++ CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls); ++ CIFSSMBClose(xid, pTcon, netfid); ++ direntry->d_inode->i_nlink--; ++ } ++ /* BB if rc = -ETXTBUSY goto the rename logic BB */ ++ } ++ } ++ } ++ cifsInode = CIFS_I(direntry->d_inode); ++ cifsInode->time = 0; /* will force revalidate to get info when needed */ ++ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = ++ CURRENT_TIME; ++ cifsInode = CIFS_I(inode); ++ cifsInode->time = 0; /* force revalidate of dir as well */ ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) ++{ ++ int rc = 0; ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ struct inode *newinode = NULL; ++ ++ cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ down(&inode->i_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(direntry); ++ up(&inode->i_sb->s_vfs_rename_sem); ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ /* BB add setting the equivalent of mode via CreateX w/ACLs */ ++ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls); ++ if (rc) { ++ cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); ++ d_drop(direntry); ++ } else { ++ inode->i_nlink++; ++ if (pTcon->ses->capabilities & CAP_UNIX) ++ rc = cifs_get_inode_info_unix(&newinode, full_path, ++ inode->i_sb,xid); ++ else ++ rc = cifs_get_inode_info(&newinode, full_path,NULL, ++ inode->i_sb,xid); ++ ++ direntry->d_op = &cifs_dentry_ops; ++ d_instantiate(direntry, newinode); ++ if(direntry->d_inode) ++ direntry->d_inode->i_nlink = 2; ++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) ++ CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, ++ (__u64)-1, ++ (__u64)-1, ++ 0 /* dev_t */, ++ cifs_sb->local_nls); ++ else { /* BB to be implemented via Windows secrty descriptors*/ ++ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ ++ } ++ } ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ ++ return rc; ++} ++ ++int ++cifs_rmdir(struct inode *inode, struct dentry *direntry) ++{ ++ int rc = 0; ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ struct cifsInodeInfo *cifsInode; ++ ++ cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ down(&inode->i_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(direntry); ++ up(&inode->i_sb->s_vfs_rename_sem); ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ ++ rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls); ++ ++ if (!rc) { ++ inode->i_nlink--; ++ direntry->d_inode->i_size = 0; ++ direntry->d_inode->i_nlink = 0; ++ } ++ ++ cifsInode = CIFS_I(direntry->d_inode); ++ cifsInode->time = 0; /* force revalidate to go get info when needed */ ++ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = ++ CURRENT_TIME; ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_rename(struct inode *source_inode, struct dentry *source_direntry, ++ struct inode *target_inode, struct dentry *target_direntry) ++{ ++ char *fromName; ++ char *toName; ++ struct cifs_sb_info *cifs_sb_source; ++ struct cifs_sb_info *cifs_sb_target; ++ struct cifsTconInfo *pTcon; ++ int xid; ++ int rc = 0; ++ ++ xid = GetXid(); ++ ++ cifs_sb_target = CIFS_SB(target_inode->i_sb); ++ cifs_sb_source = CIFS_SB(source_inode->i_sb); ++ pTcon = cifs_sb_source->tcon; ++ ++ if (pTcon != cifs_sb_target->tcon) { ++ FreeXid(xid); ++ return -EXDEV; /* BB actually could be allowed if same server, but ++ different share. Might eventually add support for this */ ++ } ++ ++ /* we already have the rename sem so we do not need ++ to grab it again here to protect the path integrity */ ++ fromName = build_path_from_dentry(source_direntry); ++ toName = build_path_from_dentry(target_direntry); ++ if((fromName == NULL) || (toName == NULL)) { ++ rc = -ENOMEM; ++ goto cifs_rename_exit; ++ } ++ ++ rc = CIFSSMBRename(xid, pTcon, fromName, toName, ++ cifs_sb_source->local_nls); ++ if(rc == -EEXIST) { ++ /* check if they are the same file ++ because rename of hardlinked files is a noop */ ++ FILE_UNIX_BASIC_INFO * info_buf_source; ++ FILE_UNIX_BASIC_INFO * info_buf_target; ++ ++ info_buf_source = ++ kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL); ++ if(info_buf_source != NULL) { ++ info_buf_target = info_buf_source+1; ++ rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName, ++ info_buf_source, cifs_sb_source->local_nls); ++ if(rc == 0) { ++ rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName, ++ info_buf_target, ++ cifs_sb_target->local_nls); ++ } ++ if((rc == 0) && ++ (info_buf_source->UniqueId == ++ info_buf_target->UniqueId)) { ++ /* do not rename since the files are hardlinked ++ which is a noop */ ++ } else { ++ /* we either can not tell the files are hardlinked ++ (as with Windows servers) or files are not hardlinked ++ so delete the target manually before renaming to ++ follow POSIX rather than Windows semantics */ ++ cifs_unlink(target_inode, target_direntry); ++ rc = CIFSSMBRename(xid, pTcon, fromName, toName, ++ cifs_sb_source->local_nls); ++ } ++ kfree(info_buf_source); ++ } /* if we can not get memory just leave rc as EEXIST */ ++ } ++ ++ if((rc == -EIO)||(rc == -EEXIST)) { ++ int oplock = FALSE; ++ __u16 netfid; ++ ++ rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ, ++ CREATE_NOT_DIR, ++ &netfid, &oplock, NULL, cifs_sb_source->local_nls); ++ if(rc==0) { ++ CIFSSMBRenameOpenFile(xid,pTcon,netfid, ++ toName, cifs_sb_source->local_nls); ++ CIFSSMBClose(xid, pTcon, netfid); ++ } ++ } ++ ++cifs_rename_exit: ++ if (fromName) ++ kfree(fromName); ++ if (toName) ++ kfree(toName); ++ ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_revalidate(struct dentry *direntry) ++{ ++ int xid; ++ int rc = 0; ++ char *full_path; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsInodeInfo *cifsInode; ++ loff_t local_size; ++ time_t local_mtime; ++ int invalidate_inode = FALSE; ++ ++ if(direntry->d_inode == NULL) ++ return -ENOENT; ++ ++ cifsInode = CIFS_I(direntry->d_inode); ++ ++ if(cifsInode == NULL) ++ return -ENOENT; ++ ++ /* no sense revalidating inode info on file that no one can write */ ++ if(CIFS_I(direntry->d_inode)->clientCanCacheRead) ++ return rc; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(direntry->d_sb); ++ ++ /* can not safely grab the rename sem here if ++ rename calls revalidate since that would deadlock */ ++ full_path = build_path_from_dentry(direntry); ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ cFYI(1, ++ ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld", ++ full_path, direntry->d_inode, ++ direntry->d_inode->i_count.counter, direntry, ++ direntry->d_time, jiffies)); ++ ++ if (cifsInode->time == 0){ ++ /* was set to zero previously to force revalidate */ ++ } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) { ++ if((S_ISREG(direntry->d_inode->i_mode) == 0) || ++ (direntry->d_inode->i_nlink == 1)) { ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++ } else { ++ cFYI(1,("Have to revalidate file due to hardlinks")); ++ } ++ } ++ ++ /* save mtime and size */ ++ local_mtime = direntry->d_inode->i_mtime; ++ local_size = direntry->d_inode->i_size; ++ ++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) { ++ rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path, ++ direntry->d_sb,xid); ++ if(rc) { ++ cFYI(1,("error on getting revalidate info %d",rc)); ++/* if(rc != -ENOENT) ++ rc = 0; */ /* BB should we cache info on certain errors? */ ++ } ++ } else { ++ rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL, ++ direntry->d_sb,xid); ++ if(rc) { ++ cFYI(1,("error on getting revalidate info %d",rc)); ++/* if(rc != -ENOENT) ++ rc = 0; */ /* BB should we cache info on certain errors? */ ++ } ++ } ++ /* should we remap certain errors, access denied?, to zero */ ++ ++ /* if not oplocked, we invalidate inode pages if mtime ++ or file size had changed on server */ ++ ++ if((local_mtime == direntry->d_inode->i_mtime) && ++ (local_size == direntry->d_inode->i_size)) { ++ cFYI(1,("cifs_revalidate - inode unchanged")); ++ } else { ++ /* file may have changed on server */ ++ if(cifsInode->clientCanCacheRead) { ++ /* no need to invalidate inode pages since we were ++ the only ones who could have modified the file and ++ the server copy is staler than ours */ ++ } else { ++ invalidate_inode = TRUE; ++ } ++ } ++ ++ /* can not grab this sem since kernel filesys locking ++ documentation indicates i_sem may be taken by the kernel ++ on lookup and rename which could deadlock if we grab ++ the i_sem here as well */ ++/* down(&direntry->d_inode->i_sem);*/ ++ /* need to write out dirty pages here */ ++ if(direntry->d_inode->i_mapping) { ++ /* do we need to lock inode until after invalidate completes below? */ ++ filemap_fdatasync(direntry->d_inode->i_mapping); ++ } ++ if(invalidate_inode) { ++ filemap_fdatawait(direntry->d_inode->i_mapping); ++ /* may eventually have to do this for open files too */ ++ if(list_empty(&(cifsInode->openFileList))) { ++ /* Has changed on server - flush read ahead pages */ ++ cFYI(1,("Invalidating read ahead data on closed file")); ++ invalidate_inode_pages(direntry->d_inode); ++ } ++ } ++/* up(&direntry->d_inode->i_sem);*/ ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ ++ return rc; ++} ++ ++/* int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) ++{ ++ int err = cifs_revalidate(dentry); ++ if (!err) ++ generic_fillattr(dentry->d_inode, stat); ++ return err; ++} */ ++ ++void ++cifs_truncate_file(struct inode *inode) ++{ /* BB remove - may not need this function after all BB */ ++ int xid; ++ int rc = -EIO; ++ int found = FALSE; ++ struct cifsFileInfo *open_file = NULL; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ struct cifsInodeInfo *cifsInode; ++ struct dentry *dirent; ++ struct list_head * tmp; ++ char *full_path = NULL; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ /* To avoid spurious oplock breaks from server, in the case ++ of inodes that we already have open, avoid doing path ++ based setting of file size if we can do it by handle. ++ This keeps our caching token (oplock) and avoids ++ timeouts when the local oplock break takes longer to flush ++ writebehind data than the SMB timeout for the SetPathInfo ++ request would allow */ ++ read_lock(&GlobalSMBSeslock); ++ cifsInode = CIFS_I(inode); ++ list_for_each(tmp, &cifsInode->openFileList) { ++ open_file = list_entry(tmp,struct cifsFileInfo, flist); ++ /* We check if file is open for writing first */ ++ if((open_file->pfile) && (!open_file->invalidHandle) && ++ ((open_file->pfile->f_flags & O_RDWR) || ++ (open_file->pfile->f_flags & O_WRONLY))) { ++ read_unlock(&GlobalSMBSeslock); ++ found = TRUE; ++ rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size, ++ open_file->netfid,open_file->pid,FALSE); ++ if(rc == 0) { ++ FreeXid(xid); ++ return; ++ } ++ /* Do not need reopen and retry on EAGAIN since we will ++ retry by pathname below */ ++ if(rc == -EAGAIN) ++ rc = -EHOSTDOWN; ++ ++ break; /* now that we found one valid file handle no ++ sense continuing to loop trying others */ ++ } ++ } ++ if(found == FALSE) ++ read_unlock(&GlobalSMBSeslock); ++ ++ if (list_empty(&inode->i_dentry)) { ++ cERROR(1, ++ ("Can not get pathname from empty dentry in inode 0x%p ", ++ inode)); ++ FreeXid(xid); ++ return; ++ } ++ ++ dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias); ++ if (dirent) { ++ full_path = build_path_from_dentry(dirent); ++ rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE, ++ cifs_sb->local_nls); ++ cFYI(1,(" SetEOF (truncate) rc = %d",rc)); ++ if (!rc) ++ CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls); ++ /* allocation size setting seems optional so ignore return code */ ++ } ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return; ++} ++ ++static int cifs_truncate_page(struct address_space *mapping, loff_t from) ++{ ++ unsigned long index = from >> PAGE_CACHE_SHIFT; ++ unsigned offset = from & (PAGE_CACHE_SIZE-1); ++ struct page *page; ++ char *kaddr; ++ int rc = 0; ++ ++ page = grab_cache_page(mapping, index); ++ if (!page) ++ return -ENOMEM; ++ ++ kaddr = kmap_atomic(page, KM_USER0); ++ memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); ++ flush_dcache_page(page); ++ kunmap_atomic(kaddr, KM_USER0); ++ unlock_page(page); ++ page_cache_release(page); ++ return rc; ++} ++ ++int ++cifs_setattr(struct dentry *direntry, struct iattr *attrs) ++{ ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ int rc = -EACCES; ++ int found = FALSE; ++ struct cifsFileInfo *open_file = NULL; ++ FILE_BASIC_INFO time_buf; ++ int set_time = FALSE; ++ __u64 mode = 0xFFFFFFFFFFFFFFFFULL; ++ __u64 uid = 0xFFFFFFFFFFFFFFFFULL; ++ __u64 gid = 0xFFFFFFFFFFFFFFFFULL; ++ struct cifsInodeInfo *cifsInode; ++ struct list_head * tmp; ++ ++ xid = GetXid(); ++ ++ cFYI(1, ++ (" In cifs_setattr, name = %s attrs->iavalid 0x%x ", ++ direntry->d_name.name, attrs->ia_valid)); ++ cifs_sb = CIFS_SB(direntry->d_inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ down(&direntry->d_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(direntry); ++ up(&direntry->d_sb->s_vfs_rename_sem); ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ cifsInode = CIFS_I(direntry->d_inode); ++ ++ /* BB check if we need to refresh inode from server now ? BB */ ++ ++ /* need to flush data before changing file size on server */ ++ filemap_fdatasync(direntry->d_inode->i_mapping); ++ ++ if (attrs->ia_valid & ATTR_SIZE) { ++ read_lock(&GlobalSMBSeslock); ++ /* To avoid spurious oplock breaks from server, in the case ++ of inodes that we already have open, avoid doing path ++ based setting of file size if we can do it by handle. ++ This keeps our caching token (oplock) and avoids ++ timeouts when the local oplock break takes longer to flush ++ writebehind data than the SMB timeout for the SetPathInfo ++ request would allow */ ++ list_for_each(tmp, &cifsInode->openFileList) { ++ open_file = list_entry(tmp,struct cifsFileInfo, flist); ++ /* We check if file is open for writing first */ ++ if((open_file->pfile) && ++ ((open_file->pfile->f_flags & O_RDWR) || ++ (open_file->pfile->f_flags & O_WRONLY))) { ++ if(open_file->invalidHandle == FALSE) { ++ /* we found a valid, writeable network file ++ handle to use to try to set the file size */ ++ __u16 nfid = open_file->netfid; ++ __u32 npid = open_file->pid; ++ read_unlock(&GlobalSMBSeslock); ++ found = TRUE; ++ rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, ++ nfid,npid,FALSE); ++ cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc)); ++ /* Do not need reopen and retry on EAGAIN since we will ++ retry by pathname below */ ++ ++ break; /* now that we found one valid file handle no ++ sense continuing to loop trying others */ ++ } ++ } ++ } ++ if(found == FALSE) { ++ read_unlock(&GlobalSMBSeslock); ++ } ++ ++ ++ if(rc != 0) { ++ /* Set file size by pathname rather than by handle either ++ because no valid, writeable file handle for it was found or ++ because there was an error setting it by handle */ ++ rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE, ++ cifs_sb->local_nls); ++ cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc)); ++ } ++ ++ /* Server is ok setting allocation size implicitly - no need to call: */ ++ /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/ ++ ++ if (rc == 0) { ++ rc = vmtruncate(direntry->d_inode, attrs->ia_size); ++ cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size); ++ } ++ } ++ if (attrs->ia_valid & ATTR_UID) { ++ cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); ++ uid = attrs->ia_uid; ++ /* entry->uid = cpu_to_le16(attr->ia_uid); */ ++ } ++ if (attrs->ia_valid & ATTR_GID) { ++ cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); ++ gid = attrs->ia_gid; ++ /* entry->gid = cpu_to_le16(attr->ia_gid); */ ++ } ++ ++ time_buf.Attributes = 0; ++ if (attrs->ia_valid & ATTR_MODE) { ++ cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); ++ mode = attrs->ia_mode; ++ /* entry->mode = cpu_to_le16(attr->ia_mode); */ ++ } ++ ++ if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) ++ && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID))) ++ rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid, ++ 0 /* dev_t */, cifs_sb->local_nls); ++ else if (attrs->ia_valid & ATTR_MODE) { ++ if((mode & S_IWUGO) == 0) /* not writeable */ { ++ if((cifsInode->cifsAttrs & ATTR_READONLY) == 0) ++ time_buf.Attributes = ++ cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY); ++ } else if((mode & S_IWUGO) == S_IWUGO) { ++ if(cifsInode->cifsAttrs & ATTR_READONLY) ++ time_buf.Attributes = ++ cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY)); ++ } ++ /* BB to be implemented - via Windows security descriptors or streams */ ++ /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/ ++ } ++ ++ if (attrs->ia_valid & ATTR_ATIME) { ++ set_time = TRUE; ++ time_buf.LastAccessTime = ++ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime)); ++ } else ++ time_buf.LastAccessTime = 0; ++ ++ if (attrs->ia_valid & ATTR_MTIME) { ++ set_time = TRUE; ++ time_buf.LastWriteTime = ++ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); ++ } else ++ time_buf.LastWriteTime = 0; ++ ++ if (attrs->ia_valid & ATTR_CTIME) { ++ set_time = TRUE; ++ time_buf.ChangeTime = ++ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); ++ } else ++ time_buf.ChangeTime = 0; ++ ++ if (set_time | time_buf.Attributes) { ++ /* BB what if setting one attribute fails ++ (such as size) but time setting works */ ++ time_buf.CreationTime = 0; /* do not change */ ++ /* In the future we should experiment - try setting timestamps ++ via Handle (SetFileInfo) instead of by path */ ++ rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf, ++ cifs_sb->local_nls); ++ } ++ ++ /* do not need local check to inode_check_ok since the server does that */ ++ if (!rc) ++ rc = inode_setattr(direntry->d_inode, attrs); ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++void ++cifs_delete_inode(struct inode *inode) ++{ ++ cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); ++ /* may have to add back in if and when safe distributed caching of ++ directories added e.g. via FindNotify */ ++} +diff -urN linux-2.4.29.old/fs/cifs/link.c linux-2.4.29/fs/cifs/link.c +--- linux-2.4.29.old/fs/cifs/link.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/link.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,328 @@ ++/* ++ * fs/cifs/link.c ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++#include <linux/fs.h> ++#include <linux/stat.h> ++#include "cifsfs.h" ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_debug.h" ++#include "cifs_fs_sb.h" ++ ++int ++cifs_hardlink(struct dentry *old_file, struct inode *inode, ++ struct dentry *direntry) ++{ ++ int rc = -EACCES; ++ int xid; ++ char *fromName = NULL; ++ char *toName = NULL; ++ struct cifs_sb_info *cifs_sb_target; ++ struct cifsTconInfo *pTcon; ++ struct cifsInodeInfo *cifsInode; ++ ++ xid = GetXid(); ++ ++ cifs_sb_target = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb_target->tcon; ++ ++/* No need to check for cross device links since server will do that ++ BB note DFS case in future though (when we may have to check) */ ++ ++ down(&inode->i_sb->s_vfs_rename_sem); ++ fromName = build_path_from_dentry(old_file); ++ toName = build_path_from_dentry(direntry); ++ up(&inode->i_sb->s_vfs_rename_sem); ++ if((fromName == NULL) || (toName == NULL)) { ++ rc = -ENOMEM; ++ goto cifs_hl_exit; ++ } ++ ++ if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX) ++ rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName, ++ cifs_sb_target->local_nls); ++ else { ++ rc = CIFSCreateHardLink(xid, pTcon, fromName, toName, ++ cifs_sb_target->local_nls); ++ if(rc == -EIO) ++ rc = -EOPNOTSUPP; ++ } ++ ++/* if (!rc) */ ++ { ++ /* renew_parental_timestamps(old_file); ++ inode->i_nlink++; ++ mark_inode_dirty(inode); ++ d_instantiate(direntry, inode); */ ++ /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */ ++ } ++ d_drop(direntry); /* force new lookup from server */ ++ cifsInode = CIFS_I(old_file->d_inode); ++ cifsInode->time = 0; /* will force revalidate to go get info when needed */ ++ ++cifs_hl_exit: ++ if (fromName) ++ kfree(fromName); ++ if (toName) ++ kfree(toName); ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_follow_link(struct dentry *direntry, struct nameidata *nd) ++{ ++ struct inode *inode = direntry->d_inode; ++ int rc = -EACCES; ++ int xid; ++ char *full_path = NULL; ++ char * target_path; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ ++ xid = GetXid(); ++ ++ down(&direntry->d_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(direntry); ++ up(&direntry->d_sb->s_vfs_rename_sem); ++ ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode)); ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ target_path = kmalloc(PATH_MAX, GFP_KERNEL); ++ if(target_path == NULL) { ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */ ++ /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */ ++ ++/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ ++ if (pTcon->ses->capabilities & CAP_UNIX) ++ rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, ++ target_path, ++ PATH_MAX-1, ++ cifs_sb->local_nls); ++ else { ++ /* rc = CIFSSMBQueryReparseLinkInfo */ ++ /* BB Add code to Query ReparsePoint info */ ++ } ++ /* BB Anything else to do to handle recursive links? */ ++ /* BB Should we be using page symlink ops here? */ ++ ++ if (rc == 0) { ++ ++/* BB Add special case check for Samba DFS symlinks */ ++ ++ target_path[PATH_MAX-1] = 0; ++ rc = vfs_follow_link(nd, target_path); ++ } ++ /* else EACCESS */ ++ ++ if (target_path) ++ kfree(target_path); ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) ++{ ++ int rc = -EOPNOTSUPP; ++ int xid; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ struct inode *newinode = NULL; ++ ++ xid = GetXid(); ++ ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++ down(&inode->i_sb->s_vfs_rename_sem); ++ full_path = build_path_from_dentry(direntry); ++ up(&inode->i_sb->s_vfs_rename_sem); ++ ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ ++ cFYI(1, ("Full path: %s ", full_path)); ++ cFYI(1, ("symname is %s", symname)); ++ ++ /* BB what if DFS and this volume is on different share? BB */ ++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) ++ rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname, ++ cifs_sb->local_nls); ++ /* else ++ rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */ ++ ++ if (rc == 0) { ++ if (pTcon->ses->capabilities & CAP_UNIX) ++ rc = cifs_get_inode_info_unix(&newinode, full_path, ++ inode->i_sb,xid); ++ else ++ rc = cifs_get_inode_info(&newinode, full_path, NULL, ++ inode->i_sb,xid); ++ ++ if (rc != 0) { ++ cFYI(1, ++ ("Create symlink worked but get_inode_info failed with rc = %d ", ++ rc)); ++ } else { ++ direntry->d_op = &cifs_dentry_ops; ++ d_instantiate(direntry, newinode); ++ } ++ } ++ ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return rc; ++} ++ ++int ++cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen) ++{ ++ struct inode *inode = direntry->d_inode; ++ int rc = -EACCES; ++ int xid; ++ int oplock = FALSE; ++ struct cifs_sb_info *cifs_sb; ++ struct cifsTconInfo *pTcon; ++ char *full_path = NULL; ++ char *tmp_path = NULL; ++ char * tmpbuffer; ++ unsigned char * referrals = NULL; ++ int num_referrals = 0; ++ int len; ++ __u16 fid; ++ ++ xid = GetXid(); ++ cifs_sb = CIFS_SB(inode->i_sb); ++ pTcon = cifs_sb->tcon; ++ ++/* BB would it be safe against deadlock to grab this sem ++ even though rename itself grabs the sem and calls lookup? */ ++/* down(&inode->i_sb->s_vfs_rename_sem);*/ ++ full_path = build_path_from_dentry(direntry); ++/* up(&inode->i_sb->s_vfs_rename_sem);*/ ++ ++ if(full_path == NULL) { ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ ++ cFYI(1, ++ ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d", ++ full_path, inode, pBuffer, buflen)); ++ if(buflen > PATH_MAX) ++ len = PATH_MAX; ++ else ++ len = buflen; ++ tmpbuffer = kmalloc(len,GFP_KERNEL); ++ if(tmpbuffer == NULL) { ++ if (full_path) ++ kfree(full_path); ++ FreeXid(xid); ++ return -ENOMEM; ++ } ++ ++/* BB add read reparse point symlink code and Unix extensions symlink code here BB */ ++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) ++ rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path, ++ tmpbuffer, ++ len - 1, ++ cifs_sb->local_nls); ++ else { ++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, ++ OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls); ++ if(!rc) { ++ rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path, ++ tmpbuffer, ++ len - 1, ++ fid, ++ cifs_sb->local_nls); ++ if(CIFSSMBClose(xid, pTcon, fid)) { ++ cFYI(1,("Error closing junction point (open for ioctl)")); ++ } ++ if(rc == -EIO) { ++ /* Query if DFS Junction */ ++ tmp_path = ++ kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1, ++ GFP_KERNEL); ++ if (tmp_path) { ++ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE); ++ strncat(tmp_path, full_path, MAX_PATHCONF); ++ rc = get_dfs_path(xid, pTcon->ses, tmp_path, ++ cifs_sb->local_nls, &num_referrals, &referrals); ++ cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc)); ++ if((num_referrals == 0) && (rc == 0)) ++ rc = -EACCES; ++ else { ++ cFYI(1,("num referral: %d",num_referrals)); ++ if(referrals) { ++ cFYI(1,("referral string: %s ",referrals)); ++ strncpy(tmpbuffer, referrals, len-1); ++ } ++ } ++ if(referrals) ++ kfree(referrals); ++ kfree(tmp_path); ++ if(referrals) { ++ kfree(referrals); ++ } ++ } ++ /* BB add code like else decode referrals then memcpy to ++ tmpbuffer and free referrals string array BB */ ++ } ++ } ++ } ++ /* BB Anything else to do to handle recursive links? */ ++ /* BB Should we be using page ops here? */ ++ ++ /* BB null terminate returned string in pBuffer? BB */ ++ if (rc == 0) { ++ rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer); ++ cFYI(1, ++ ("vfs_readlink called from cifs_readlink returned %d", ++ rc)); ++ } ++ ++ if (tmpbuffer) { ++ kfree(tmpbuffer); ++ } ++ if (full_path) { ++ kfree(full_path); ++ } ++ FreeXid(xid); ++ return rc; ++} +diff -urN linux-2.4.29.old/fs/cifs/Makefile linux-2.4.29/fs/cifs/Makefile +--- linux-2.4.29.old/fs/cifs/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/Makefile 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,10 @@ ++# ++# Makefile for Linux CIFS VFS client ++# ++O_TARGET := cifs.o ++ ++obj-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o cifsencrypt.o ++ ++obj-m := $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +diff -urN linux-2.4.29.old/fs/cifs/md4.c linux-2.4.29/fs/cifs/md4.c +--- linux-2.4.29.old/fs/cifs/md4.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/md4.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,203 @@ ++/* ++ Unix SMB/Netbios implementation. ++ Version 1.9. ++ a implementation of MD4 designed for use in the SMB authentication protocol ++ Copyright (C) Andrew Tridgell 1997-1998. ++ Modified by Steve French (sfrench@us.ibm.com) 2002-2003 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++#include <linux/module.h> ++#include <linux/fs.h> ++/* NOTE: This code makes no attempt to be fast! */ ++ ++static __u32 ++F(__u32 X, __u32 Y, __u32 Z) ++{ ++ return (X & Y) | ((~X) & Z); ++} ++ ++static __u32 ++G(__u32 X, __u32 Y, __u32 Z) ++{ ++ return (X & Y) | (X & Z) | (Y & Z); ++} ++ ++static __u32 ++H(__u32 X, __u32 Y, __u32 Z) ++{ ++ return X ^ Y ^ Z; ++} ++ ++static __u32 ++lshift(__u32 x, int s) ++{ ++ x &= 0xFFFFFFFF; ++ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); ++} ++ ++#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s) ++#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s) ++#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s) ++ ++/* this applies md4 to 64 byte chunks */ ++static void ++mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D) ++{ ++ int j; ++ __u32 AA, BB, CC, DD; ++ __u32 X[16]; ++ ++ ++ for (j = 0; j < 16; j++) ++ X[j] = M[j]; ++ ++ AA = *A; ++ BB = *B; ++ CC = *C; ++ DD = *D; ++ ++ ROUND1(A, B, C, D, 0, 3); ++ ROUND1(D, A, B, C, 1, 7); ++ ROUND1(C, D, A, B, 2, 11); ++ ROUND1(B, C, D, A, 3, 19); ++ ROUND1(A, B, C, D, 4, 3); ++ ROUND1(D, A, B, C, 5, 7); ++ ROUND1(C, D, A, B, 6, 11); ++ ROUND1(B, C, D, A, 7, 19); ++ ROUND1(A, B, C, D, 8, 3); ++ ROUND1(D, A, B, C, 9, 7); ++ ROUND1(C, D, A, B, 10, 11); ++ ROUND1(B, C, D, A, 11, 19); ++ ROUND1(A, B, C, D, 12, 3); ++ ROUND1(D, A, B, C, 13, 7); ++ ROUND1(C, D, A, B, 14, 11); ++ ROUND1(B, C, D, A, 15, 19); ++ ++ ROUND2(A, B, C, D, 0, 3); ++ ROUND2(D, A, B, C, 4, 5); ++ ROUND2(C, D, A, B, 8, 9); ++ ROUND2(B, C, D, A, 12, 13); ++ ROUND2(A, B, C, D, 1, 3); ++ ROUND2(D, A, B, C, 5, 5); ++ ROUND2(C, D, A, B, 9, 9); ++ ROUND2(B, C, D, A, 13, 13); ++ ROUND2(A, B, C, D, 2, 3); ++ ROUND2(D, A, B, C, 6, 5); ++ ROUND2(C, D, A, B, 10, 9); ++ ROUND2(B, C, D, A, 14, 13); ++ ROUND2(A, B, C, D, 3, 3); ++ ROUND2(D, A, B, C, 7, 5); ++ ROUND2(C, D, A, B, 11, 9); ++ ROUND2(B, C, D, A, 15, 13); ++ ++ ROUND3(A, B, C, D, 0, 3); ++ ROUND3(D, A, B, C, 8, 9); ++ ROUND3(C, D, A, B, 4, 11); ++ ROUND3(B, C, D, A, 12, 15); ++ ROUND3(A, B, C, D, 2, 3); ++ ROUND3(D, A, B, C, 10, 9); ++ ROUND3(C, D, A, B, 6, 11); ++ ROUND3(B, C, D, A, 14, 15); ++ ROUND3(A, B, C, D, 1, 3); ++ ROUND3(D, A, B, C, 9, 9); ++ ROUND3(C, D, A, B, 5, 11); ++ ROUND3(B, C, D, A, 13, 15); ++ ROUND3(A, B, C, D, 3, 3); ++ ROUND3(D, A, B, C, 11, 9); ++ ROUND3(C, D, A, B, 7, 11); ++ ROUND3(B, C, D, A, 15, 15); ++ ++ *A += AA; ++ *B += BB; ++ *C += CC; ++ *D += DD; ++ ++ *A &= 0xFFFFFFFF; ++ *B &= 0xFFFFFFFF; ++ *C &= 0xFFFFFFFF; ++ *D &= 0xFFFFFFFF; ++ ++ for (j = 0; j < 16; j++) ++ X[j] = 0; ++} ++ ++static void ++copy64(__u32 * M, unsigned char *in) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) ++ M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) | ++ (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0); ++} ++ ++static void ++copy4(unsigned char *out, __u32 x) ++{ ++ out[0] = x & 0xFF; ++ out[1] = (x >> 8) & 0xFF; ++ out[2] = (x >> 16) & 0xFF; ++ out[3] = (x >> 24) & 0xFF; ++} ++ ++/* produce a md4 message digest from data of length n bytes */ ++void ++mdfour(unsigned char *out, unsigned char *in, int n) ++{ ++ unsigned char buf[128]; ++ __u32 M[16]; ++ __u32 b = n * 8; ++ int i; ++ __u32 A = 0x67452301; ++ __u32 B = 0xefcdab89; ++ __u32 C = 0x98badcfe; ++ __u32 D = 0x10325476; ++ ++ while (n > 64) { ++ copy64(M, in); ++ mdfour64(M,&A,&B, &C, &D); ++ in += 64; ++ n -= 64; ++ } ++ ++ for (i = 0; i < 128; i++) ++ buf[i] = 0; ++ memcpy(buf, in, n); ++ buf[n] = 0x80; ++ ++ if (n <= 55) { ++ copy4(buf + 56, b); ++ copy64(M, buf); ++ mdfour64(M, &A, &B, &C, &D); ++ } else { ++ copy4(buf + 120, b); ++ copy64(M, buf); ++ mdfour64(M, &A, &B, &C, &D); ++ copy64(M, buf + 64); ++ mdfour64(M, &A, &B, &C, &D); ++ } ++ ++ for (i = 0; i < 128; i++) ++ buf[i] = 0; ++ copy64(M, buf); ++ ++ copy4(out, A); ++ copy4(out + 4, B); ++ copy4(out + 8, C); ++ copy4(out + 12, D); ++ ++ A = B = C = D = 0; ++} +diff -urN linux-2.4.29.old/fs/cifs/md5.c linux-2.4.29/fs/cifs/md5.c +--- linux-2.4.29.old/fs/cifs/md5.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/md5.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,363 @@ ++/* ++ * This code implements the MD5 message-digest algorithm. ++ * The algorithm is due to Ron Rivest. This code was ++ * written by Colin Plumb in 1993, no copyright is claimed. ++ * This code is in the public domain; do with it what you wish. ++ * ++ * Equivalent code is available from RSA Data Security, Inc. ++ * This code has been tested against that, and is equivalent, ++ * except that you don't need to include two pages of legalese ++ * with every copy. ++ * ++ * To compute the message digest of a chunk of bytes, declare an ++ * MD5Context structure, pass it to MD5Init, call MD5Update as ++ * needed on buffers full of bytes, and then call MD5Final, which ++ * will fill a supplied 16-byte array with the digest. ++ */ ++ ++/* This code slightly modified to fit into Samba by ++ abartlet@samba.org Jun 2001 ++ and to fit the cifs vfs by ++ Steve French sfrench@us.ibm.com */ ++ ++#include <linux/string.h> ++#include "md5.h" ++ ++static void MD5Transform(__u32 buf[4], __u32 const in[16]); ++ ++/* ++ * Note: this code is harmless on little-endian machines. ++ */ ++static void ++byteReverse(unsigned char *buf, unsigned longs) ++{ ++ __u32 t; ++ do { ++ t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ++ ((unsigned) buf[1] << 8 | buf[0]); ++ *(__u32 *) buf = t; ++ buf += 4; ++ } while (--longs); ++} ++ ++/* ++ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious ++ * initialization constants. ++ */ ++void ++MD5Init(struct MD5Context *ctx) ++{ ++ ctx->buf[0] = 0x67452301; ++ ctx->buf[1] = 0xefcdab89; ++ ctx->buf[2] = 0x98badcfe; ++ ctx->buf[3] = 0x10325476; ++ ++ ctx->bits[0] = 0; ++ ctx->bits[1] = 0; ++} ++ ++/* ++ * Update context to reflect the concatenation of another buffer full ++ * of bytes. ++ */ ++void ++MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len) ++{ ++ register __u32 t; ++ ++ /* Update bitcount */ ++ ++ t = ctx->bits[0]; ++ if ((ctx->bits[0] = t + ((__u32) len << 3)) < t) ++ ctx->bits[1]++; /* Carry from low to high */ ++ ctx->bits[1] += len >> 29; ++ ++ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ ++ ++ /* Handle any leading odd-sized chunks */ ++ ++ if (t) { ++ unsigned char *p = (unsigned char *) ctx->in + t; ++ ++ t = 64 - t; ++ if (len < t) { ++ memmove(p, buf, len); ++ return; ++ } ++ memmove(p, buf, t); ++ byteReverse(ctx->in, 16); ++ MD5Transform(ctx->buf, (__u32 *) ctx->in); ++ buf += t; ++ len -= t; ++ } ++ /* Process data in 64-byte chunks */ ++ ++ while (len >= 64) { ++ memmove(ctx->in, buf, 64); ++ byteReverse(ctx->in, 16); ++ MD5Transform(ctx->buf, (__u32 *) ctx->in); ++ buf += 64; ++ len -= 64; ++ } ++ ++ /* Handle any remaining bytes of data. */ ++ ++ memmove(ctx->in, buf, len); ++} ++ ++/* ++ * Final wrapup - pad to 64-byte boundary with the bit pattern ++ * 1 0* (64-bit count of bits processed, MSB-first) ++ */ ++void ++MD5Final(unsigned char digest[16], struct MD5Context *ctx) ++{ ++ unsigned int count; ++ unsigned char *p; ++ ++ /* Compute number of bytes mod 64 */ ++ count = (ctx->bits[0] >> 3) & 0x3F; ++ ++ /* Set the first char of padding to 0x80. This is safe since there is ++ always at least one byte free */ ++ p = ctx->in + count; ++ *p++ = 0x80; ++ ++ /* Bytes of padding needed to make 64 bytes */ ++ count = 64 - 1 - count; ++ ++ /* Pad out to 56 mod 64 */ ++ if (count < 8) { ++ /* Two lots of padding: Pad the first block to 64 bytes */ ++ memset(p, 0, count); ++ byteReverse(ctx->in, 16); ++ MD5Transform(ctx->buf, (__u32 *) ctx->in); ++ ++ /* Now fill the next block with 56 bytes */ ++ memset(ctx->in, 0, 56); ++ } else { ++ /* Pad block to 56 bytes */ ++ memset(p, 0, count - 8); ++ } ++ byteReverse(ctx->in, 14); ++ ++ /* Append length in bits and transform */ ++ ((__u32 *) ctx->in)[14] = ctx->bits[0]; ++ ((__u32 *) ctx->in)[15] = ctx->bits[1]; ++ ++ MD5Transform(ctx->buf, (__u32 *) ctx->in); ++ byteReverse((unsigned char *) ctx->buf, 4); ++ memmove(digest, ctx->buf, 16); ++ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ ++} ++ ++/* The four core functions - F1 is optimized somewhat */ ++ ++/* #define F1(x, y, z) (x & y | ~x & z) */ ++#define F1(x, y, z) (z ^ (x & (y ^ z))) ++#define F2(x, y, z) F1(z, x, y) ++#define F3(x, y, z) (x ^ y ^ z) ++#define F4(x, y, z) (y ^ (x | ~z)) ++ ++/* This is the central step in the MD5 algorithm. */ ++#define MD5STEP(f, w, x, y, z, data, s) \ ++ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) ++ ++/* ++ * The core of the MD5 algorithm, this alters an existing MD5 hash to ++ * reflect the addition of 16 longwords of new data. MD5Update blocks ++ * the data and converts bytes into longwords for this routine. ++ */ ++static void ++MD5Transform(__u32 buf[4], __u32 const in[16]) ++{ ++ register __u32 a, b, c, d; ++ ++ a = buf[0]; ++ b = buf[1]; ++ c = buf[2]; ++ d = buf[3]; ++ ++ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); ++ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); ++ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); ++ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); ++ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); ++ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); ++ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); ++ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); ++ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); ++ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); ++ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); ++ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); ++ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); ++ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); ++ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); ++ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); ++ ++ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); ++ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); ++ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); ++ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); ++ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); ++ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); ++ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); ++ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); ++ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); ++ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); ++ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); ++ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); ++ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); ++ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); ++ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); ++ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); ++ ++ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); ++ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); ++ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); ++ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); ++ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); ++ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); ++ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); ++ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); ++ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); ++ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); ++ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); ++ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); ++ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); ++ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); ++ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); ++ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); ++ ++ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); ++ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); ++ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); ++ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); ++ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); ++ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); ++ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); ++ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); ++ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); ++ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); ++ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); ++ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); ++ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); ++ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); ++ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); ++ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); ++ ++ buf[0] += a; ++ buf[1] += b; ++ buf[2] += c; ++ buf[3] += d; ++} ++ ++/*********************************************************************** ++ the rfc 2104 version of hmac_md5 initialisation. ++***********************************************************************/ ++void ++hmac_md5_init_rfc2104(unsigned char *key, int key_len, ++ struct HMACMD5Context *ctx) ++{ ++ int i; ++ ++ /* if key is longer than 64 bytes reset it to key=MD5(key) */ ++ if (key_len > 64) { ++ unsigned char tk[16]; ++ struct MD5Context tctx; ++ ++ MD5Init(&tctx); ++ MD5Update(&tctx, key, key_len); ++ MD5Final(tk, &tctx); ++ ++ key = tk; ++ key_len = 16; ++ } ++ ++ /* start out by storing key in pads */ ++ memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); ++ memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); ++ memcpy(ctx->k_ipad, key, key_len); ++ memcpy(ctx->k_opad, key, key_len); ++ ++ /* XOR key with ipad and opad values */ ++ for (i = 0; i < 64; i++) { ++ ctx->k_ipad[i] ^= 0x36; ++ ctx->k_opad[i] ^= 0x5c; ++ } ++ ++ MD5Init(&ctx->ctx); ++ MD5Update(&ctx->ctx, ctx->k_ipad, 64); ++} ++ ++/*********************************************************************** ++ the microsoft version of hmac_md5 initialisation. ++***********************************************************************/ ++void ++hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, ++ struct HMACMD5Context *ctx) ++{ ++ int i; ++ ++ /* if key is longer than 64 bytes truncate it */ ++ if (key_len > 64) { ++ key_len = 64; ++ } ++ ++ /* start out by storing key in pads */ ++ memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad)); ++ memset(ctx->k_opad, 0, sizeof (ctx->k_opad)); ++ memcpy(ctx->k_ipad, key, key_len); ++ memcpy(ctx->k_opad, key, key_len); ++ ++ /* XOR key with ipad and opad values */ ++ for (i = 0; i < 64; i++) { ++ ctx->k_ipad[i] ^= 0x36; ++ ctx->k_opad[i] ^= 0x5c; ++ } ++ ++ MD5Init(&ctx->ctx); ++ MD5Update(&ctx->ctx, ctx->k_ipad, 64); ++} ++ ++/*********************************************************************** ++ update hmac_md5 "inner" buffer ++***********************************************************************/ ++void ++hmac_md5_update(const unsigned char *text, int text_len, ++ struct HMACMD5Context *ctx) ++{ ++ MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */ ++} ++ ++/*********************************************************************** ++ finish off hmac_md5 "inner" buffer and generate outer one. ++***********************************************************************/ ++void ++hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) ++{ ++ struct MD5Context ctx_o; ++ ++ MD5Final(digest, &ctx->ctx); ++ ++ MD5Init(&ctx_o); ++ MD5Update(&ctx_o, ctx->k_opad, 64); ++ MD5Update(&ctx_o, digest, 16); ++ MD5Final(digest, &ctx_o); ++} ++ ++/*********************************************************** ++ single function to calculate an HMAC MD5 digest from data. ++ use the microsoft hmacmd5 init method because the key is 16 bytes. ++************************************************************/ ++void ++hmac_md5(unsigned char key[16], unsigned char *data, int data_len, ++ unsigned char *digest) ++{ ++ struct HMACMD5Context ctx; ++ hmac_md5_init_limK_to_64(key, 16, &ctx); ++ if (data_len != 0) { ++ hmac_md5_update(data, data_len, &ctx); ++ } ++ hmac_md5_final(digest, &ctx); ++} +diff -urN linux-2.4.29.old/fs/cifs/md5.h linux-2.4.29/fs/cifs/md5.h +--- linux-2.4.29.old/fs/cifs/md5.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/md5.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,38 @@ ++#ifndef MD5_H ++#define MD5_H ++#ifndef HEADER_MD5_H ++/* Try to avoid clashes with OpenSSL */ ++#define HEADER_MD5_H ++#endif ++ ++struct MD5Context { ++ __u32 buf[4]; ++ __u32 bits[2]; ++ unsigned char in[64]; ++}; ++#endif /* !MD5_H */ ++ ++#ifndef _HMAC_MD5_H ++struct HMACMD5Context { ++ struct MD5Context ctx; ++ unsigned char k_ipad[65]; ++ unsigned char k_opad[65]; ++}; ++#endif /* _HMAC_MD5_H */ ++ ++void MD5Init(struct MD5Context *context); ++void MD5Update(struct MD5Context *context, unsigned char const *buf, ++ unsigned len); ++void MD5Final(unsigned char digest[16], struct MD5Context *context); ++ ++/* The following definitions come from lib/hmacmd5.c */ ++ ++void hmac_md5_init_rfc2104(unsigned char *key, int key_len, ++ struct HMACMD5Context *ctx); ++void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, ++ struct HMACMD5Context *ctx); ++void hmac_md5_update(const unsigned char *text, int text_len, ++ struct HMACMD5Context *ctx); ++void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); ++void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, ++ unsigned char *digest); +diff -urN linux-2.4.29.old/fs/cifs/misc.c linux-2.4.29/fs/cifs/misc.c +--- linux-2.4.29.old/fs/cifs/misc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/misc.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,463 @@ ++/* ++ * fs/cifs/misc.c ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2003 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/slab.h> ++#include <linux/ctype.h> ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_debug.h" ++#include "smberr.h" ++#include "nterr.h" ++ ++extern kmem_cache_t *cifs_req_cachep; ++extern struct task_struct * oplockThread; ++ ++__u16 GlobalMid; /* multiplex id - rotating counter */ ++ ++/* The xid serves as a useful identifier for each incoming vfs request, ++ in a similar way to the mid which is useful to track each sent smb, ++ and CurrentXid can also provide a running counter (although it ++ will eventually wrap past zero) of the total vfs operations handled ++ since the cifs fs was mounted */ ++ ++unsigned int ++_GetXid(void) ++{ ++ unsigned int xid; ++ ++ spin_lock(&GlobalMid_Lock); ++ GlobalTotalActiveXid++; ++ if (GlobalTotalActiveXid > GlobalMaxActiveXid) ++ GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ ++ xid = GlobalCurrentXid++; ++ spin_unlock(&GlobalMid_Lock); ++ return xid; ++} ++ ++void ++_FreeXid(unsigned int xid) ++{ ++ spin_lock(&GlobalMid_Lock); ++ /* if(GlobalTotalActiveXid == 0) ++ BUG(); */ ++ GlobalTotalActiveXid--; ++ spin_unlock(&GlobalMid_Lock); ++} ++ ++struct cifsSesInfo * ++sesInfoAlloc(void) ++{ ++ struct cifsSesInfo *ret_buf; ++ ++ ret_buf = ++ (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo), ++ GFP_KERNEL); ++ if (ret_buf) { ++ memset(ret_buf, 0, sizeof (struct cifsSesInfo)); ++ write_lock(&GlobalSMBSeslock); ++ atomic_inc(&sesInfoAllocCount); ++ ret_buf->status = CifsNew; ++ list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); ++ init_MUTEX(&ret_buf->sesSem); ++ write_unlock(&GlobalSMBSeslock); ++ } ++ return ret_buf; ++} ++ ++void ++sesInfoFree(struct cifsSesInfo *buf_to_free) ++{ ++ if (buf_to_free == NULL) { ++ cFYI(1, ("Null buffer passed to sesInfoFree")); ++ return; ++ } ++ ++ write_lock(&GlobalSMBSeslock); ++ atomic_dec(&sesInfoAllocCount); ++ list_del(&buf_to_free->cifsSessionList); ++ write_unlock(&GlobalSMBSeslock); ++ if (buf_to_free->serverOS) ++ kfree(buf_to_free->serverOS); ++ if (buf_to_free->serverDomain) ++ kfree(buf_to_free->serverDomain); ++ if (buf_to_free->serverNOS) ++ kfree(buf_to_free->serverNOS); ++ if (buf_to_free->password) ++ kfree(buf_to_free->password); ++ kfree(buf_to_free); ++} ++ ++struct cifsTconInfo * ++tconInfoAlloc(void) ++{ ++ struct cifsTconInfo *ret_buf; ++ ret_buf = ++ (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo), ++ GFP_KERNEL); ++ if (ret_buf) { ++ memset(ret_buf, 0, sizeof (struct cifsTconInfo)); ++ write_lock(&GlobalSMBSeslock); ++ atomic_inc(&tconInfoAllocCount); ++ list_add(&ret_buf->cifsConnectionList, ++ &GlobalTreeConnectionList); ++ ret_buf->tidStatus = CifsNew; ++ INIT_LIST_HEAD(&ret_buf->openFileList); ++ init_MUTEX(&ret_buf->tconSem); ++#ifdef CONFIG_CIFS_STATS ++ ret_buf->stat_lock = SPIN_LOCK_UNLOCKED; ++#endif ++ write_unlock(&GlobalSMBSeslock); ++ } ++ return ret_buf; ++} ++ ++void ++tconInfoFree(struct cifsTconInfo *buf_to_free) ++{ ++ if (buf_to_free == NULL) { ++ cFYI(1, ("Null buffer passed to tconInfoFree")); ++ return; ++ } ++ write_lock(&GlobalSMBSeslock); ++ atomic_dec(&tconInfoAllocCount); ++ list_del(&buf_to_free->cifsConnectionList); ++ write_unlock(&GlobalSMBSeslock); ++ if (buf_to_free->nativeFileSystem) ++ kfree(buf_to_free->nativeFileSystem); ++ kfree(buf_to_free); ++} ++ ++struct smb_hdr * ++cifs_buf_get(void) ++{ ++ struct smb_hdr *ret_buf = NULL; ++ ++/* We could use negotiated size instead of max_msgsize - ++ but it may be more efficient to always alloc same size ++ albeit slightly larger than necessary and maxbuffersize ++ defaults to this and can not be bigger */ ++ ret_buf = ++ (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL); ++ ++ /* clear the first few header bytes */ ++ if (ret_buf) { ++ memset(ret_buf, 0, sizeof (struct smb_hdr)); ++ atomic_inc(&bufAllocCount); ++ } ++ ++ return ret_buf; ++} ++ ++void ++cifs_buf_release(void *buf_to_free) ++{ ++ ++ if (buf_to_free == NULL) { ++ cFYI(1, ("Null buffer passed to cifs_buf_release")); ++ return; ++ } ++ kmem_cache_free(cifs_req_cachep, buf_to_free); ++ ++ atomic_dec(&bufAllocCount); ++ return; ++} ++ ++void ++header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , ++ const struct cifsTconInfo *treeCon, int word_count ++ /* length of fixed section (word count) in two byte units */ ++ ) ++{ ++ int i; ++ __u32 tmp; ++ struct list_head* temp_item; ++ struct cifsSesInfo * ses; ++ char *temp = (char *) buffer; ++ ++ for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) { ++ temp[i] = 0; /* BB is this needed ?? */ ++ } ++ ++ buffer->smb_buf_length = ++ (2 * word_count) + sizeof (struct smb_hdr) - ++ 4 /* RFC 1001 length field does not count */ + ++ 2 /* for bcc field itself */ ; ++ /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */ ++ ++ buffer->Protocol[0] = 0xFF; ++ buffer->Protocol[1] = 'S'; ++ buffer->Protocol[2] = 'M'; ++ buffer->Protocol[3] = 'B'; ++ buffer->Command = smb_command; ++ buffer->Flags = 0x00; /* case sensitive */ ++ buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES; ++ tmp = cpu_to_le32(current->pid); ++ buffer->Pid = tmp & 0xFFFF; ++ tmp >>= 16; ++ buffer->PidHigh = tmp & 0xFFFF; ++ spin_lock(&GlobalMid_Lock); ++ GlobalMid++; ++ buffer->Mid = GlobalMid; ++ spin_unlock(&GlobalMid_Lock); ++ if (treeCon) { ++ buffer->Tid = treeCon->tid; ++ if (treeCon->ses) { ++ if (treeCon->ses->capabilities & CAP_UNICODE) ++ buffer->Flags2 |= SMBFLG2_UNICODE; ++ if (treeCon->ses->capabilities & CAP_STATUS32) { ++ buffer->Flags2 |= SMBFLG2_ERR_STATUS; ++ } ++ ++ buffer->Uid = treeCon->ses->Suid; /* always in LE format */ ++ if(multiuser_mount != 0) { ++ /* For the multiuser case, there are few obvious technically */ ++ /* possible mechanisms to match the local linux user (uid) */ ++ /* to a valid remote smb user (smb_uid): */ ++ /* 1) Query Winbind (or other local pam/nss daemon */ ++ /* for userid/password/logon_domain or credential */ ++ /* 2) Query Winbind for uid to sid to username mapping */ ++ /* and see if we have a matching password for existing*/ ++ /* session for that user perhas getting password by */ ++ /* adding a new pam_cifs module that stores passwords */ ++ /* so that the cifs vfs can get at that for all logged*/ ++ /* on users */ ++ /* 3) (Which is the mechanism we have chosen) */ ++ /* Search through sessions to the same server for a */ ++ /* a match on the uid that was passed in on mount */ ++ /* with the current processes uid (or euid?) and use */ ++ /* that smb uid. If no existing smb session for */ ++ /* that uid found, use the default smb session ie */ ++ /* the smb session for the volume mounted which is */ ++ /* the same as would be used if the multiuser mount */ ++ /* flag were disabled. */ ++ ++ /* BB Add support for establishing new tCon and SMB Session */ ++ /* with userid/password pairs found on the smb session */ ++ /* for other target tcp/ip addresses BB */ ++ if(current->uid != treeCon->ses->linux_uid) { ++ cFYI(1,("Multiuser mode and UID did not match tcon uid ")); ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(temp_item, &GlobalSMBSessionList) { ++ ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); ++ if(ses->linux_uid == current->uid) { ++ if(ses->server == treeCon->ses->server) { ++ cFYI(1,("found matching uid substitute right smb_uid")); ++ buffer->Uid = ses->Suid; ++ break; ++ } else { ++ /* BB eventually call cifs_setup_session here */ ++ cFYI(1,("local UID found but smb sess with this server does not exist")); ++ } ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ } ++ } ++ } ++ if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) ++ buffer->Flags2 |= SMBFLG2_DFS; ++ if(treeCon->ses->server) ++ if(treeCon->ses->server->secMode & ++ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) ++ buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; ++ } ++ ++/* endian conversion of flags is now done just before sending */ ++ buffer->WordCount = (char) word_count; ++ return; ++} ++ ++int ++checkSMBhdr(struct smb_hdr *smb, __u16 mid) ++{ ++ /* Make sure that this really is an SMB, that it is a response, ++ and that the message ids match */ ++ if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) && ++ (mid == smb->Mid)) { ++ if(smb->Flags & SMBFLG_RESPONSE) ++ return 0; ++ else { ++ /* only one valid case where server sends us request */ ++ if(smb->Command == SMB_COM_LOCKING_ANDX) ++ return 0; ++ else ++ cERROR(1, ("Rcvd Request not response ")); ++ } ++ } else { /* bad signature or mid */ ++ if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff)) ++ cERROR(1, ++ ("Bad protocol string signature header %x ", ++ *(unsigned int *) smb->Protocol)); ++ if (mid != smb->Mid) ++ cERROR(1, ("Mids do not match")); ++ } ++ cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid)); ++ return 1; ++} ++ ++int ++checkSMB(struct smb_hdr *smb, __u16 mid, int length) ++{ ++ cFYI(0, ++ ("Entering checkSMB with Length: %x, smb_buf_length: %x ", ++ length, ntohl(smb->smb_buf_length))); ++ if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ++ || (ntohl(smb->smb_buf_length) > ++ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) { ++ if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { ++ cERROR(1, ("Length less than 2 + sizeof smb_hdr ")); ++ if (((unsigned int)length >= sizeof (struct smb_hdr) - 1) ++ && (smb->Status.CifsError != 0)) ++ return 0; /* some error cases do not return wct and bcc */ ++ ++ } ++ if (ntohl(smb->smb_buf_length) > ++ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) ++ cERROR(1, ++ ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... ")); ++ cERROR(1, ++ ("bad smb detected. Illegal length. The mid=%d", ++ smb->Mid)); ++ return 1; ++ } ++ ++ if (checkSMBhdr(smb, mid)) ++ return 1; ++ ++ if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb)) ++ || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) { ++ return 0; ++ } else { ++ cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); ++ cERROR(1, ++ ("bad smb size detected. The Mid=%d", smb->Mid)); ++ return 1; ++ } ++} ++int ++is_valid_oplock_break(struct smb_hdr *buf) ++{ ++ struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf; ++ struct list_head *tmp; ++ struct list_head *tmp1; ++ struct cifsTconInfo *tcon; ++ struct cifsFileInfo *netfile; ++ ++ /* could add check for smb response flag 0x80 */ ++ cFYI(1,("Checking for oplock break")); ++ if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX) ++ return FALSE; ++ if(pSMB->hdr.Flags & SMBFLG_RESPONSE) { ++ /* no sense logging error on invalid handle on oplock ++ break - harmless race between close request and oplock ++ break response is expected from time to time writing out ++ large dirty files cached on the client */ ++ if ((NT_STATUS_INVALID_HANDLE) == ++ le32_to_cpu(pSMB->hdr.Status.CifsError)) { ++ cFYI(1,("invalid handle on oplock break")); ++ return TRUE; ++ } else if (ERRbadfid == ++ le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { ++ return TRUE; ++ } else { ++ return FALSE; /* on valid oplock brk we get "request" */ ++ } ++ } ++ if(pSMB->hdr.WordCount != 8) ++ return FALSE; ++ ++ cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel)); ++ if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) ++ return FALSE; ++ ++ /* look up tcon based on tid & uid */ ++ read_lock(&GlobalSMBSeslock); ++ list_for_each(tmp, &GlobalTreeConnectionList) { ++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); ++ if (tcon->tid == buf->Tid) { ++#ifdef CONFIG_CIFS_STATS ++ atomic_inc(&tcon->num_oplock_brks); ++#endif ++ list_for_each(tmp1,&tcon->openFileList){ ++ netfile = list_entry(tmp1,struct cifsFileInfo,tlist); ++ if(pSMB->Fid == netfile->netfid) { ++ struct cifsInodeInfo *pCifsInode; ++ read_unlock(&GlobalSMBSeslock); ++ cFYI(1,("Matching file id, processing oplock break")); ++ pCifsInode = ++ CIFS_I(netfile->pInode); ++ pCifsInode->clientCanCacheAll = FALSE; ++ if(pSMB->OplockLevel == 0) ++ pCifsInode->clientCanCacheRead = FALSE; ++ pCifsInode->oplockPending = TRUE; ++ AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon); ++ cFYI(1,("about to wake up oplock thd")); ++ wake_up_process(oplockThread); ++ return TRUE; ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ cFYI(1,("No matching file for oplock break on connection")); ++ return TRUE; ++ } ++ } ++ read_unlock(&GlobalSMBSeslock); ++ cFYI(1,("Can not process oplock break for non-existent connection")); ++ return TRUE; ++} ++ ++void ++dump_smb(struct smb_hdr *smb_buf, int smb_buf_length) ++{ ++ int i, j; ++ char debug_line[17]; ++ unsigned char *buffer; ++ ++ if (traceSMB == 0) ++ return; ++ ++ buffer = (unsigned char *) smb_buf; ++ for (i = 0, j = 0; i < smb_buf_length; i++, j++) { ++ if (i % 8 == 0) { /* we have reached the beginning of line */ ++ printk(KERN_DEBUG "| "); ++ j = 0; ++ } ++ printk("%0#4x ", buffer[i]); ++ debug_line[2 * j] = ' '; ++ if (isprint(buffer[i])) ++ debug_line[1 + (2 * j)] = buffer[i]; ++ else ++ debug_line[1 + (2 * j)] = '_'; ++ ++ if (i % 8 == 7) { /* we have reached end of line, time to print ascii */ ++ debug_line[16] = 0; ++ printk(" | %s\n", debug_line); ++ } ++ } ++ for (; j < 8; j++) { ++ printk(" "); ++ debug_line[2 * j] = ' '; ++ debug_line[1 + (2 * j)] = ' '; ++ } ++ printk( " | %s\n", debug_line); ++ return; ++} +diff -urN linux-2.4.29.old/fs/cifs/netmisc.c linux-2.4.29/fs/cifs/netmisc.c +--- linux-2.4.29.old/fs/cifs/netmisc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/netmisc.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,905 @@ ++/* ++ * fs/cifs/netmisc.c ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * Error mapping routines from Samba libsmb/errormap.c ++ * Copyright (C) Andrew Tridgell 2001 ++ * ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/net.h> ++#include <linux/string.h> ++#include <linux/in.h> ++#include <linux/ctype.h> ++#include <linux/fs.h> ++#include <asm/div64.h> ++#include <asm/byteorder.h> ++#include "cifsfs.h" ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "smberr.h" ++#include "cifs_debug.h" ++#include "nterr.h" ++ ++struct smb_to_posix_error { ++ __u16 smb_err; ++ int posix_code; ++}; ++ ++const struct smb_to_posix_error mapping_table_ERRDOS[] = { ++ {ERRbadfunc, -EINVAL}, ++ {ERRbadfile, -ENOENT}, ++ {ERRbadpath, -ENOTDIR}, ++ {ERRnofids, -EMFILE}, ++ {ERRnoaccess, -EACCES}, ++ {ERRbadfid, -EBADF}, ++ {ERRbadmcb, -EIO}, ++ {ERRnomem, -ENOMEM}, ++ {ERRbadmem, -EFAULT}, ++ {ERRbadenv, -EFAULT}, ++ {ERRbadformat, -EINVAL}, ++ {ERRbadaccess, -EACCES}, ++ {ERRbaddata, -EIO}, ++ {ERRbaddrive, -ENXIO}, ++ {ERRremcd, -EACCES}, ++ {ERRdiffdevice, -EXDEV}, ++ {ERRnofiles, -ENOENT}, ++ {ERRbadshare, -ETXTBSY}, ++ {ERRlock, -EACCES}, ++ {ERRunsup, -EINVAL}, ++ {ERRnosuchshare,-ENXIO}, ++ {ERRfilexists, -EEXIST}, ++ {ERRinvparm, -EINVAL}, ++ {ERRdiskfull, -ENOSPC}, ++ {ERRinvname, -ENOENT}, ++ {ERRdirnotempty, -ENOTEMPTY}, ++ {ERRnotlocked, -ENOLCK}, ++ {ERRalreadyexists, -EEXIST}, ++ {ERRmoredata, -EOVERFLOW}, ++ {ErrQuota, -EDQUOT}, ++ {ErrNotALink, -ENOLINK}, ++ {ERRnetlogonNotStarted,-ENOPROTOOPT}, ++ {0, 0} ++}; ++ ++const struct smb_to_posix_error mapping_table_ERRSRV[] = { ++ {ERRerror, -EIO}, ++ {ERRbadpw, -EPERM}, ++ {ERRbadtype, -EREMOTE}, ++ {ERRaccess, -EACCES}, ++ {ERRinvtid, -ENXIO}, ++ {ERRinvnetname, -ENODEV}, ++ {ERRinvdevice, -ENXIO}, ++ {ERRqfull, -ENOSPC}, ++ {ERRqtoobig, -ENOSPC}, ++ {ERRqeof, -EIO}, ++ {ERRinvpfid, -EBADF}, ++ {ERRsmbcmd, -EBADRQC}, ++ {ERRsrverror, -EIO}, ++ {ERRbadBID, -EIO}, ++ {ERRfilespecs, -EINVAL}, ++ {ERRbadLink, -EIO}, ++ {ERRbadpermits, -EINVAL}, ++ {ERRbadPID, -ESRCH}, ++ {ERRsetattrmode, -EINVAL}, ++ {ERRpaused, -EHOSTDOWN}, ++ {ERRmsgoff, -EHOSTDOWN}, ++ {ERRnoroom, -ENOSPC}, ++ {ERRrmuns, -EUSERS}, ++ {ERRtimeout, -ETIME}, ++ {ERRnoresource, -ENOBUFS}, ++ {ERRtoomanyuids, -EUSERS}, ++ {ERRbaduid, -EACCES}, ++ {ERRusempx, -EIO}, ++ {ERRusestd, -EIO}, ++ {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, ++ {ERRaccountexpired, -EACCES}, ++ {ERRbadclient, -EACCES}, ++ {ERRbadLogonTime, -EACCES}, ++ {ERRpasswordExpired, -EACCES}, ++ {ERRnosupport, -EINVAL}, ++ {0, 0} ++}; ++ ++const struct smb_to_posix_error mapping_table_ERRHRD[] = { ++ {0, 0} ++}; ++ ++/* Convert string containing dotted ip address to binary form */ ++/* returns 0 if invalid address */ ++ ++/* BB add address family, change rc to status flag and return union or for ipv6 */ ++/* will need parent to call something like inet_pton to convert ipv6 address BB */ ++int ++cifs_inet_pton(int address_family, char *cp,void *dst) ++{ ++ struct in_addr address; ++ int value; ++ int digit; ++ int i; ++ char temp; ++ char bytes[4]; ++ char *end = bytes; ++ static const int addr_class_max[4] = ++ { 0xffffffff, 0xffffff, 0xffff, 0xff }; ++ ++ if(address_family != AF_INET) ++ return -EAFNOSUPPORT; ++ ++ for (i = 0; i < 4; i++) { ++ bytes[i] = 0; ++ } ++ ++ temp = *cp; ++ ++ while (TRUE) { ++ if (!isdigit(temp)) ++ return 0; ++ ++ value = 0; ++ digit = 0; ++ for (;;) { ++ if (isascii(temp) && isdigit(temp)) { ++ value = (value * 10) + temp - '0'; ++ temp = *++cp; ++ digit = 1; ++ } else ++ break; ++ } ++ ++ if (temp == '.') { ++ if ((end > bytes + 2) || (value > 255)) ++ return 0; ++ *end++ = value; ++ temp = *++cp; ++ } else if (temp == ':') { ++ cFYI(1,("IPv6 addresses not supported for CIFS mounts yet")); ++ return -1; ++ } else ++ break; ++ } ++ ++ /* check for last characters */ ++ if (temp != '\0' && (!isascii(temp) || !isspace(temp))) ++ if (temp != '\\') { ++ if (temp != '/') ++ return 0; ++ else ++ (*cp = '\\'); /* switch the slash the expected way */ ++ } ++ if (value > addr_class_max[end - bytes]) ++ return 0; ++ ++ address.s_addr = *((int *) bytes) | htonl(value); ++ *((int *)dst) = address.s_addr; ++ return 1; /* success */ ++} ++ ++/***************************************************************************** ++convert a NT status code to a dos class/code ++ *****************************************************************************/ ++/* NT status -> dos error map */ ++static const struct { ++ __u8 dos_class; ++ __u16 dos_code; ++ __u32 ntstatus; ++} ntstatus_to_dos_map[] = { ++ { ++ ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, { ++ ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, { ++ ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, { ++ ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, { ++ ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, { ++ ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, { ++ ERRDOS, 87, NT_STATUS_INVALID_CID}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, { ++ ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, { ++ ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, { ++ ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, { ++ ERRDOS, 38, NT_STATUS_END_OF_FILE}, { ++ ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, { ++ ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, { ++ ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR}, ++/* { This NT error code was 'sqashed' ++ from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK ++ during the session setup } */ ++ { ++ ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, { ++ ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, { ++ ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, { ++ ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, { ++ ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, { ++ ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, { ++ ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED}, ++/* { This NT error code was 'sqashed' ++ from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE ++ during the session setup } */ ++ { ++ ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, { ++ ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, { ++ ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, { ++ ERRDOS, 158, NT_STATUS_NOT_LOCKED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, { ++ ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, { ++ ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, { ++ ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */ ++ ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, { ++ ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, { ++ ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, { ++ ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, { ++ ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, { ++ ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, { ++ ERRDOS, 23, NT_STATUS_DATA_ERROR}, { ++ ERRDOS, 23, NT_STATUS_CRC_ERROR}, { ++ ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, { ++ ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, { ++ ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, { ++ ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, { ++ ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, { ++ ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, { ++ ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, { ++ ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, { ++ ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, { ++ ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, { ++ ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, { ++ ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, { ++ ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, { ++ ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, { ++ ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, { ++ ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, { ++ ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, { ++ ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, { ++ ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS}, ++/* { This NT error code was 'sqashed' ++ from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE ++ during the session setup } */ ++ { ++ ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN}, ++/* { This NT error code was 'sqashed' ++ from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE ++ during the session setup } */ ++ { ++ ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { ++ ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { ++ ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { ++ ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, { ++ ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, { ++ ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, { ++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, { ++ ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, { ++ ERRDOS, 112, NT_STATUS_DISK_FULL}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, { ++ ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, { ++ ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, { ++ ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, { ++ ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, { ++ ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, { ++ ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, { ++ ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, { ++ ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, ++/* { This NT error code was 'sqashed' ++ from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES ++ during the session setup } */ ++ { ++ ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, { ++ ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, { ++ ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, { ++ ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, { ++ ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, { ++ ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, { ++ ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, { ++ ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, { ++ ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, { ++ ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, { ++ ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, { ++ ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, { ++ ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, { ++ ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, { ++ ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, { ++ ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, { ++ ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, { ++ ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, { ++ ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, { ++ ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, { ++ ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, { ++ ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, { ++ ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, { ++ ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, { ++ ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, { ++ ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, { ++ ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, { ++ ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, { ++ ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, { ++ ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, { ++ ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, { ++ ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, { ++ ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, { ++ ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, { ++ ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, { ++ ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, { ++ ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, { ++ ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, { ++ ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, { ++ ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, { ++ ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, { ++ ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, { ++ ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, { ++ ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, { ++ ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, { ++ ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, { ++ ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, { ++ ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, { ++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, { ++ ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, { ++ ERRDOS, 203, 0xc0000100}, { ++ ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, { ++ ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, { ++ ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, { ++ ERRDOS, 2401, NT_STATUS_FILES_OPEN}, { ++ ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, { ++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, { ++ ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, { ++ ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, { ++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, { ++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, { ++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, { ++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, { ++ ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, { ++ ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, { ++ ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, { ++ ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, { ++ ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, { ++ ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, { ++ ERRDOS, 59, NT_STATUS_LINK_FAILED}, { ++ ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, { ++ ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, { ++ ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, { ++ ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, { ++ ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, { ++ ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, { ++ ERRHRD, ERRgeneral, 0xc000016e}, { ++ ERRHRD, ERRgeneral, 0xc000016f}, { ++ ERRHRD, ERRgeneral, 0xc0000170}, { ++ ERRHRD, ERRgeneral, 0xc0000171}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, { ++ ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, { ++ ERRHRD, ERRgeneral, 0xc0000179}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, { ++ ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, { ++ ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, { ++ ERRDOS, 19, NT_STATUS_TOO_LATE}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET}, ++/* { This NT error code was 'sqashed' ++ from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE ++ during the session setup } */ ++ { ++ ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { ++ ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { ++ ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, ++/* { This NT error code was 'sqashed' ++ from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE ++ during the session setup } */ ++ { ++ ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, { ++ ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, { ++ ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, { ++ ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, { ++ ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, { ++ ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, { ++ ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, { ++ ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, { ++ ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, { ++ ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, { ++ ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, { ++ ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, { ++ ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, { ++ ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, { ++ ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, { ++ ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, { ++ ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, { ++ ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, { ++ ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { ++ ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, { ++ ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_RETRY}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, { ++ ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, { ++ ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, { ++ ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, { ++ ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, { ++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, { ++ ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, { ++ ERRHRD, ERRgeneral, 0xc000024a}, { ++ ERRHRD, ERRgeneral, 0xc000024b}, { ++ ERRHRD, ERRgeneral, 0xc000024c}, { ++ ERRHRD, ERRgeneral, 0xc000024d}, { ++ ERRHRD, ERRgeneral, 0xc000024e}, { ++ ERRHRD, ERRgeneral, 0xc000024f}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, { ++ ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, { ++ ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, { ++ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, { ++ ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, { ++ ERRHRD, ERRgeneral, 0xc000025d}, { ++ ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, { ++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, { ++ ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, { ++ ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, { ++ ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, { ++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, { ++ ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, { ++ ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, { ++ ERRDOS, 21, 0xc000026e}, { ++ ERRDOS, 161, 0xc0000281}, { ++ ERRDOS, ERRnoaccess, 0xc000028a}, { ++ ERRDOS, ERRnoaccess, 0xc000028b}, { ++ ERRHRD, ERRgeneral, 0xc000028c}, { ++ ERRDOS, ERRnoaccess, 0xc000028d}, { ++ ERRDOS, ERRnoaccess, 0xc000028e}, { ++ ERRDOS, ERRnoaccess, 0xc000028f}, { ++ ERRDOS, ERRnoaccess, 0xc0000290}, { ++ERRDOS, ERRbadfunc, 0xc000029c},}; ++ ++/***************************************************************************** ++ Print an error message from the status code ++ *****************************************************************************/ ++static void ++cifs_print_status(__u32 status_code) ++{ ++ int idx = 0; ++ ++ while (nt_errs[idx].nt_errstr != NULL) { ++ if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) == ++ (status_code & 0xFFFFFF)) { ++ printk(KERN_NOTICE "Status code returned 0x%08x %s\n", ++ status_code,nt_errs[idx].nt_errstr); ++ } ++ idx++; ++ } ++ return; ++} ++ ++ ++static void ++ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) ++{ ++ int i; ++ if (ntstatus == 0) { ++ *eclass = 0; ++ *ecode = 0; ++ return; ++ } ++ for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) { ++ if (ntstatus == ntstatus_to_dos_map[i].ntstatus) { ++ *eclass = ntstatus_to_dos_map[i].dos_class; ++ *ecode = ntstatus_to_dos_map[i].dos_code; ++ return; ++ } ++ } ++ *eclass = ERRHRD; ++ *ecode = ERRgeneral; ++} ++ ++int ++map_smb_to_linux_error(struct smb_hdr *smb) ++{ ++ unsigned int i; ++ int rc = -EIO; /* if transport error smb error may not be set */ ++ __u8 smberrclass; ++ __u16 smberrcode; ++ ++ /* BB if NT Status codes - map NT BB */ ++ ++ /* old style smb error codes */ ++ if (smb->Status.CifsError == 0) ++ return 0; ++ ++ if (smb->Flags2 & SMBFLG2_ERR_STATUS) { ++ /* translate the newer STATUS codes to old style errors and then to POSIX errors */ ++ smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError); ++ if(cifsFYI) ++ cifs_print_status(smb->Status.CifsError); ++ ntstatus_to_dos(smb->Status.CifsError, &smberrclass, ++ &smberrcode); ++ } else { ++ smberrclass = smb->Status.DosError.ErrorClass; ++ smb->Status.DosError.Error = ++ le16_to_cpu(smb->Status.DosError.Error); ++ smberrcode = smb->Status.DosError.Error; ++ } ++ ++ /* old style errors */ ++ ++ /* DOS class smb error codes - map DOS */ ++ if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */ ++ for (i = 0; ++ i < ++ sizeof (mapping_table_ERRDOS) / ++ sizeof (struct smb_to_posix_error); i++) { ++ if (mapping_table_ERRDOS[i].smb_err == 0) ++ break; ++ else if (mapping_table_ERRDOS[i].smb_err == smberrcode) { ++ rc = mapping_table_ERRDOS[i].posix_code; ++ break; ++ } ++ /* else try the next error mapping one to see if it will match */ ++ } ++ } else if (smberrclass == ERRSRV) { /* server class of error codes */ ++ for (i = 0; ++ i < ++ sizeof (mapping_table_ERRSRV) / ++ sizeof (struct smb_to_posix_error); i++) { ++ if (mapping_table_ERRSRV[i].smb_err == 0) ++ break; ++ else if (mapping_table_ERRSRV[i].smb_err == smberrcode) { ++ rc = mapping_table_ERRSRV[i].posix_code; ++ break; ++ } ++ /* else try the next error mapping one to see if it will match */ ++ } ++ } ++ /* else ERRHRD class errors or junk - return EIO */ ++ ++ cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc)); ++ ++ /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */ ++ ++ return rc; ++} ++ ++/* ++ * calculate the size of the SMB message based on the fixed header ++ * portion, the number of word parameters and the data portion of the message ++ */ ++unsigned int ++smbCalcSize(struct smb_hdr *ptr) ++{ ++ return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + ++ BCC(ptr)); ++} ++ ++/* The following are taken from fs/ntfs/util.c */ ++ ++#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000) ++ ++ /* ++ * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units) ++ * into Unix UTC (based 1970-01-01, in seconds). ++ */ ++time_t ++cifs_NTtimeToUnix(__u64 ntutc) ++{ ++ /* BB what about the timezone? BB */ ++ ++ /* Subtract the NTFS time offset, then convert to 1s intervals. */ ++ u64 t; ++ ++ t = ntutc - NTFS_TIME_OFFSET; ++ do_div(t, 10000000); ++ return (time_t)t; ++} ++ ++/* Convert the Unix UTC into NT UTC. */ ++__u64 ++cifs_UnixTimeToNT(time_t t) ++{ ++ __u64 dce_time; ++ /* Convert to 100ns intervals and then add the NTFS time offset. */ ++ dce_time = (__u64) t * 10000000; ++ dce_time += NTFS_TIME_OFFSET; ++ return dce_time; ++} +diff -urN linux-2.4.29.old/fs/cifs/nterr.c linux-2.4.29/fs/cifs/nterr.c +--- linux-2.4.29.old/fs/cifs/nterr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/nterr.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,687 @@ ++/* ++ * Unix SMB/Netbios implementation. ++ * Version 1.9. ++ * RPC Pipe client / server routines ++ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++/* NT error codes - see nterr.h */ ++#include <linux/types.h> ++#include <linux/fs.h> ++#include "nterr.h" ++ ++const struct nt_err_code_struct nt_errs[] = { ++ {"NT_STATUS_OK", NT_STATUS_OK}, ++ {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL}, ++ {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED}, ++ {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS}, ++ {"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH}, ++ {"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION}, ++ {"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW}, ++ {"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR}, ++ {"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA}, ++ {"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE}, ++ {"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK}, ++ {"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC}, ++ {"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID}, ++ {"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED}, ++ {"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER}, ++ {"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE}, ++ {"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE}, ++ {"NT_STATUS_INVALID_DEVICE_REQUEST", ++ NT_STATUS_INVALID_DEVICE_REQUEST}, ++ {"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE}, ++ {"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME}, ++ {"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE}, ++ {"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA}, ++ {"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR}, ++ {"NT_STATUS_MORE_PROCESSING_REQUIRED", ++ NT_STATUS_MORE_PROCESSING_REQUIRED}, ++ {"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY}, ++ {"NT_STATUS_CONFLICTING_ADDRESSES", ++ NT_STATUS_CONFLICTING_ADDRESSES}, ++ {"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW}, ++ {"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM}, ++ {"NT_STATUS_UNABLE_TO_DELETE_SECTION", ++ NT_STATUS_UNABLE_TO_DELETE_SECTION}, ++ {"NT_STATUS_INVALID_SYSTEM_SERVICE", ++ NT_STATUS_INVALID_SYSTEM_SERVICE}, ++ {"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION}, ++ {"NT_STATUS_INVALID_LOCK_SEQUENCE", ++ NT_STATUS_INVALID_LOCK_SEQUENCE}, ++ {"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE}, ++ {"NT_STATUS_INVALID_FILE_FOR_SECTION", ++ NT_STATUS_INVALID_FILE_FOR_SECTION}, ++ {"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED}, ++ {"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED}, ++ {"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL}, ++ {"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH}, ++ {"NT_STATUS_NONCONTINUABLE_EXCEPTION", ++ NT_STATUS_NONCONTINUABLE_EXCEPTION}, ++ {"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION}, ++ {"NT_STATUS_UNWIND", NT_STATUS_UNWIND}, ++ {"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK}, ++ {"NT_STATUS_INVALID_UNWIND_TARGET", ++ NT_STATUS_INVALID_UNWIND_TARGET}, ++ {"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED}, ++ {"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR}, ++ {"NT_STATUS_UNABLE_TO_DECOMMIT_VM", ++ NT_STATUS_UNABLE_TO_DECOMMIT_VM}, ++ {"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED}, ++ {"NT_STATUS_INVALID_PORT_ATTRIBUTES", ++ NT_STATUS_INVALID_PORT_ATTRIBUTES}, ++ {"NT_STATUS_PORT_MESSAGE_TOO_LONG", ++ NT_STATUS_PORT_MESSAGE_TOO_LONG}, ++ {"NT_STATUS_INVALID_PARAMETER_MIX", ++ NT_STATUS_INVALID_PARAMETER_MIX}, ++ {"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER}, ++ {"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR}, ++ {"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID}, ++ {"NT_STATUS_OBJECT_NAME_NOT_FOUND", ++ NT_STATUS_OBJECT_NAME_NOT_FOUND}, ++ {"NT_STATUS_OBJECT_NAME_COLLISION", ++ NT_STATUS_OBJECT_NAME_COLLISION}, ++ {"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE}, ++ {"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED}, ++ {"NT_STATUS_DEVICE_ALREADY_ATTACHED", ++ NT_STATUS_DEVICE_ALREADY_ATTACHED}, ++ {"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID}, ++ {"NT_STATUS_OBJECT_PATH_NOT_FOUND", ++ NT_STATUS_OBJECT_PATH_NOT_FOUND}, ++ {"NT_STATUS_OBJECT_PATH_SYNTAX_BAD", ++ NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, ++ {"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN}, ++ {"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR}, ++ {"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR}, ++ {"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR}, ++ {"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG}, ++ {"NT_STATUS_PORT_CONNECTION_REFUSED", ++ NT_STATUS_PORT_CONNECTION_REFUSED}, ++ {"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE}, ++ {"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION}, ++ {"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED}, ++ {"NT_STATUS_INVALID_PAGE_PROTECTION", ++ NT_STATUS_INVALID_PAGE_PROTECTION}, ++ {"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED}, ++ {"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", ++ NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, ++ {"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET}, ++ {"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE}, ++ {"NT_STATUS_SUSPEND_COUNT_EXCEEDED", ++ NT_STATUS_SUSPEND_COUNT_EXCEEDED}, ++ {"NT_STATUS_THREAD_IS_TERMINATING", ++ NT_STATUS_THREAD_IS_TERMINATING}, ++ {"NT_STATUS_BAD_WORKING_SET_LIMIT", ++ NT_STATUS_BAD_WORKING_SET_LIMIT}, ++ {"NT_STATUS_INCOMPATIBLE_FILE_MAP", ++ NT_STATUS_INCOMPATIBLE_FILE_MAP}, ++ {"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION}, ++ {"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED}, ++ {"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE}, ++ {"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY}, ++ {"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE}, ++ {"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR}, ++ {"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT}, ++ {"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED}, ++ {"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING}, ++ {"NT_STATUS_CTL_FILE_NOT_SUPPORTED", ++ NT_STATUS_CTL_FILE_NOT_SUPPORTED}, ++ {"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION}, ++ {"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH}, ++ {"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER}, ++ {"NT_STATUS_INVALID_PRIMARY_GROUP", ++ NT_STATUS_INVALID_PRIMARY_GROUP}, ++ {"NT_STATUS_NO_IMPERSONATION_TOKEN", ++ NT_STATUS_NO_IMPERSONATION_TOKEN}, ++ {"NT_STATUS_CANT_DISABLE_MANDATORY", ++ NT_STATUS_CANT_DISABLE_MANDATORY}, ++ {"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS}, ++ {"NT_STATUS_NO_SUCH_LOGON_SESSION", ++ NT_STATUS_NO_SUCH_LOGON_SESSION}, ++ {"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE}, ++ {"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD}, ++ {"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME}, ++ {"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS}, ++ {"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER}, ++ {"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS}, ++ {"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP}, ++ {"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP}, ++ {"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP}, ++ {"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN}, ++ {"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD}, ++ {"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD}, ++ {"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION}, ++ {"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE}, ++ {"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION}, ++ {"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS}, ++ {"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION}, ++ {"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED}, ++ {"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED}, ++ {"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED}, ++ {"NT_STATUS_TOO_MANY_LUIDS_REQUESTED", ++ NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, ++ {"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED}, ++ {"NT_STATUS_INVALID_SUB_AUTHORITY", ++ NT_STATUS_INVALID_SUB_AUTHORITY}, ++ {"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL}, ++ {"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID}, ++ {"NT_STATUS_INVALID_SECURITY_DESCR", ++ NT_STATUS_INVALID_SECURITY_DESCR}, ++ {"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND}, ++ {"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT}, ++ {"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN}, ++ {"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL}, ++ {"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED}, ++ {"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL}, ++ {"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED}, ++ {"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED}, ++ {"NT_STATUS_TOO_MANY_GUIDS_REQUESTED", ++ NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, ++ {"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED}, ++ {"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY}, ++ {"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED}, ++ {"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL}, ++ {"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED}, ++ {"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA}, ++ {"NT_STATUS_RESOURCE_DATA_NOT_FOUND", ++ NT_STATUS_RESOURCE_DATA_NOT_FOUND}, ++ {"NT_STATUS_RESOURCE_TYPE_NOT_FOUND", ++ NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, ++ {"NT_STATUS_RESOURCE_NAME_NOT_FOUND", ++ NT_STATUS_RESOURCE_NAME_NOT_FOUND}, ++ {"NT_STATUS_ARRAY_BOUNDS_EXCEEDED", ++ NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, ++ {"NT_STATUS_FLOAT_DENORMAL_OPERAND", ++ NT_STATUS_FLOAT_DENORMAL_OPERAND}, ++ {"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, ++ {"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT}, ++ {"NT_STATUS_FLOAT_INVALID_OPERATION", ++ NT_STATUS_FLOAT_INVALID_OPERATION}, ++ {"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW}, ++ {"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK}, ++ {"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW}, ++ {"NT_STATUS_INTEGER_DIVIDE_BY_ZERO", ++ NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, ++ {"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW}, ++ {"NT_STATUS_PRIVILEGED_INSTRUCTION", ++ NT_STATUS_PRIVILEGED_INSTRUCTION}, ++ {"NT_STATUS_TOO_MANY_PAGING_FILES", ++ NT_STATUS_TOO_MANY_PAGING_FILES}, ++ {"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID}, ++ {"NT_STATUS_ALLOTTED_SPACE_EXCEEDED", ++ NT_STATUS_ALLOTTED_SPACE_EXCEEDED}, ++ {"NT_STATUS_INSUFFICIENT_RESOURCES", ++ NT_STATUS_INSUFFICIENT_RESOURCES}, ++ {"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND}, ++ {"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR}, ++ {"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED}, ++ {"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE}, ++ {"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE}, ++ {"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED}, ++ {"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA}, ++ {"NT_STATUS_MEDIA_WRITE_PROTECTED", ++ NT_STATUS_MEDIA_WRITE_PROTECTED}, ++ {"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY}, ++ {"NT_STATUS_INVALID_GROUP_ATTRIBUTES", ++ NT_STATUS_INVALID_GROUP_ATTRIBUTES}, ++ {"NT_STATUS_BAD_IMPERSONATION_LEVEL", ++ NT_STATUS_BAD_IMPERSONATION_LEVEL}, ++ {"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS}, ++ {"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS}, ++ {"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE}, ++ {"NT_STATUS_BAD_MASTER_BOOT_RECORD", ++ NT_STATUS_BAD_MASTER_BOOT_RECORD}, ++ {"NT_STATUS_INSTRUCTION_MISALIGNMENT", ++ NT_STATUS_INSTRUCTION_MISALIGNMENT}, ++ {"NT_STATUS_INSTANCE_NOT_AVAILABLE", ++ NT_STATUS_INSTANCE_NOT_AVAILABLE}, ++ {"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE}, ++ {"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE}, ++ {"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY}, ++ {"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION}, ++ {"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED}, ++ {"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING}, ++ {"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED}, ++ {"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING}, ++ {"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE}, ++ {"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT}, ++ {"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED}, ++ {"NT_STATUS_PROFILING_NOT_STARTED", ++ NT_STATUS_PROFILING_NOT_STARTED}, ++ {"NT_STATUS_PROFILING_NOT_STOPPED", ++ NT_STATUS_PROFILING_NOT_STOPPED}, ++ {"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET}, ++ {"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY}, ++ {"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED}, ++ {"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING}, ++ {"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME}, ++ {"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH}, ++ {"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY}, ++ {"NT_STATUS_DEVICE_DOES_NOT_EXIST", ++ NT_STATUS_DEVICE_DOES_NOT_EXIST}, ++ {"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS}, ++ {"NT_STATUS_ADAPTER_HARDWARE_ERROR", ++ NT_STATUS_ADAPTER_HARDWARE_ERROR}, ++ {"NT_STATUS_INVALID_NETWORK_RESPONSE", ++ NT_STATUS_INVALID_NETWORK_RESPONSE}, ++ {"NT_STATUS_UNEXPECTED_NETWORK_ERROR", ++ NT_STATUS_UNEXPECTED_NETWORK_ERROR}, ++ {"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER}, ++ {"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL}, ++ {"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE}, ++ {"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED}, ++ {"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED}, ++ {"NT_STATUS_NETWORK_ACCESS_DENIED", ++ NT_STATUS_NETWORK_ACCESS_DENIED}, ++ {"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE}, ++ {"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME}, ++ {"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES}, ++ {"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS}, ++ {"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED}, ++ {"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED}, ++ {"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED}, ++ {"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT}, ++ {"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT}, ++ {"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE}, ++ {"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED}, ++ {"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", ++ NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, ++ {"NT_STATUS_NO_SECURITY_ON_OBJECT", ++ NT_STATUS_NO_SECURITY_ON_OBJECT}, ++ {"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT}, ++ {"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY}, ++ {"NT_STATUS_CANT_ACCESS_DOMAIN_INFO", ++ NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, ++ {"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF}, ++ {"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE}, ++ {"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE}, ++ {"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE}, ++ {"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN}, ++ {"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS}, ++ {"NT_STATUS_DOMAIN_LIMIT_EXCEEDED", ++ NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, ++ {"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED}, ++ {"NT_STATUS_INVALID_OPLOCK_PROTOCOL", ++ NT_STATUS_INVALID_OPLOCK_PROTOCOL}, ++ {"NT_STATUS_INTERNAL_DB_CORRUPTION", ++ NT_STATUS_INTERNAL_DB_CORRUPTION}, ++ {"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR}, ++ {"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED}, ++ {"NT_STATUS_BAD_DESCRIPTOR_FORMAT", ++ NT_STATUS_BAD_DESCRIPTOR_FORMAT}, ++ {"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER}, ++ {"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR}, ++ {"NT_STATUS_UNEXPECTED_MM_CREATE_ERR", ++ NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, ++ {"NT_STATUS_UNEXPECTED_MM_MAP_ERROR", ++ NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, ++ {"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", ++ NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, ++ {"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS}, ++ {"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS}, ++ {"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1}, ++ {"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2}, ++ {"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3}, ++ {"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4}, ++ {"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5}, ++ {"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6}, ++ {"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7}, ++ {"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8}, ++ {"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9}, ++ {"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10}, ++ {"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11}, ++ {"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12}, ++ {"NT_STATUS_REDIRECTOR_NOT_STARTED", ++ NT_STATUS_REDIRECTOR_NOT_STARTED}, ++ {"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED}, ++ {"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW}, ++ {"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE}, ++ {"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE}, ++ {"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY}, ++ {"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR}, ++ {"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY}, ++ {"NT_STATUS_BAD_LOGON_SESSION_STATE", ++ NT_STATUS_BAD_LOGON_SESSION_STATE}, ++ {"NT_STATUS_LOGON_SESSION_COLLISION", ++ NT_STATUS_LOGON_SESSION_COLLISION}, ++ {"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG}, ++ {"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN}, ++ {"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE}, ++ {"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND}, ++ {"NT_STATUS_PROCESS_IS_TERMINATING", ++ NT_STATUS_PROCESS_IS_TERMINATING}, ++ {"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE}, ++ {"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION}, ++ {"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE}, ++ {"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED}, ++ {"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT}, ++ {"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST}, ++ {"NT_STATUS_ABIOS_LID_ALREADY_OWNED", ++ NT_STATUS_ABIOS_LID_ALREADY_OWNED}, ++ {"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER}, ++ {"NT_STATUS_ABIOS_INVALID_COMMAND", ++ NT_STATUS_ABIOS_INVALID_COMMAND}, ++ {"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID}, ++ {"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", ++ NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, ++ {"NT_STATUS_ABIOS_INVALID_SELECTOR", ++ NT_STATUS_ABIOS_INVALID_SELECTOR}, ++ {"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT}, ++ {"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE}, ++ {"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET}, ++ {"NT_STATUS_INVALID_LDT_DESCRIPTOR", ++ NT_STATUS_INVALID_LDT_DESCRIPTOR}, ++ {"NT_STATUS_INVALID_IMAGE_NE_FORMAT", ++ NT_STATUS_INVALID_IMAGE_NE_FORMAT}, ++ {"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE}, ++ {"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE}, ++ {"NT_STATUS_MAPPED_FILE_SIZE_ZERO", ++ NT_STATUS_MAPPED_FILE_SIZE_ZERO}, ++ {"NT_STATUS_TOO_MANY_OPENED_FILES", ++ NT_STATUS_TOO_MANY_OPENED_FILES}, ++ {"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED}, ++ {"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE}, ++ {"NT_STATUS_INVALID_COMPUTER_NAME", ++ NT_STATUS_INVALID_COMPUTER_NAME}, ++ {"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED}, ++ {"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT}, ++ {"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP}, ++ {"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER}, ++ {"NT_STATUS_MEMBERS_PRIMARY_GROUP", ++ NT_STATUS_MEMBERS_PRIMARY_GROUP}, ++ {"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED}, ++ {"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS}, ++ {"NT_STATUS_THREAD_NOT_IN_PROCESS", ++ NT_STATUS_THREAD_NOT_IN_PROCESS}, ++ {"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE}, ++ {"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", ++ NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, ++ {"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT}, ++ {"NT_STATUS_INVALID_IMAGE_LE_FORMAT", ++ NT_STATUS_INVALID_IMAGE_LE_FORMAT}, ++ {"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ}, ++ {"NT_STATUS_INVALID_IMAGE_PROTECT", ++ NT_STATUS_INVALID_IMAGE_PROTECT}, ++ {"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16}, ++ {"NT_STATUS_LOGON_SERVER_CONFLICT", ++ NT_STATUS_LOGON_SERVER_CONFLICT}, ++ {"NT_STATUS_TIME_DIFFERENCE_AT_DC", ++ NT_STATUS_TIME_DIFFERENCE_AT_DC}, ++ {"NT_STATUS_SYNCHRONIZATION_REQUIRED", ++ NT_STATUS_SYNCHRONIZATION_REQUIRED}, ++ {"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND}, ++ {"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED}, ++ {"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED}, ++ {"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND}, ++ {"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND}, ++ {"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT}, ++ {"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT}, ++ {"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT}, ++ {"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES}, ++ {"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED}, ++ {"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT}, ++ {"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION}, ++ {"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS}, ++ {"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED}, ++ {"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE}, ++ {"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION}, ++ {"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE}, ++ {"NT_STATUS_PAGEFILE_CREATE_FAILED", ++ NT_STATUS_PAGEFILE_CREATE_FAILED}, ++ {"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE}, ++ {"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL}, ++ {"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE}, ++ {"NT_STATUS_ILLEGAL_FLOAT_CONTEXT", ++ NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, ++ {"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN}, ++ {"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT}, ++ {"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED}, ++ {"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR}, ++ {"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME}, ++ {"NT_STATUS_SERIAL_NO_DEVICE_INITED", ++ NT_STATUS_SERIAL_NO_DEVICE_INITED}, ++ {"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS}, ++ {"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS}, ++ {"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS}, ++ {"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS}, ++ {"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED}, ++ {"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS}, ++ {"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG}, ++ {"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR}, ++ {"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE}, ++ {"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS}, ++ {"NT_STATUS_LOGON_TYPE_NOT_GRANTED", ++ NT_STATUS_LOGON_TYPE_NOT_GRANTED}, ++ {"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE}, ++ {"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", ++ NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, ++ {"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", ++ NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, ++ {"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER}, ++ {"NT_STATUS_ILL_FORMED_SERVICE_ENTRY", ++ NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, ++ {"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER}, ++ {"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER}, ++ {"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER}, ++ {"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME}, ++ {"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", ++ NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, ++ {"NT_STATUS_FLOPPY_WRONG_CYLINDER", ++ NT_STATUS_FLOPPY_WRONG_CYLINDER}, ++ {"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR}, ++ {"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS}, ++ {"NT_STATUS_DISK_RECALIBRATE_FAILED", ++ NT_STATUS_DISK_RECALIBRATE_FAILED}, ++ {"NT_STATUS_DISK_OPERATION_FAILED", ++ NT_STATUS_DISK_OPERATION_FAILED}, ++ {"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED}, ++ {"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY}, ++ {"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING}, ++ {"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE}, ++ {"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH}, ++ {"NT_STATUS_DEVICE_NOT_PARTITIONED", ++ NT_STATUS_DEVICE_NOT_PARTITIONED}, ++ {"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA}, ++ {"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", ++ NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, ++ {"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW}, ++ {"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA}, ++ {"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER}, ++ {"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER}, ++ {"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED}, ++ {"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE}, ++ {"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS}, ++ {"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", ++ NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, ++ {"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN}, ++ {"NT_STATUS_CHILD_MUST_BE_VOLATILE", ++ NT_STATUS_CHILD_MUST_BE_VOLATILE}, ++ {"NT_STATUS_DEVICE_CONFIGURATION_ERROR", ++ NT_STATUS_DEVICE_CONFIGURATION_ERROR}, ++ {"NT_STATUS_DRIVER_INTERNAL_ERROR", ++ NT_STATUS_DRIVER_INTERNAL_ERROR}, ++ {"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE}, ++ {"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR}, ++ {"NT_STATUS_DEVICE_PROTOCOL_ERROR", ++ NT_STATUS_DEVICE_PROTOCOL_ERROR}, ++ {"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER}, ++ {"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL}, ++ {"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE}, ++ {"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET}, ++ {"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT}, ++ {"NT_STATUS_TRUSTED_DOMAIN_FAILURE", ++ NT_STATUS_TRUSTED_DOMAIN_FAILURE}, ++ {"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", ++ NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, ++ {"NT_STATUS_EVENTLOG_FILE_CORRUPT", ++ NT_STATUS_EVENTLOG_FILE_CORRUPT}, ++ {"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START}, ++ {"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE}, ++ {"NT_STATUS_MUTANT_LIMIT_EXCEEDED", ++ NT_STATUS_MUTANT_LIMIT_EXCEEDED}, ++ {"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED}, ++ {"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED}, ++ {"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK}, ++ {"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", ++ NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, ++ {"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT}, ++ {"NT_STATUS_EVENTLOG_FILE_CHANGED", ++ NT_STATUS_EVENTLOG_FILE_CHANGED}, ++ {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", ++ NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, ++ {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", ++ NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, ++ {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", ++ NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, ++ {"NT_STATUS_DOMAIN_TRUST_INCONSISTENT", ++ NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, ++ {"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED}, ++ {"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY}, ++ {"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED}, ++ {"NT_STATUS_RESOURCE_LANG_NOT_FOUND", ++ NT_STATUS_RESOURCE_LANG_NOT_FOUND}, ++ {"NT_STATUS_INSUFF_SERVER_RESOURCES", ++ NT_STATUS_INSUFF_SERVER_RESOURCES}, ++ {"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE}, ++ {"NT_STATUS_INVALID_ADDRESS_COMPONENT", ++ NT_STATUS_INVALID_ADDRESS_COMPONENT}, ++ {"NT_STATUS_INVALID_ADDRESS_WILDCARD", ++ NT_STATUS_INVALID_ADDRESS_WILDCARD}, ++ {"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES}, ++ {"NT_STATUS_ADDRESS_ALREADY_EXISTS", ++ NT_STATUS_ADDRESS_ALREADY_EXISTS}, ++ {"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED}, ++ {"NT_STATUS_CONNECTION_DISCONNECTED", ++ NT_STATUS_CONNECTION_DISCONNECTED}, ++ {"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET}, ++ {"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES}, ++ {"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED}, ++ {"NT_STATUS_TRANSACTION_TIMED_OUT", ++ NT_STATUS_TRANSACTION_TIMED_OUT}, ++ {"NT_STATUS_TRANSACTION_NO_RELEASE", ++ NT_STATUS_TRANSACTION_NO_RELEASE}, ++ {"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH}, ++ {"NT_STATUS_TRANSACTION_RESPONDED", ++ NT_STATUS_TRANSACTION_RESPONDED}, ++ {"NT_STATUS_TRANSACTION_INVALID_ID", ++ NT_STATUS_TRANSACTION_INVALID_ID}, ++ {"NT_STATUS_TRANSACTION_INVALID_TYPE", ++ NT_STATUS_TRANSACTION_INVALID_TYPE}, ++ {"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION}, ++ {"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION}, ++ {"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", ++ NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, ++ {"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED}, ++ {"NT_STATUS_SYSTEM_PROCESS_TERMINATED", ++ NT_STATUS_SYSTEM_PROCESS_TERMINATED}, ++ {"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED}, ++ {"NT_STATUS_NO_BROWSER_SERVERS_FOUND", ++ NT_STATUS_NO_BROWSER_SERVERS_FOUND}, ++ {"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR}, ++ {"NT_STATUS_DRIVER_CANCEL_TIMEOUT", ++ NT_STATUS_DRIVER_CANCEL_TIMEOUT}, ++ {"NT_STATUS_REPLY_MESSAGE_MISMATCH", ++ NT_STATUS_REPLY_MESSAGE_MISMATCH}, ++ {"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT}, ++ {"NT_STATUS_IMAGE_CHECKSUM_MISMATCH", ++ NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, ++ {"NT_STATUS_LOST_WRITEBEHIND_DATA", ++ NT_STATUS_LOST_WRITEBEHIND_DATA}, ++ {"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", ++ NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, ++ {"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE}, ++ {"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND}, ++ {"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM}, ++ {"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE}, ++ {"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ}, ++ {"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK}, ++ {"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID}, ++ {"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS}, ++ {"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE}, ++ {"NT_STATUS_RETRY", NT_STATUS_RETRY}, ++ {"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE}, ++ {"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET}, ++ {"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND}, ++ {"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW}, ++ {"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT}, ++ {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", ++ NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, ++ {"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT}, ++ {"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE}, ++ {"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED}, ++ {"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT}, ++ {"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", ++ NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, ++ {"NT_STATUS_ADDRESS_NOT_ASSOCIATED", ++ NT_STATUS_ADDRESS_NOT_ASSOCIATED}, ++ {"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID}, ++ {"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE}, ++ {"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE}, ++ {"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE}, ++ {"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE}, ++ {"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE}, ++ {"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED}, ++ {"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED}, ++ {"NT_STATUS_BAD_COMPRESSION_BUFFER", ++ NT_STATUS_BAD_COMPRESSION_BUFFER}, ++ {"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE}, ++ {"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED}, ++ {"NT_STATUS_TIMER_RESOLUTION_NOT_SET", ++ NT_STATUS_TIMER_RESOLUTION_NOT_SET}, ++ {"NT_STATUS_CONNECTION_COUNT_LIMIT", ++ NT_STATUS_CONNECTION_COUNT_LIMIT}, ++ {"NT_STATUS_LOGIN_TIME_RESTRICTION", ++ NT_STATUS_LOGIN_TIME_RESTRICTION}, ++ {"NT_STATUS_LOGIN_WKSTA_RESTRICTION", ++ NT_STATUS_LOGIN_WKSTA_RESTRICTION}, ++ {"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH}, ++ {"NT_STATUS_INSUFFICIENT_LOGON_INFO", ++ NT_STATUS_INSUFFICIENT_LOGON_INFO}, ++ {"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT}, ++ {"NT_STATUS_BAD_SERVICE_ENTRYPOINT", ++ NT_STATUS_BAD_SERVICE_ENTRYPOINT}, ++ {"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST}, ++ {"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1}, ++ {"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2}, ++ {"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT}, ++ {"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED}, ++ {"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE}, ++ {"NT_STATUS_LICENSE_QUOTA_EXCEEDED", ++ NT_STATUS_LICENSE_QUOTA_EXCEEDED}, ++ {"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT}, ++ {"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT}, ++ {"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT}, ++ {"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE}, ++ {"NT_STATUS_UNSUPPORTED_COMPRESSION", ++ NT_STATUS_UNSUPPORTED_COMPRESSION}, ++ {"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE}, ++ {"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", ++ NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, ++ {"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", ++ NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, ++ {"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", ++ NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, ++ {"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED}, ++ {"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS}, ++ {"NT_STATUS_QUOTA_LIST_INCONSISTENT", ++ NT_STATUS_QUOTA_LIST_INCONSISTENT}, ++ {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE}, ++ {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES}, ++ {"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES}, ++ {"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED}, ++ {NULL, 0} ++}; +diff -urN linux-2.4.29.old/fs/cifs/nterr.h linux-2.4.29/fs/cifs/nterr.h +--- linux-2.4.29.old/fs/cifs/nterr.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/nterr.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,556 @@ ++/* ++ Unix SMB/Netbios implementation. ++ Version 1.9. ++ NT error code constants ++ Copyright (C) Andrew Tridgell 1992-2000 ++ Copyright (C) John H Terpstra 1996-2000 ++ Copyright (C) Luke Kenneth Casson Leighton 1996-2000 ++ Copyright (C) Paul Ashton 1998-2000 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++ ++ ++#ifndef _NTERR_H ++#define _NTERR_H ++ ++struct nt_err_code_struct { ++ char *nt_errstr; ++ __u32 nt_errcode; ++}; ++ ++extern const struct nt_err_code_struct nt_errs[]; ++ ++/* Win32 Status codes. */ ++ ++#define STATUS_BUFFER_OVERFLOW 0x80000005 ++#define STATUS_MORE_ENTRIES 0x0105 ++#define ERROR_INVALID_PARAMETER 0x0057 ++#define ERROR_INSUFFICIENT_BUFFER 0x007a ++#define STATUS_1804 0x070c ++#define STATUS_NOTIFY_ENUM_DIR 0x010c ++ ++/* Win32 Error codes extracted using a loop in smbclient then printing a ++ netmon sniff to a file. */ ++ ++#define NT_STATUS_OK 0x0000 ++#define STATUS_SOME_UNMAPPED 0x0107 ++#define STATUS_BUFFER_OVERFLOW 0x80000005 ++#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a ++#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001 ++#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002 ++#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003 ++#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004 ++#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005 ++#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006 ++#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007 ++#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008 ++#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009 ++#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a ++#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b ++#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c ++#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d ++#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e ++#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f ++#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010 ++#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011 ++#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012 ++#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013 ++#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014 ++#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015 ++#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016 ++#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017 ++#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018 ++#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019 ++#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a ++#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b ++#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c ++#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d ++#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e ++#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f ++#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020 ++#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021 ++#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022 ++#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023 ++#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024 ++#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025 ++#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026 ++#define NT_STATUS_UNWIND 0xC0000000 | 0x0027 ++#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028 ++#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029 ++#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a ++#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b ++#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c ++#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d ++#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e ++#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f ++#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030 ++#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031 ++#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032 ++#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033 ++#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034 ++#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035 ++#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036 ++#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037 ++#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038 ++#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039 ++#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a ++#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b ++#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c ++#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d ++#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e ++#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f ++#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040 ++#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041 ++#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042 ++#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043 ++#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044 ++#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045 ++#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046 ++#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047 ++#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048 ++#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049 ++#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a ++#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b ++#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c ++#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d ++#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e ++#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f ++#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050 ++#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051 ++#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052 ++#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053 ++#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054 ++#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055 ++#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056 ++#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057 ++#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058 ++#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059 ++#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a ++#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b ++#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c ++#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d ++#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e ++#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f ++#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060 ++#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061 ++#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062 ++#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063 ++#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064 ++#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065 ++#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066 ++#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067 ++#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068 ++#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069 ++#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a ++#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b ++#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c ++#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d ++#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e ++#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f ++#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070 ++#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071 ++#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072 ++#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073 ++#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074 ++#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075 ++#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076 ++#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077 ++#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078 ++#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079 ++#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a ++#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b ++#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c ++#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d ++#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e ++#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f ++#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080 ++#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081 ++#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082 ++#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083 ++#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084 ++#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085 ++#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086 ++#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087 ++#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088 ++#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089 ++#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a ++#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b ++#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c ++#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d ++#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e ++#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f ++#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090 ++#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091 ++#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092 ++#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093 ++#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094 ++#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095 ++#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096 ++#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097 ++#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098 ++#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099 ++#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a ++#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b ++#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c ++#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d ++#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e ++#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f ++#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0 ++#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1 ++#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2 ++#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3 ++#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4 ++#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5 ++#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6 ++#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7 ++#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8 ++#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9 ++#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa ++#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab ++#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac ++#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad ++#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae ++#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af ++#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0 ++#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1 ++#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2 ++#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3 ++#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4 ++#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5 ++#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6 ++#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7 ++#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8 ++#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9 ++#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba ++#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb ++#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc ++#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd ++#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be ++#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf ++#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0 ++#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1 ++#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2 ++#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3 ++#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4 ++#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5 ++#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6 ++#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7 ++#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8 ++#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9 ++#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca ++#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb ++#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc ++#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd ++#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce ++#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf ++#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0 ++#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1 ++#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2 ++#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3 ++#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4 ++#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5 ++#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6 ++#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7 ++#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8 ++#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9 ++#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da ++#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db ++#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc ++#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd ++#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de ++#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df ++#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0 ++#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1 ++#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2 ++#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3 ++#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4 ++#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5 ++#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6 ++#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7 ++#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8 ++#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9 ++#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea ++#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb ++#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec ++#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed ++#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee ++#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef ++#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0 ++#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1 ++#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2 ++#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3 ++#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4 ++#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5 ++#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6 ++#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7 ++#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8 ++#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9 ++#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa ++#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb ++#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc ++#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd ++#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe ++#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff ++#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101 ++#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102 ++#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103 ++#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104 ++#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105 ++#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106 ++#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107 ++#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108 ++#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109 ++#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a ++#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b ++#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c ++#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d ++#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e ++#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f ++#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110 ++#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111 ++#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112 ++#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113 ++#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114 ++#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115 ++#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116 ++#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117 ++#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118 ++#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119 ++#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a ++#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b ++#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c ++#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d ++#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e ++#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f ++#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120 ++#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121 ++#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122 ++#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123 ++#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124 ++#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125 ++#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126 ++#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127 ++#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128 ++#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129 ++#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a ++#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b ++#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c ++#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d ++#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e ++#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f ++#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130 ++#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131 ++#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132 ++#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133 ++#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134 ++#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135 ++#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136 ++#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137 ++#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138 ++#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139 ++#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a ++#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b ++#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c ++#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d ++#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e ++#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f ++#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140 ++#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141 ++#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142 ++#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143 ++#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144 ++#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145 ++#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146 ++#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147 ++#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148 ++#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149 ++#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a ++#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b ++#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c ++#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d ++#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e ++#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f ++#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150 ++#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151 ++#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152 ++#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153 ++#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154 ++#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155 ++#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156 ++#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157 ++#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158 ++#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159 ++#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a ++#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b ++#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c ++#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d ++#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e ++#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f ++#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160 ++#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161 ++#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162 ++#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163 ++#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164 ++#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165 ++#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166 ++#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167 ++#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168 ++#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169 ++#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a ++#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b ++#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c ++#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d ++#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172 ++#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173 ++#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174 ++#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175 ++#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176 ++#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177 ++#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178 ++#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a ++#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b ++#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c ++#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d ++#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e ++#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f ++#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180 ++#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181 ++#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182 ++#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183 ++#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184 ++#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185 ++#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186 ++#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187 ++#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188 ++#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189 ++#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a ++#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b ++#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c ++#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d ++#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e ++#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f ++#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190 ++#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191 ++#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192 ++#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193 ++#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194 ++#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195 ++#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196 ++#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197 ++#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198 ++#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199 ++#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a ++#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b ++#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c ++#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202 ++#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203 ++#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204 ++#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205 ++#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206 ++#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207 ++#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208 ++#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209 ++#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a ++#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b ++#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c ++#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d ++#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e ++#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f ++#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210 ++#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211 ++#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212 ++#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213 ++#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214 ++#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215 ++#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216 ++#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217 ++#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218 ++#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219 ++#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a ++#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b ++#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c ++#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d ++#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e ++#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f ++#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220 ++#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221 ++#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222 ++#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223 ++#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224 ++#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225 ++#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226 ++#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227 ++#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228 ++#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229 ++#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a ++#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b ++#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c ++#define NT_STATUS_RETRY 0xC0000000 | 0x022d ++#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e ++#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f ++#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230 ++#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231 ++#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232 ++#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233 ++#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234 ++#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235 ++#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236 ++#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237 ++#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238 ++#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239 ++#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a ++#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b ++#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c ++#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d ++#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e ++#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f ++#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240 ++#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241 ++#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242 ++#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243 ++#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244 ++#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245 ++#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246 ++#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247 ++#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248 ++#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249 ++#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250 ++#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251 ++#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252 ++#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253 ++#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254 ++#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255 ++#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256 ++#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257 ++#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258 ++#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259 ++#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a ++#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b ++#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c ++#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e ++#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f ++#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260 ++#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261 ++#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262 ++#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263 ++#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264 ++#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265 ++#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266 ++#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267 ++#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */ ++ ++#endif /* _NTERR_H */ +diff -urN linux-2.4.29.old/fs/cifs/ntlmssp.h linux-2.4.29/fs/cifs/ntlmssp.h +--- linux-2.4.29.old/fs/cifs/ntlmssp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/ntlmssp.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,101 @@ ++/* ++ * fs/cifs/ntlmssp.h ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#pragma pack(1) ++ ++#define NTLMSSP_SIGNATURE "NTLMSSP" ++/* Message Types */ ++#define NtLmNegotiate 1 ++#define NtLmChallenge 2 ++#define NtLmAuthenticate 3 ++#define UnknownMessage 8 ++ ++/* Negotiate Flags */ ++#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode ++#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM ++#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm ++#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability ++#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality ++#define NTLMSSP_NEGOTIATE_DGRAM 0x0040 ++#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal ++#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication ++#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000 ++#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000 ++#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine ++#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels ++#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000 ++#define NTLMSSP_TARGET_TYPE_SERVER 0x20000 ++#define NTLMSSP_TARGET_TYPE_SHARE 0x40000 ++#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000 ++#define NTLMSSP_REQUEST_INIT_RESP 0x100000 ++#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000 ++#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000 ++#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000 ++#define NTLMSSP_NEGOTIATE_128 0x20000000 ++#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000 ++#define NTLMSSP_NEGOTIATE_56 0x80000000 ++ ++/* Although typedefs are not commonly used for structure definitions */ ++/* in the Linux kernel, in this particular case they are useful */ ++/* to more closely match the standards document for NTLMSSP from */ ++/* OpenGroup and to make the code more closely match the standard in */ ++/* appearance */ ++ ++typedef struct _SECURITY_BUFFER { ++ __u16 Length; ++ __u16 MaximumLength; ++ __u32 Buffer; /* offset to buffer */ ++} SECURITY_BUFFER; ++ ++typedef struct _NEGOTIATE_MESSAGE { ++ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; ++ __u32 MessageType; /* 1 */ ++ __u32 NegotiateFlags; ++ SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */ ++ SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ ++ char DomainString[0]; ++ /* followed by WorkstationString */ ++} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; ++ ++typedef struct _CHALLENGE_MESSAGE { ++ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; ++ __u32 MessageType; /* 2 */ ++ SECURITY_BUFFER TargetName; ++ __u32 NegotiateFlags; ++ __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; ++ __u8 Reserved[8]; ++ SECURITY_BUFFER TargetInfoArray; ++} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; ++ ++typedef struct _AUTHENTICATE_MESSAGE { ++ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; ++ __u32 MessageType; /* 3 */ ++ SECURITY_BUFFER LmChallengeResponse; ++ SECURITY_BUFFER NtChallengeResponse; ++ SECURITY_BUFFER DomainName; ++ SECURITY_BUFFER UserName; ++ SECURITY_BUFFER WorkstationName; ++ SECURITY_BUFFER SessionKey; ++ __u32 NegotiateFlags; ++ char UserString[0]; ++} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; ++ ++#pragma pack() /* resume default structure packing */ +diff -urN linux-2.4.29.old/fs/cifs/README linux-2.4.29/fs/cifs/README +--- linux-2.4.29.old/fs/cifs/README 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/README 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,356 @@ ++The CIFS VFS support for Linux supports many advanced network filesystem ++features such as heirarchical dfs like namespace, hardlinks, locking and more. ++It was designed to comply with the SNIA CIFS Technical Reference (which ++supersedes the 1992 X/Open SMB Standard) as well as to perform best practice ++practical interoperability with Windows 2000, Windows XP, Samba and equivalent ++servers. ++ ++For questions or bug reports please contact: ++ sfrench@samba.org (sfrench@us.ibm.com) ++ ++Build instructions: ++================== ++For Linux 2.4: ++1) Get the kernel source (e.g.from http://www.kernel.org) ++and download the cifs vfs source (see the project page ++at http://us1.samba.org/samba/Linux_CIFS_client.html) ++and change directory into the top of the kernel directory ++then patch the kernel (e.g. "patch -p1 < cifs_24.patch") ++to add the cifs vfs to your kernel configure options if ++it has not already been added (e.g. current SuSE and UL ++users do not need to apply the cifs_24.patch since the cifs vfs is ++already in the kernel configure menu) and then ++mkdir linux/fs/cifs and then copy the current cifs vfs files from ++the cifs download to your kernel build directory e.g. ++ ++ cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs ++ ++2) make menuconfig (or make xconfig) ++3) select cifs from within the network filesystem choices ++4) save and exit ++5) make dep ++6) make modules (or "make" if CIFS VFS not to be built as a module) ++ ++For Linux 2.5: ++1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper ++at bk://linux.bkbits.net/linux-2.5) and change directory into the top ++of the kernel directory tree (e.g. /usr/src/linux-2.5.73) ++2) make menuconfig (or make xconfig) ++3) select cifs from within the network filesystem choices ++4) save and exit ++5) make ++ ++ ++Installation instructions: ++========================= ++If you have built the CIFS vfs as module (successfully) simply ++type "make modules_install" (or if you prefer, manually copy the file to ++the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o). ++ ++If you have built the CIFS vfs into the kernel itself, follow the instructions ++for your distribution on how to install a new kernel (usually you ++would simply type "make install"). ++ ++If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on ++the CIFS VFS web site) copy it to the same directory in which mount.smbfs and ++similar files reside (usually /sbin). Although the helper software is not ++required, mount.cifs is recommended. Eventually the Samba 3.0 utility program ++"net" may also be helpful since it may someday provide easier mount syntax for ++users who are used to Windows e.g. net use <mount point> <UNC name or cifs URL> ++Note that running the Winbind pam/nss module (logon service) on all of your ++Linux clients is useful in mapping Uids and Gids consistently across the ++domain to the proper network user. The mount.cifs mount helper can be ++trivially built from Samba 3.0 or later source e.g. by executing: ++ ++ gcc samba/source/client/mount.cifs.c -o mount.cifs ++ ++Note that when the mount.cifs utility is run suid (allowing user mounts), ++in order to reduce risks, the "nosuid" mount flag is passed in on mount to ++disallow execution of an suid program mounted on the remote target. ++When mount is executed as root, nosuid is not passed in by default, ++and execution of suid programs on the remote target would be enabled ++by default. This can be changed, as with nfs and other filesystems, ++by simply specifying "nosuid" among the mount options. For user mounts ++though to be able to pass the suid flag to mount requires rebuilding ++mount.cifs with the following flag: ++ ++ gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs ++ ++There is a corresponding manual page for cifs mounting in the Samba 3.0 and ++later source tree in docs/manpages/mount.cifs.8 ++ ++Samba Considerations ++==================== ++To get the maximum benefit from the CIFS VFS, we recommend using a server that ++supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or ++Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers. ++Note that uid, gid and file permissions will display default values if you do ++not have a server that supports the Unix extensions for CIFS (such as Samba ++2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add ++the line: ++ ++ unix extensions = yes ++ ++to your smb.conf file on the server. Note that the following smb.conf settings ++are also useful (on the Samba server) when the majority of clients are Unix or ++Linux: ++ ++ case sensitive = yes ++ delete readonly = yes ++ ea support = yes ++ ++Note that ea support is required for supporting Linux xattrs. ++Some administrators also change the "map archive" and the "create mask" ++parameters from their default values. Creating special devices (mknod) ++remotely may require specifying a mkdev function to Samba if you are not using ++Samba 3.0.5 or later. For more information on these see the manual pages ++("man smb.conf") on the Samba server system. Note that the cifs vfs, ++unlike the smbfs vfs, does not read the smb.conf on the client system ++(the few optional settings are passed in on mount via -o parameters instead). ++Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete ++open files (required for strict POSIX compliance). Windows Servers already ++supported this feature. Samba server does not allow symlinks that refer to files ++outside of the share, so in Samba versions prior to 3.0.5, most symlinks to ++files with absolute paths (ie beginning with slash) such as: ++ ln -s /mnt/foo bar ++would be forbidden. Samba 3.0.5 server or later includes the ability to create ++such symlinks safely by converting unsafe symlinks (ie symlinks to server ++files that are outside of the share) to a samba specific format on the server ++that is ignored by local server applications and non-cifs clients and that will ++not be traversed by the Samba server). This is opaque to the Linux client ++application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or ++later, but only for remote clients using the CIFS Unix extensions, and will ++be invisbile to Windows clients and typically will not affect local ++applications running on the same server as Samba. ++ ++Use instructions: ++================ ++Once the CIFS VFS support is built into the kernel or installed as a module ++(cifs.o), you can use mount syntax like the following to access Samba or Windows ++servers: ++ ++ mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword ++ ++Before -o the option -v may be specified to make the mount.cifs ++mount helper display the mount steps more verbosely. ++After -o the following commonly used cifs vfs specific options ++are supported: ++ ++ user=<username> ++ pass=<password> ++ domain=<domain name> ++ ++Other cifs mount options are described below. Use of TCP names (in addition to ++ip addresses) is available if the mount helper (mount.cifs) is installed. If ++you do not trust the server to which are mounted, or if you do not have ++cifs signing enabled (and the physical network is insecure), consider use ++of the standard mount options "noexec" and "nosuid" to reduce the risk of ++running an altered binary on your local system (downloaded from a hostile server ++or altered by a hostile router). ++ ++When using the mount helper mount.cifs, passwords may be specified via alternate ++mechanisms, instead of specifying it after -o using the normal "pass=" syntax ++on the command line: ++1) By including it in a credential file. Specify credentials=filename as one ++of the mount options. Credential files contain two lines ++ username=someuser ++ password=your_password ++2) By specifying the password in the PASSWD environment variable (similarly ++the user name can be taken from the USER environment variable). ++3) By specifying the password in a file by name via PASSWD_FILE ++4) By specifying the password in a file by file descriptor via PASSWD_FD ++ ++If no password is provided, mount.cifs will prompt for password entry ++ ++Restrictions ++============ ++Servers must support the NTLM SMB dialect (which is the most recent, supported ++by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers) ++Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC ++1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a ++problem as most servers support this. IPv6 support is planned for the future. ++ ++CIFS VFS Mount Options ++====================== ++A partial list of the supported mount options follows: ++ user The user name to use when trying to establish ++ the CIFS session. ++ password The user password. If the mount helper is ++ installed, the user will be prompted for password ++ if it is not supplied. ++ ip The ip address of the target server ++ unc The target server Universal Network Name (export) to ++ mount. ++ domain Set the SMB/CIFS workgroup name prepended to the ++ username during CIFS session establishment ++ uid If CIFS Unix extensions are not supported by the server ++ this overrides the default uid for inodes. For mounts to ++ servers which do support the CIFS Unix extensions, such ++ as a properly configured Samba server, the server provides ++ the uid, gid and mode. For servers which do not support ++ the Unix extensions, the default uid (and gid) returned on ++ lookup of existing files is the uid (gid) of the person ++ who executed the mount (root, except when mount.cifs ++ is configured setuid for user mounts) unless the "uid=" ++ (gid) mount option is specified. For the uid (gid) of newly ++ created files and directories, ie files created since ++ the last mount of the server share, the expected uid ++ (gid) is cached as as long as the inode remains in ++ memory on the client. Also note that permission ++ checks (authorization checks) on accesses to a file occur ++ at the server, but there are cases in which an administrator ++ may want to restrict at the client as well. For those ++ servers which do not report a uid/gid owner ++ (such as Windows), permissions can also be checked at the ++ client, and a crude form of client side permission checking ++ can be enabled by specifying file_mode and dir_mode on ++ the client ++ gid If CIFS Unix extensions are not supported by the server ++ this overrides the default gid for inodes. ++ file_mode If CIFS Unix extensions are not supported by the server ++ this overrides the default mode for file inodes. ++ dir_mode If CIFS Unix extensions are not supported by the server ++ this overrides the default mode for directory inodes. ++ port attempt to contact the server on this tcp port, before ++ trying the usual ports (port 445, then 139). ++ iocharset Codepage used to convert local path names to and from ++ Unicode. Unicode is used by default for network path ++ names if the server supports it. If iocharset is ++ not specified then the nls_default specified ++ during the local client kernel build will be used. ++ If server does not support Unicode, this parameter is ++ unused. ++ rsize default read size ++ wsize default write size ++ rw mount the network share read-write (note that the ++ server may still consider the share read-only) ++ ro mount network share read-only ++ version used to distinguish different versions of the ++ mount helper utility (not typically needed) ++ sep if first mount option (after the -o), overrides ++ the comma as the separator between the mount ++ parms. e.g. ++ -o user=myname,password=mypassword,domain=mydom ++ could be passed instead with period as the separator by ++ -o sep=.user=myname.password=mypassword.domain=mydom ++ this might be useful when comma is contained within username ++ or password or domain. This option is less important ++ when the cifs mount helper cifs.mount (version 1.1 or later) ++ is used. ++ nosuid Do not allow remote executables with the suid bit ++ program to be executed. This is only meaningful for mounts ++ to servers such as Samba which support the CIFS Unix Extensions. ++ If you do not trust the servers in your network (your mount ++ targets) it is recommended that you specify this option for ++ greater security. ++ suid Allow remote files on this mountpoint with suid enabled to ++ be executed (default for mounts when executed as root, ++ nosuid is default for user mounts). ++ credentials Although ignored by the cifs kernel component, it is used by ++ the mount helper, mount.cifs. When mount.cifs is installed it ++ opens and reads the credential file specified in order ++ to obtain the userid and password arguments which are passed to ++ the cifs vfs. ++ guest Although ignored by the kernel component, the mount.cifs ++ mount helper will not prompt the user for a password ++ if guest is specified on the mount options. If no ++ password is specified a null password will be used. ++ ++The mount.cifs mount helper also accepts a few mount options before -o ++including: ++ ++ -S take password from stdin (equivalent to setting the environment ++ variable "PASSWD_FD=0" ++ -V print mount.cifs version ++ -? display simple usage information ++ ++With recent 2.6 kernel versions of modutils, the version of the cifs kernel ++module can be displayed via modinfo. ++ ++Misc /proc/fs/cifs Flags and Debug Info ++======================================= ++Informational pseudo-files: ++DebugData Displays information about active CIFS sessions ++ and shares. ++Stats Lists summary resource usage information as well as per ++ share statistics, if CONFIG_CIFS_STATS in enabled ++ in the kernel configuration. ++ ++Configuration pseudo-files: ++MultiuserMount If set to one, more than one CIFS session to ++ the same server ip address can be established ++ if more than one uid accesses the same mount ++ point and if the uids user/password mapping ++ information is available. (default is 0) ++PacketSigningEnabled If set to one, cifs packet signing is enabled ++ and will be used if the server requires ++ it. If set to two, cifs packet signing is ++ required even if the server considers packet ++ signing optional. (default 1) ++cifsFYI If set to one, additional debug information is ++ logged to the system error log. (default 0) ++ExtendedSecurity If set to one, SPNEGO session establishment ++ is allowed which enables more advanced ++ secure CIFS session establishment (default 0) ++NTLMV2Enabled If set to one, more secure password hashes ++ are used when the server supports them and ++ when kerberos is not negotiated (default 0) ++traceSMB If set to one, debug information is logged to the ++ system error log with the start of smb requests ++ and responses (default 0) ++LookupCacheEnable If set to one, inode information is kept cached ++ for one second improving performance of lookups ++ (default 1) ++OplockEnabled If set to one, safe distributed caching enabled. ++ (default 1) ++LinuxExtensionsEnabled If set to one then the client will attempt to ++ use the CIFS "UNIX" extensions which are optional ++ protocol enhancements that allow CIFS servers ++ to return accurate UID/GID information as well ++ as support symbolic links. If you use servers ++ such as Samba that support the CIFS Unix ++ extensions but do not want to use symbolic link ++ support and want to map the uid and gid fields ++ to values supplied at mount (rather than the ++ actual values, then set this to zero. (default 1) ++ ++These experimental features and tracing can be enabled by changing flags in ++/proc/fs/cifs (after the cifs module has been installed or built into the ++kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable ++tracing to the kernel message log type: ++ ++ echo 1 > /proc/fs/cifs/cifsFYI ++ ++and for more extensive tracing including the start of smb requests and responses ++ ++ echo 1 > /proc/fs/cifs/traceSMB ++ ++Three other experimental features are under development and to test ++require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h) ++ ++ CONFIG_CIFS_QUOTA ++ ++ CONFIG_CIFS_XATTR ++ ++ CONFIG_CIFS_FCNTL (fcntl needed for support of directory change ++ notification and perhaps later for file leases) ++ ++Per share (per client mount) statistics are available in /proc/fs/cifs/DebugData ++if the kernel was configured with cifs statistics enabled. The statistics ++represent the number of successful (ie non-zero return code from the server) ++SMB responses to some of the more common commands (open, delete, mkdir etc.). ++Also recorded is the total bytes read and bytes written to the server for ++that share. Note that due to client caching effects this can be less than the ++number of bytes read and written by the application running on the client. ++The statistics for the number of total SMBs and oplock breaks are different in ++that they represent all for that share, not just those for which the server ++returned success. ++ ++Also note that "cat /proc/fs/cifs/DebugData" will display information about ++the active sessions and the shares that are mounted. Note: NTLMv2 enablement ++will not work since they its implementation is not quite complete yet. ++Do not alter these configuration values unless you are doing specific testing. ++Enabling extended security works to Windows 2000 Workstations and XP but not to ++Windows 2000 server or Samba since it does not usually send "raw NTLMSSP" ++(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not ++complete in the CIFS VFS yet). +diff -urN linux-2.4.29.old/fs/cifs/rfc1002pdu.h linux-2.4.29/fs/cifs/rfc1002pdu.h +--- linux-2.4.29.old/fs/cifs/rfc1002pdu.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/rfc1002pdu.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,79 @@ ++/* ++ * fs/cifs/rfc1002pdu.h ++ * ++ * Protocol Data Unit definitions for RFC 1001/1002 support ++ * ++ * Copyright (c) International Business Machines Corp., 2004 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#pragma pack(1) ++ ++/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ ++ ++ /* RFC 1002 session packet types */ ++#define RFC1002_SESSION_MESASAGE 0x00 ++#define RFC1002_SESSION_REQUEST 0x81 ++#define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 ++#define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 ++#define RFC1002_RETARGET_SESSION_RESPONSE 0x83 ++#define RFC1002_SESSION_KEEP_ALIVE 0x85 ++ ++ /* RFC 1002 flags (only one defined */ ++#define RFC1002_LENGTH_EXTEND 0x80 /* high order bit of length (ie +64K) */ ++ ++struct rfc1002_session_packet { ++ __u8 type; ++ __u8 flags; ++ __u16 length; ++ union { ++ struct { ++ __u8 called_len; ++ __u8 called_name[32]; ++ __u8 scope1; /* null */ ++ __u8 calling_len; ++ __u8 calling_name[32]; ++ __u8 scope2; /* null */ ++ } session_req; ++ struct { ++ __u32 retarget_ip_addr; ++ __u16 port; ++ } retarget_resp; ++ __u8 neg_ses_resp_error_code; ++ /* POSITIVE_SESSION_RESPONSE packet does not include trailer. ++ SESSION_KEEP_ALIVE packet also does not include a trailer. ++ Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ ++ } trailer; ++}; ++ ++/* Negative Session Response error codes */ ++#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ ++#define RFC1002_NOT_LISTENING_CALLING 0x81 /* not listening on calling name */ ++#define RFC1002_NOT_PRESENT 0x82 /* called name not present */ ++#define RFC1002_INSUFFICIENT_RESOURCE 0x83 ++#define RFC1002_UNSPECIFIED_ERROR 0x8F ++ ++/* RFC 1002 Datagram service packets are not defined here as they ++are not needed for the network filesystem client unless we plan on ++implementing broadcast resolution of the server ip address (from ++server netbios name). Currently server names are resolved only via DNS ++(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ ++ ++#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " ++ ++#pragma pack() /* resume default structure packing */ ++ +diff -urN linux-2.4.29.old/fs/cifs/smbdes.c linux-2.4.29/fs/cifs/smbdes.c +--- linux-2.4.29.old/fs/cifs/smbdes.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/smbdes.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,408 @@ ++/* ++ Unix SMB/Netbios implementation. ++ Version 1.9. ++ ++ a partial implementation of DES designed for use in the ++ SMB authentication protocol ++ ++ Copyright (C) Andrew Tridgell 1998 ++ Modified by Steve French (sfrench@us.ibm.com) 2002,2004 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++/* NOTES: ++ ++ This code makes no attempt to be fast! In fact, it is a very ++ slow implementation ++ ++ This code is NOT a complete DES implementation. It implements only ++ the minimum necessary for SMB authentication, as used by all SMB ++ products (including every copy of Microsoft Windows95 ever sold) ++ ++ In particular, it can only do a unchained forward DES pass. This ++ means it is not possible to use this code for encryption/decryption ++ of data, instead it is only useful as a "hash" algorithm. ++ ++ There is no entry point into this code that allows normal DES operation. ++ ++ I believe this means that this code does not come under ITAR ++ regulations but this is NOT a legal opinion. If you are concerned ++ about the applicability of ITAR regulations to this code then you ++ should confirm it for yourself (and maybe let me know if you come ++ up with a different answer to the one above) ++*/ ++#include <linux/slab.h> ++#define uchar unsigned char ++ ++static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9, ++ 1, 58, 50, 42, 34, 26, 18, ++ 10, 2, 59, 51, 43, 35, 27, ++ 19, 11, 3, 60, 52, 44, 36, ++ 63, 55, 47, 39, 31, 23, 15, ++ 7, 62, 54, 46, 38, 30, 22, ++ 14, 6, 61, 53, 45, 37, 29, ++ 21, 13, 5, 28, 20, 12, 4 ++}; ++ ++static uchar perm2[48] = { 14, 17, 11, 24, 1, 5, ++ 3, 28, 15, 6, 21, 10, ++ 23, 19, 12, 4, 26, 8, ++ 16, 7, 27, 20, 13, 2, ++ 41, 52, 31, 37, 47, 55, ++ 30, 40, 51, 45, 33, 48, ++ 44, 49, 39, 56, 34, 53, ++ 46, 42, 50, 36, 29, 32 ++}; ++ ++static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2, ++ 60, 52, 44, 36, 28, 20, 12, 4, ++ 62, 54, 46, 38, 30, 22, 14, 6, ++ 64, 56, 48, 40, 32, 24, 16, 8, ++ 57, 49, 41, 33, 25, 17, 9, 1, ++ 59, 51, 43, 35, 27, 19, 11, 3, ++ 61, 53, 45, 37, 29, 21, 13, 5, ++ 63, 55, 47, 39, 31, 23, 15, 7 ++}; ++ ++static uchar perm4[48] = { 32, 1, 2, 3, 4, 5, ++ 4, 5, 6, 7, 8, 9, ++ 8, 9, 10, 11, 12, 13, ++ 12, 13, 14, 15, 16, 17, ++ 16, 17, 18, 19, 20, 21, ++ 20, 21, 22, 23, 24, 25, ++ 24, 25, 26, 27, 28, 29, ++ 28, 29, 30, 31, 32, 1 ++}; ++ ++static uchar perm5[32] = { 16, 7, 20, 21, ++ 29, 12, 28, 17, ++ 1, 15, 23, 26, ++ 5, 18, 31, 10, ++ 2, 8, 24, 14, ++ 32, 27, 3, 9, ++ 19, 13, 30, 6, ++ 22, 11, 4, 25 ++}; ++ ++static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32, ++ 39, 7, 47, 15, 55, 23, 63, 31, ++ 38, 6, 46, 14, 54, 22, 62, 30, ++ 37, 5, 45, 13, 53, 21, 61, 29, ++ 36, 4, 44, 12, 52, 20, 60, 28, ++ 35, 3, 43, 11, 51, 19, 59, 27, ++ 34, 2, 42, 10, 50, 18, 58, 26, ++ 33, 1, 41, 9, 49, 17, 57, 25 ++}; ++ ++static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; ++ ++static uchar sbox[8][4][16] = { ++ {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, ++ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, ++ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, ++ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}}, ++ ++ {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, ++ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, ++ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, ++ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}}, ++ ++ {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, ++ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, ++ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, ++ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}}, ++ ++ {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, ++ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, ++ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, ++ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}}, ++ ++ {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, ++ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, ++ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, ++ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}}, ++ ++ {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, ++ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, ++ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, ++ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}}, ++ ++ {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, ++ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, ++ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, ++ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}}, ++ ++ {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, ++ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, ++ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, ++ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}} ++}; ++ ++static void ++permute(char *out, char *in, uchar * p, int n) ++{ ++ int i; ++ for (i = 0; i < n; i++) ++ out[i] = in[p[i] - 1]; ++} ++ ++static void ++lshift(char *d, int count, int n) ++{ ++ char out[64]; ++ int i; ++ for (i = 0; i < n; i++) ++ out[i] = d[(i + count) % n]; ++ for (i = 0; i < n; i++) ++ d[i] = out[i]; ++} ++ ++static void ++concat(char *out, char *in1, char *in2, int l1, int l2) ++{ ++ while (l1--) ++ *out++ = *in1++; ++ while (l2--) ++ *out++ = *in2++; ++} ++ ++static void ++xor(char *out, char *in1, char *in2, int n) ++{ ++ int i; ++ for (i = 0; i < n; i++) ++ out[i] = in1[i] ^ in2[i]; ++} ++ ++static void ++dohash(char *out, char *in, char *key, int forw) ++{ ++ int i, j, k; ++ char *pk1; ++ char c[28]; ++ char d[28]; ++ char *cd; ++ char ki[16][48]; ++ char *pd1; ++ char l[32], r[32]; ++ char *rl; ++ ++ /* Have to reduce stack usage */ ++ pk1 = kmalloc(56+56+64+64,GFP_KERNEL); ++ if(pk1 == NULL) ++ return; ++ ++ cd = pk1 + 56; ++ pd1= cd + 56; ++ rl = pd1 + 64; ++ ++ permute(pk1, key, perm1, 56); ++ ++ for (i = 0; i < 28; i++) ++ c[i] = pk1[i]; ++ for (i = 0; i < 28; i++) ++ d[i] = pk1[i + 28]; ++ ++ for (i = 0; i < 16; i++) { ++ lshift(c, sc[i], 28); ++ lshift(d, sc[i], 28); ++ ++ concat(cd, c, d, 28, 28); ++ permute(ki[i], cd, perm2, 48); ++ } ++ ++ permute(pd1, in, perm3, 64); ++ ++ for (j = 0; j < 32; j++) { ++ l[j] = pd1[j]; ++ r[j] = pd1[j + 32]; ++ } ++ ++ for (i = 0; i < 16; i++) { ++ char *er; /* er[48] */ ++ char *erk; /* erk[48] */ ++ char b[8][6]; ++ char *cb; /* cb[32] */ ++ char *pcb; /* pcb[32] */ ++ char *r2; /* r2[32] */ ++ ++ er = kmalloc(48+48+32+32+32, GFP_KERNEL); ++ if(er == NULL) { ++ kfree(pk1); ++ return; ++ } ++ erk = er+48; ++ cb = erk+48; ++ pcb = cb+32; ++ r2 = pcb+32; ++ ++ permute(er, r, perm4, 48); ++ ++ xor(erk, er, ki[forw ? i : 15 - i], 48); ++ ++ for (j = 0; j < 8; j++) ++ for (k = 0; k < 6; k++) ++ b[j][k] = erk[j * 6 + k]; ++ ++ for (j = 0; j < 8; j++) { ++ int m, n; ++ m = (b[j][0] << 1) | b[j][5]; ++ ++ n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] << ++ 1) | b[j][4]; ++ ++ for (k = 0; k < 4; k++) ++ b[j][k] = ++ (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0; ++ } ++ ++ for (j = 0; j < 8; j++) ++ for (k = 0; k < 4; k++) ++ cb[j * 4 + k] = b[j][k]; ++ permute(pcb, cb, perm5, 32); ++ ++ xor(r2, l, pcb, 32); ++ ++ for (j = 0; j < 32; j++) ++ l[j] = r[j]; ++ ++ for (j = 0; j < 32; j++) ++ r[j] = r2[j]; ++ ++ kfree(er); ++ } ++ ++ concat(rl, r, l, 32, 32); ++ ++ permute(out, rl, perm6, 64); ++ kfree(pk1); ++} ++ ++static void ++str_to_key(unsigned char *str, unsigned char *key) ++{ ++ int i; ++ ++ key[0] = str[0] >> 1; ++ key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); ++ key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); ++ key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); ++ key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); ++ key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); ++ key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); ++ key[7] = str[6] & 0x7F; ++ for (i = 0; i < 8; i++) { ++ key[i] = (key[i] << 1); ++ } ++} ++ ++static void ++smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw) ++{ ++ int i; ++ char *outb; /* outb[64] */ ++ char *inb; /* inb[64] */ ++ char *keyb; /* keyb[64] */ ++ unsigned char key2[8]; ++ ++ outb = kmalloc(64 * 3,GFP_KERNEL); ++ if(outb == NULL) ++ return; ++ ++ inb = outb + 64; ++ keyb = inb + 64; ++ ++ str_to_key(key, key2); ++ ++ for (i = 0; i < 64; i++) { ++ inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; ++ keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0; ++ outb[i] = 0; ++ } ++ ++ dohash(outb, inb, keyb, forw); ++ ++ for (i = 0; i < 8; i++) { ++ out[i] = 0; ++ } ++ ++ for (i = 0; i < 64; i++) { ++ if (outb[i]) ++ out[i / 8] |= (1 << (7 - (i % 8))); ++ } ++ kfree(outb); ++} ++ ++void ++E_P16(unsigned char *p14, unsigned char *p16) ++{ ++ unsigned char sp8[8] = ++ { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; ++ smbhash(p16, sp8, p14, 1); ++ smbhash(p16 + 8, sp8, p14 + 7, 1); ++} ++ ++void ++E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) ++{ ++ smbhash(p24, c8, p21, 1); ++ smbhash(p24 + 8, c8, p21 + 7, 1); ++ smbhash(p24 + 16, c8, p21 + 14, 1); ++} ++ ++void ++D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) ++{ ++ smbhash(out, in, p14, 0); ++ smbhash(out + 8, in + 8, p14 + 7, 0); ++} ++ ++void ++E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) ++{ ++ smbhash(out, in, p14, 1); ++ smbhash(out + 8, in + 8, p14 + 7, 1); ++} ++ ++void ++cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key) ++{ ++ unsigned char buf[8]; ++ ++ smbhash(buf, in, key, 1); ++ smbhash(out, buf, key + 9, 1); ++} ++ ++void ++cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key) ++{ ++ unsigned char buf[8]; ++ static unsigned char key2[8]; ++ ++ smbhash(buf, in, key, 1); ++ key2[0] = key[7]; ++ smbhash(out, buf, key2, 1); ++} ++ ++void ++cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw) ++{ ++ static unsigned char key2[8]; ++ ++ smbhash(out, in, key, forw); ++ key2[0] = key[7]; ++ smbhash(out + 8, in + 8, key2, forw); ++} +diff -urN linux-2.4.29.old/fs/cifs/smbencrypt.c linux-2.4.29/fs/cifs/smbencrypt.c +--- linux-2.4.29.old/fs/cifs/smbencrypt.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/smbencrypt.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,295 @@ ++/* ++ Unix SMB/Netbios implementation. ++ Version 1.9. ++ SMB parameters and setup ++ Copyright (C) Andrew Tridgell 1992-2000 ++ Copyright (C) Luke Kenneth Casson Leighton 1996-2000 ++ Modified by Jeremy Allison 1995. ++ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003 ++ Modified by Steve French (sfrench@us.ibm.com) 2002-2003 ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++ ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/string.h> ++#include <linux/kernel.h> ++#include <linux/random.h> ++#include "cifs_unicode.h" ++#include "cifspdu.h" ++#include "md5.h" ++#include "cifs_debug.h" ++ ++#ifndef FALSE ++#define FALSE 0 ++#endif ++#ifndef TRUE ++#define TRUE 1 ++#endif ++ ++/* following came from the other byteorder.h to avoid include conflicts */ ++#define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) ++#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) ++#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) ++ ++/*The following definitions come from lib/md4.c */ ++ ++void mdfour(unsigned char *out, unsigned char *in, int n); ++ ++/*The following definitions come from libsmb/smbdes.c */ ++ ++void E_P16(unsigned char *p14, unsigned char *p16); ++void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); ++void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out); ++void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out); ++void cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key); ++void cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key); ++void cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, ++ int forw); ++ ++/*The following definitions come from libsmb/smbencrypt.c */ ++ ++void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); ++void E_md4hash(const unsigned char *passwd, unsigned char *p16); ++void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]); ++void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, ++ unsigned char p24[24]); ++void NTLMSSPOWFencrypt(unsigned char passwd[8], ++ unsigned char *ntlmchalresp, unsigned char p24[24]); ++void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); ++int decode_pw_buffer(char in_buffer[516], char *new_pwrd, ++ int new_pwrd_size, __u32 * new_pw_len); ++ ++/* ++ This implements the X/Open SMB password encryption ++ It takes a password, a 8 byte "crypt key" and puts 24 bytes of ++ encrypted password into p24 */ ++/* Note that password must be uppercased and null terminated */ ++void ++SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) ++{ ++ unsigned char p14[15], p21[21]; ++ ++ memset(p21, '\0', 21); ++ memset(p14, '\0', 14); ++ strncpy((char *) p14, (char *) passwd, 14); ++ ++/* strupper((char *)p14); *//* BB at least uppercase the easy range */ ++ E_P16(p14, p21); ++ ++ SMBOWFencrypt(p21, c8, p24); ++ ++ memset(p14,0,15); ++ memset(p21,0,21); ++} ++ ++/* Routines for Windows NT MD4 Hash functions. */ ++static int ++_my_wcslen(__u16 * str) ++{ ++ int len = 0; ++ while (*str++ != 0) ++ len++; ++ return len; ++} ++ ++/* ++ * Convert a string into an NT UNICODE string. ++ * Note that regardless of processor type ++ * this must be in intel (little-endian) ++ * format. ++ */ ++ ++static int ++_my_mbstowcs(__u16 * dst, const unsigned char *src, int len) ++{ /* not a very good conversion routine - change/fix */ ++ int i; ++ __u16 val; ++ ++ for (i = 0; i < len; i++) { ++ val = *src; ++ SSVAL(dst, 0, val); ++ dst++; ++ src++; ++ if (val == 0) ++ break; ++ } ++ return i; ++} ++ ++/* ++ * Creates the MD4 Hash of the users password in NT UNICODE. ++ */ ++ ++void ++E_md4hash(const unsigned char *passwd, unsigned char *p16) ++{ ++ int len; ++ __u16 wpwd[129]; ++ ++ /* Password cannot be longer than 128 characters */ ++ if(passwd) { ++ len = strlen((char *) passwd); ++ if (len > 128) { ++ len = 128; ++ } ++ /* Password must be converted to NT unicode */ ++ _my_mbstowcs(wpwd, passwd, len); ++ } else ++ len = 0; ++ ++ wpwd[len] = 0; /* Ensure string is null terminated */ ++ /* Calculate length in bytes */ ++ len = _my_wcslen(wpwd) * sizeof (__u16); ++ ++ mdfour(p16, (unsigned char *) wpwd, len); ++ memset(wpwd,0,129 * 2); ++} ++ ++/* Does both the NT and LM owfs of a user's password */ ++void ++nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) ++{ ++ char passwd[514]; ++ ++ memset(passwd, '\0', 514); ++ if (strlen(pwd) < 513) ++ strcpy(passwd, pwd); ++ else ++ memcpy(passwd, pwd, 512); ++ /* Calculate the MD4 hash (NT compatible) of the password */ ++ memset(nt_p16, '\0', 16); ++ E_md4hash(passwd, nt_p16); ++ ++ /* Mangle the passwords into Lanman format */ ++ passwd[14] = '\0'; ++/* strupper(passwd); */ ++ ++ /* Calculate the SMB (lanman) hash functions of the password */ ++ ++ memset(p16, '\0', 16); ++ E_P16((unsigned char *) passwd, (unsigned char *) p16); ++ ++ /* clear out local copy of user's password (just being paranoid). */ ++ memset(passwd, '\0', sizeof (passwd)); ++} ++ ++/* Does the NTLMv2 owfs of a user's password */ ++void ++ntv2_owf_gen(const unsigned char owf[16], const char *user_n, ++ const char *domain_n, unsigned char kr_buf[16], ++ const struct nls_table *nls_codepage) ++{ ++ wchar_t * user_u; ++ wchar_t * dom_u; ++ int user_l, domain_l; ++ struct HMACMD5Context ctx; ++ ++ /* might as well do one alloc to hold both (user_u and dom_u) */ ++ user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL); ++ if(user_u == NULL) ++ return; ++ dom_u = user_u + 1024; ++ ++ /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); ++ push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */ ++ ++ /* BB user and domain may need to be uppercased */ ++ user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage); ++ domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage); ++ ++ user_l++; /* trailing null */ ++ domain_l++; ++ ++ hmac_md5_init_limK_to_64(owf, 16, &ctx); ++ hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx); ++ hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx); ++ hmac_md5_final(kr_buf, &ctx); ++ ++ kfree(user_u); ++} ++ ++/* Does the des encryption from the NT or LM MD4 hash. */ ++void ++SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, ++ unsigned char p24[24]) ++{ ++ unsigned char p21[21]; ++ ++ memset(p21, '\0', 21); ++ ++ memcpy(p21, passwd, 16); ++ E_P24(p21, c8, p24); ++} ++ ++/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ ++void ++NTLMSSPOWFencrypt(unsigned char passwd[8], ++ unsigned char *ntlmchalresp, unsigned char p24[24]) ++{ ++ unsigned char p21[21]; ++ ++ memset(p21, '\0', 21); ++ memcpy(p21, passwd, 8); ++ memset(p21 + 8, 0xbd, 8); ++ ++ E_P24(p21, ntlmchalresp, p24); ++} ++ ++/* Does the NT MD4 hash then des encryption. */ ++ ++void ++SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24) ++{ ++ unsigned char p21[21]; ++ ++ memset(p21, '\0', 21); ++ ++ E_md4hash(passwd, p21); ++ SMBOWFencrypt(p21, c8, p24); ++} ++ ++/* Does the md5 encryption from the NT hash for NTLMv2. */ ++void ++SMBOWFencrypt_ntv2(const unsigned char kr[16], ++ const struct data_blob * srv_chal, ++ const struct data_blob * cli_chal, unsigned char resp_buf[16]) ++{ ++ struct HMACMD5Context ctx; ++ ++ hmac_md5_init_limK_to_64(kr, 16, &ctx); ++ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx); ++ hmac_md5_update(cli_chal->data, cli_chal->length, &ctx); ++ hmac_md5_final(resp_buf, &ctx); ++} ++ ++void ++SMBsesskeygen_ntv2(const unsigned char kr[16], ++ const unsigned char *nt_resp, __u8 sess_key[16]) ++{ ++ struct HMACMD5Context ctx; ++ ++ hmac_md5_init_limK_to_64(kr, 16, &ctx); ++ hmac_md5_update(nt_resp, 16, &ctx); ++ hmac_md5_final((unsigned char *) sess_key, &ctx); ++} ++ ++void ++SMBsesskeygen_ntv1(const unsigned char kr[16], ++ const unsigned char *nt_resp, __u8 sess_key[16]) ++{ ++ mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16); ++} +diff -urN linux-2.4.29.old/fs/cifs/smberr.c linux-2.4.29/fs/cifs/smberr.c +--- linux-2.4.29.old/fs/cifs/smberr.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/smberr.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,240 @@ ++/* ++ Unix SMB/Netbios implementation. ++ Version 1.9. ++ Copyright (C) Andrew Tridgell 1998 ++ Copyright (C) Steve French (sfrench@us.ibm.com) 2002 ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++*/ ++include "smberr.h" ++#define NO_SYSLOG ++/* error code stuff - put together by Merik Karman ++ merik@blackadder.dsh.oz.au */ ++ typedef const struct { ++ char *name; ++ int code; ++ char *message; ++ int posix_code; ++} err_code_struct; ++ ++/* Dos Error Messages */ ++err_code_struct dos_msgs[] = { ++ {"ERRbadfunc", ERRbadfunc, "Invalid function.", -EINVAL}, ++ {"ERRbadfile", ERRbadfile, "File not found.", -ENOENT}, ++ {"ERRbadpath", ERRbadpath, "Directory invalid.", -ENOENT}, ++ {"ERRnofids", ERRnofids, "No file descriptors available", -EMFILE}, ++ {"ERRnoaccess", ERRnoaccess, "Access denied.", -EACCES}, ++ {"ERRbadfid", ERRbadfid, "Invalid file handle.", -EBADF}, ++ {"ERRbadmcb", 7, "Memory control blocks destroyed.", -EIO}, ++ {"ERRnomem", ERRnomem, ++ "Insufficient server memory to perform the requested function.", ++ -ENOMEM}, ++ {"ERRbadmem", ERRbadmem, "Invalid memory block address.", -EFAULT}, ++ {"ERRbadenv", ERRbadenv, "Invalid environment.", -EFAULT}, ++ {"ERRbadformat", 11, "Invalid format.", -EINVAL}, ++ {"ERRbadaccess", ERRbadaccess, "Invalid open mode." - EACCES}, ++ {"ERRbaddata", ERRbaddata, "Invalid data.", -EIO}, ++ {"ERR", ERRres, "reserved.", -EIO}, ++ {"ERRbaddrive", ERRbaddrive, "Invalid drive specified.", -ENXIO}, ++ {"ERRremcd", ERRremcd, ++ "A Delete Directory request attempted to remove the server's current directory.", ++ -EIO}, ++ {"ERRdiffdevice", ERRdiffdevice, "Not same device.", -EXDEV}, ++ {"ERRnofiles", ERRnofiles, "A File Search command can find no more files matching the specified criteria.", -ENOENT}, /* Note: must map to zero manually in some places such as readdir */ ++ {"ERRbadshare", ERRbadshare, ++ "The sharing mode specified for an Open conflicts with existing FIDs on the file.", ++ -EXTBSY}, ++ {"ERRlock", ERRlock, ++ "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process.", ++ -EACCES}, ++ {"ERRunsup", ERRunsup, "The operation is unsupported", -EINVAL}, ++ {"ERRnosuchshare", ERRnosuchshare, ++ "You specified an invalid share name", -ENXIO}, ++ {"ERRfilexists", ERRfilexists, ++ "The file named in a Create Directory, Make New File or Link request already exists.", ++ -EEXIST}, ++ {"ERRinvalidname", ERRinvalidname, "Invalid name", -ENOENT}, ++ {"ERRdiskfull", ERRdiskfull, "Disk full", -ENOSPC} ++ ++ {"ERRmoredata", ERRmoredata, ++ "There is more data to be returned.",}, ++ {"ERRinvgroup", 2455, "Invalid workgroup (try the -W option)"}, ++ {NULL, -1, NULL, -EIO} ++}; ++ ++/* Server Error Messages */ ++err_code_struct server_msgs[] = { ++ {"ERRerror", 1, "Non-specific error code."}, ++ {"ERRbadpw", 2, ++ "Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, ++ {"ERRbadtype", 3, "reserved."}, ++ {"ERRaccess", 4, ++ "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, ++ {"ERRinvnid", 5, ++ "The tree ID (TID) specified in a command was invalid."}, ++ {"ERRinvnetname", 6, "Invalid network name in tree connect."}, ++ {"ERRinvdevice", 7, ++ "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, ++ {"ERRqfull", 49, ++ "Print queue full (files) -- returned by open print file."}, ++ {"ERRqtoobig", 50, "Print queue full -- no space."}, ++ {"ERRqeof", 51, "EOF on print queue dump."}, ++ {"ERRinvpfid", 52, "Invalid print file FID."}, ++ {"ERRsmbcmd", 64, ++ "The server did not recognize the command received."}, ++ {"ERRsrverror", 65, ++ "The server encountered an internal error, e.g., system file unavailable."}, ++ {"ERRfilespecs", 67, ++ "The file handle (FID) and pathname parameters contained an invalid combination of values."}, ++ {"ERRreserved", 68, "reserved."}, ++ {"ERRbadpermits", 69, ++ "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, ++ {"ERRreserved", 70, "reserved."}, ++ {"ERRsetattrmode", 71, ++ "The attribute mode in the Set File Attribute request is invalid."}, ++ {"ERRpaused", 81, "Server is paused."}, ++ {"ERRmsgoff", 82, "Not receiving messages."}, ++ {"ERRnoroom", 83, "No room to buffer message."}, ++ {"ERRrmuns", 87, "Too many remote user names."}, ++ {"ERRtimeout", 88, "Operation timed out."}, ++ {"ERRnoresource", 89, ++ "No resources currently available for request."}, ++ {"ERRtoomanyuids", 90, "Too many UIDs active on this session."}, ++ {"ERRbaduid", 91, ++ "The UID is not known as a valid ID on this session."}, ++ {"ERRusempx", 250, "Temp unable to support Raw, use MPX mode."}, ++ {"ERRusestd", 251, ++ "Temp unable to support Raw, use standard read/write."}, ++ {"ERRcontmpx", 252, "Continue in MPX mode."}, ++ {"ERRreserved", 253, "reserved."}, ++ {"ERRreserved", 254, "reserved."}, ++ {"ERRnosupport", 0xFFFF, "Function not supported."}, ++ {NULL, -1, NULL} ++}; ++ ++/* Hard Error Messages */ ++err_code_struct hard_msgs[] = { ++ {"ERRnowrite", 19, ++ "Attempt to write on write-protected diskette."}, ++ {"ERRbadunit", 20, "Unknown unit."}, ++ {"ERRnotready", 21, "Drive not ready."}, ++ {"ERRbadcmd", 22, "Unknown command."}, ++ {"ERRdata", 23, "Data error (CRC)."}, ++ {"ERRbadreq", 24, "Bad request structure length."}, ++ {"ERRseek", 25, "Seek error."}, ++ {"ERRbadmedia", 26, "Unknown media type."}, ++ {"ERRbadsector", 27, "Sector not found."}, ++ {"ERRnopaper", 28, "Printer out of paper."}, ++ {"ERRwrite", 29, "Write fault."}, ++ {"ERRread", 30, "Read fault."}, ++ {"ERRgeneral", 31, "General failure."}, ++ {"ERRbadshare", 32, "An open conflicts with an existing open."}, ++ {"ERRlock", 33, ++ "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, ++ {"ERRwrongdisk", 34, "The wrong disk was found in a drive."}, ++ {"ERRFCBUnavail", 35, "No FCBs are available to process request."}, ++ {"ERRsharebufexc", 36, "A sharing buffer has been exceeded."}, ++ {NULL, -1, NULL} ++}; ++ ++ ++const struct { ++ int code; ++ char *class; ++ err_code_struct *err_msgs; ++} err_classes[] = { ++ { ++ 0, "SUCCESS", NULL}, { ++ 0x01, "ERRDOS", dos_msgs}, { ++ 0x02, "ERRSRV", server_msgs}, { ++ 0x03, "ERRHRD", hard_msgs}, { ++ 0x04, "ERRXOS", NULL}, { ++ 0xE1, "ERRRMX1", NULL}, { ++ 0xE2, "ERRRMX2", NULL}, { ++ 0xE3, "ERRRMX3", NULL}, { ++ 0xFF, "ERRCMD", NULL}, { ++-1, NULL, NULL}}; ++ ++ ++/**************************************************************************** ++return a SMB error string from a SMB buffer ++****************************************************************************/ ++char *smb_dos_errstr(char *inbuf) ++{ ++ static pstring ret; ++ int class = CVAL(inbuf, smb_rcls); ++ int num = SVAL(inbuf, smb_err); ++ int i, j; ++ ++ for (i = 0; err_classes[i].class; i++) ++ if (err_classes[i].code == class) { ++ if (err_classes[i].err_msgs) { ++ err_code_struct *err = ++ err_classes[i].err_msgs; ++ for (j = 0; err[j].name; j++) ++ if (num == err[j].code) { ++ if (DEBUGLEVEL > 0) ++ slprintf(ret, ++ sizeof ++ (ret) - 1, ++ "%s - %s (%s)", ++ err_classes ++ [i].class, ++ err[j]. ++ name, ++ err[j]. ++ message); ++ else ++ slprintf(ret, ++ sizeof ++ (ret) - 1, ++ "%s - %s", ++ err_classes ++ [i].class, ++ err[j]. ++ name); ++ return ret; ++ } ++ } ++ ++ slprintf(ret, sizeof(ret) - 1, "%s - %d", ++ err_classes[i].class, num); ++ return ret; ++ } ++ ++ slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)", ++ class, num); ++ return (ret); ++} ++ ++ ++/***************************************************************************** ++ returns an WERROR error message. ++ *****************************************************************************/ ++char *werror_str(WERROR status) ++{ ++ static fstring msg; ++ slprintf(msg, sizeof(msg), "WIN32 code 0x%08x", W_ERROR_V(status)); ++ return msg; ++} ++ ++ ++/***************************************************************************** ++map a unix errno to a win32 error ++ *****************************************************************************/ ++WERROR map_werror_from_unix(int error) ++{ ++ NTSTATUS status = map_nt_error_from_unix(error); ++ return ntstatus_to_werror(status); ++} +diff -urN linux-2.4.29.old/fs/cifs/smberr.h linux-2.4.29/fs/cifs/smberr.h +--- linux-2.4.29.old/fs/cifs/smberr.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/smberr.h 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,113 @@ ++/* ++ * fs/cifs/smberr.h ++ * ++ * Copyright (c) International Business Machines Corp., 2002 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * See Error Codes section of the SNIA CIFS Specification ++ * for more information ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#define SUCCESS 0 /* The request was successful. */ ++#define ERRDOS 0x01 /* Error is from the core DOS operating system set */ ++#define ERRSRV 0x02 /* Error is generated by the file server daemon */ ++#define ERRHRD 0x03 /* Error is a hardware error. */ ++#define ERRCMD 0xFF /* Command was not in the "SMB" format. */ ++ ++/* The following error codes may be generated with the SUCCESS error class.*/ ++ ++#define SUCCESS 0 /* The request was successful. */ ++ ++/* The following error codes may be generated with the ERRDOS error class.*/ ++ ++#define ERRbadfunc 1 /* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */ ++#define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */ ++#define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */ ++#define ERRnofids 4 /* Too many open files. The server has no file handles available. */ ++#define ERRnoaccess 5 /* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */ ++#define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */ ++#define ERRbadmcb 7 /* Memory control blocks destroyed. */ ++#define ERRnomem 8 /* Insufficient server memory to perform the requested function. */ ++#define ERRbadmem 9 /* Invalid memory block address. */ ++#define ERRbadenv 10 /* Invalid environment. */ ++#define ERRbadformat 11 /* Invalid format. */ ++#define ERRbadaccess 12 /* Invalid open mode. */ ++#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */ ++#define ERRbaddrive 15 /* Invalid drive specified. */ ++#define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */ ++#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */ ++#define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */ ++#define ERRgeneral 31 ++#define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */ ++#define ERRlock 33 /* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */ ++#define ERRunsup 50 ++#define ERRnosuchshare 67 ++#define ERRfilexists 80 /* The file named in the request already exists. */ ++#define ERRinvparm 87 ++#define ERRdiskfull 112 ++#define ERRinvname 123 ++#define ERRdirnotempty 145 ++#define ERRnotlocked 158 ++#define ERRalreadyexists 183 ++#define ERRbadpipe 230 ++#define ERRpipebusy 231 ++#define ERRpipeclosing 232 ++#define ERRnotconnected 233 ++#define ERRmoredata 234 ++#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */ ++#define ErrNotALink 0x201 /* A link operation was performed on a pathname that ++ was not a link. */ ++ ++/* Following error codes may be generated with the ERRSRV error ++class.*/ ++ ++#define ERRerror 1 /* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */ ++#define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */ ++#define ERRbadtype 3 /* used for indicating DFS referral needed */ ++#define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */ ++#define ERRinvtid 5 /* The Tid specified in a command was invalid. */ ++#define ERRinvnetname 6 /* Invalid network name in tree connect. */ ++#define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */ ++#define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */ ++#define ERRqtoobig 50 /* Print queue full -- no space. */ ++#define ERRqeof 51 /* EOF on print queue dump */ ++#define ERRinvpfid 52 /* Invalid print file FID. */ ++#define ERRsmbcmd 64 /* The server did not recognize the command received. */ ++#define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */ ++#define ERRbadBID 66 /* (obsolete) */ ++#define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */ ++#define ERRbadLink 68 /* (obsolete) */ ++#define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */ ++#define ERRbadPID 70 ++#define ERRsetattrmode 71 /* attribute (mode) is invalid */ ++#define ERRpaused 81 /* Server is paused */ ++#define ERRmsgoff 82 /* reserved - messaging off */ ++#define ERRnoroom 83 /* reserved - no room for message */ ++#define ERRrmuns 87 /* reserved - too many remote names */ ++#define ERRtimeout 88 /* operation timed out */ ++#define ERRnoresource 89 /* No resources available for request */ ++#define ERRtoomanyuids 90 /* Too many UIDs active on this session */ ++#define ERRbaduid 91 /* The UID is not known as a valid user */ ++#define ERRusempx 250 /* temporarily unable to use raw */ ++#define ERRusestd 251 /* temporarily unable to use either raw or mpx */ ++#define ERR_NOTIFY_ENUM_DIR 1024 ++#define ERRaccountexpired 2239 ++#define ERRbadclient 2240 ++#define ERRbadLogonTime 2241 ++#define ERRpasswordExpired 2242 ++#define ERRnetlogonNotStarted 2455 ++#define ERRnosupport 0xFFFF +diff -urN linux-2.4.29.old/fs/cifs/TODO linux-2.4.29/fs/cifs/TODO +--- linux-2.4.29.old/fs/cifs/TODO 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/TODO 2004-07-14 00:25:04.000000000 +0200 +@@ -0,0 +1,106 @@ ++version 1.16 May 27, 2004 ++ ++A Partial List of Missing Features ++================================== ++ ++Contributions are welcome. There are plenty of opportunities ++for visible, important contributions to this module. Here ++is a partial list of the known problems and missing features: ++ ++a) Support for SecurityDescriptors for chmod/chgrp/chown so ++these can be supported for Windows servers ++ ++b) Better pam/winbind integration ++ ++c) multi-user mounts - multiplexed sessionsetups over single vc ++(ie tcp session) - prettying up needed ++ ++d) Kerberos/SPNEGO session setup support - (started) ++ ++e) NTLMv2 authentication (mostly implemented) ++ ++f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup ++used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM ++and raw NTLMSSP already. This is important when enabling ++extended security and mounting to Windows 2003 Servers ++ ++f) Directory entry caching relies on a 1 second timer, rather than ++using FindNotify or equivalent. - (started) ++ ++g) A few byte range testcases fail due to POSIX vs. Windows/CIFS ++style byte range lock differences ++ ++h) quota support ++ ++i) support for the Linux 2.5 kernel new feature get_xattr and set_xattr ++which will allow us to expose dos attributes as well as real ++ACLs. This support has been started in the current code, but is ++ifdeffed out. ++ ++k) finish writepages support (multi-page write behind for improved ++performance) and syncpage ++ ++l) hook lower into the sockets api (as NFS/SunRPC does) to avoid the ++extra copy in/out of the socket buffers in some cases. ++ ++m) finish support for IPv6. This is mostly complete but ++needs a simple inet_pton like function to convert ipv6 ++addresses in string representation. ++ ++o) Better optimize open (and pathbased setfilesize) to reduce the ++oplock breaks coming from windows srv. Piggyback identical file ++opens on top of each other by incrementing reference count rather ++than resending (helps reduce server resource utilization and avoid ++spurious oplock breaks). ++ ++p) Improve performance of readpages by sending more than one read ++at a time when 8 pages or more are requested. Evaluate whether ++reads larger than 16K would be helpful. ++ ++q) For support of Windows9x/98 we need to retry failed mounts ++to *SMBSERVER (default server name) with the uppercase hostname ++in the RFC1001 session_init request. ++ ++r) Add Extended Attributed support (for storing UID/GID info ++to Windows servers) ++ ++s) Finish fcntl D_NOTIFY support so kde and gnome file list windows ++will autorefresh ++ ++t) Add GUI tool to configure /proc/fs/cifs settings and for display of ++the CIFS statistics ++ ++KNOWN BUGS (updated May 27, 2004) ++==================================== ++1) existing symbolic links (Windows reparse points) are recognized but ++can not be created remotely. They are implemented for Samba and those that ++support the CIFS Unix extensions but Samba has a bug currently handling ++symlink text beginning with slash ++2) follow_link and readdir code does not follow dfs junctions ++but recognizes them ++3) create of new files to FAT partitions on Windows servers can ++succeed but still return access denied (appears to be Windows ++server not cifs client problem) and has not been reproduced recently. ++NTFS partitions do not have this problem. ++4) debug connectathon lock test case 10 which fails against ++Samba (may be unmappable due to POSIX to Windows lock model ++differences but worth investigating). Also debug Samba to ++see why lock test case 7 takes longer to complete to Samba ++than to Windows. ++ ++Misc testing to do ++================== ++1) check out max path names and max path name components against various server ++types. Try nested symlinks. Return max path name in stat -f information ++ ++2) Modify file portion of ltp so it can run against a mounted network ++share and run it against cifs vfs. ++ ++3) Additional performance testing and optimization using iozone and similar - ++there are some easy changes that can be done to parallelize sequential writes, ++and when signing is disabled to request larger read sizes (larger than ++negotiated size) and send larger write sizes to modern servers. ++ ++4) More exhaustively test the recently added NT4 support against various ++NT4 service pack levels. ++ +diff -urN linux-2.4.29.old/fs/cifs/transport.c linux-2.4.29/fs/cifs/transport.c +--- linux-2.4.29.old/fs/cifs/transport.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.29/fs/cifs/transport.c 2004-07-14 00:25:05.000000000 +0200 +@@ -0,0 +1,434 @@ ++/* ++ * fs/cifs/transport.c ++ * ++ * Copyright (C) International Business Machines Corp., 2002,2004 ++ * Author(s): Steve French (sfrench@us.ibm.com) ++ * ++ * This library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published ++ * by the Free Software Foundation; either version 2.1 of the License, or ++ * (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ++ * the GNU Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this library; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include <linux/fs.h> ++#include <linux/list.h> ++#include <linux/wait.h> ++#include <linux/net.h> ++#include <linux/version.h> ++#include <asm/uaccess.h> ++#include <asm/processor.h> ++#include "cifspdu.h" ++#include "cifsglob.h" ++#include "cifsproto.h" ++#include "cifs_debug.h" ++ ++extern kmem_cache_t *cifs_mid_cachep; ++extern kmem_cache_t *cifs_oplock_cachep; ++ ++struct mid_q_entry * ++AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) ++{ ++ struct mid_q_entry *temp; ++ ++ if (ses == NULL) { ++ cERROR(1, ("Null session passed in to AllocMidQEntry ")); ++ return NULL; ++ } ++ if (ses->server == NULL) { ++ cERROR(1, ("Null TCP session in AllocMidQEntry")); ++ return NULL; ++ } ++ ++ temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep, ++ SLAB_KERNEL); ++ if (temp == NULL) ++ return temp; ++ else { ++ memset(temp, 0, sizeof (struct mid_q_entry)); ++ temp->mid = smb_buffer->Mid; /* always LE */ ++ temp->pid = current->pid; ++ temp->command = smb_buffer->Command; ++ cFYI(1, ("For smb_command %d", temp->command)); ++ do_gettimeofday(&temp->when_sent); ++ temp->ses = ses; ++ temp->tsk = current; ++ } ++ ++ spin_lock(&GlobalMid_Lock); ++ list_add_tail(&temp->qhead, &ses->server->pending_mid_q); ++ atomic_inc(&midCount); ++ temp->midState = MID_REQUEST_ALLOCATED; ++ spin_unlock(&GlobalMid_Lock); ++ return temp; ++} ++ ++void ++DeleteMidQEntry(struct mid_q_entry *midEntry) ++{ ++ spin_lock(&GlobalMid_Lock); ++ midEntry->midState = MID_FREE; ++ list_del(&midEntry->qhead); ++ atomic_dec(&midCount); ++ spin_unlock(&GlobalMid_Lock); ++ cifs_buf_release(midEntry->resp_buf); ++ kmem_cache_free(cifs_mid_cachep, midEntry); ++} ++ ++struct oplock_q_entry * ++AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon) ++{ ++ struct oplock_q_entry *temp; ++ if ((pinode== NULL) || (tcon == NULL)) { ++ cERROR(1, ("Null parms passed to AllocOplockQEntry")); ++ return NULL; ++ } ++ temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep, ++ SLAB_KERNEL); ++ if (temp == NULL) ++ return temp; ++ else { ++ temp->pinode = pinode; ++ temp->tcon = tcon; ++ temp->netfid = fid; ++ spin_lock(&GlobalMid_Lock); ++ list_add_tail(&temp->qhead, &GlobalOplock_Q); ++ spin_unlock(&GlobalMid_Lock); ++ } ++ return temp; ++ ++} ++ ++void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry) ++{ ++ spin_lock(&GlobalMid_Lock); ++ /* should we check if list empty first? */ ++ list_del(&oplockEntry->qhead); ++ spin_unlock(&GlobalMid_Lock); ++ kmem_cache_free(cifs_oplock_cachep, oplockEntry); ++} ++ ++int ++smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, ++ unsigned int smb_buf_length, struct sockaddr *sin) ++{ ++ int rc = 0; ++ int i = 0; ++ struct msghdr smb_msg; ++ struct iovec iov; ++ mm_segment_t temp_fs; ++ ++ if(ssocket == NULL) ++ return -ENOTSOCK; /* BB eventually add reconnect code here */ ++ iov.iov_base = smb_buffer; ++ iov.iov_len = smb_buf_length + 4; ++ ++ smb_msg.msg_name = sin; ++ smb_msg.msg_namelen = sizeof (struct sockaddr); ++ smb_msg.msg_iov = &iov; ++ smb_msg.msg_iovlen = 1; ++ smb_msg.msg_control = NULL; ++ smb_msg.msg_controllen = 0; ++ smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ ++ ++ /* smb header is converted in header_assemble. bcc and rest of SMB word ++ area, and byte area if necessary, is converted to littleendian in ++ cifssmb.c and RFC1001 len is converted to bigendian in smb_send ++ Flags2 is converted in SendReceive */ ++ ++ smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); ++ cFYI(1, ("Sending smb of length %d ", smb_buf_length)); ++ dump_smb(smb_buffer, smb_buf_length + 4); ++ ++ temp_fs = get_fs(); /* we must turn off socket api parm checking */ ++ set_fs(get_ds()); ++ while(iov.iov_len > 0) { ++ rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4); ++ if ((rc == -ENOSPC) || (rc == -EAGAIN)) { ++ i++; ++ if(i > 60) { ++ cERROR(1, ++ ("sends on sock %p stuck for 30 seconds", ++ ssocket)); ++ rc = -EAGAIN; ++ break; ++ } ++ set_current_state(TASK_INTERRUPTIBLE); ++ schedule_timeout(HZ/2); ++ continue; ++ } ++ if (rc < 0) ++ break; ++ iov.iov_base += rc; ++ iov.iov_len -= rc; ++ } ++ set_fs(temp_fs); ++ ++ if (rc < 0) { ++ cERROR(1,("Error %d sending data on socket to server.", rc)); ++ } else { ++ rc = 0; ++ } ++ ++ return rc; ++} ++ ++int ++SendReceive(const unsigned int xid, struct cifsSesInfo *ses, ++ struct smb_hdr *in_buf, struct smb_hdr *out_buf, ++ int *pbytes_returned, const int long_op) ++{ ++ int rc = 0; ++ unsigned int receive_len; ++ long timeout; ++ struct mid_q_entry *midQ; ++ ++ if (ses == NULL) { ++ cERROR(1,("Null smb session")); ++ return -EIO; ++ } ++ if(ses->server == NULL) { ++ cERROR(1,("Null tcp session")); ++ return -EIO; ++ } ++ ++ /* Ensure that we do not send more than 50 overlapping requests ++ to the same server. We may make this configurable later or ++ use ses->maxReq */ ++ if(long_op == -1) { ++ /* oplock breaks must not be held up */ ++ atomic_inc(&ses->server->inFlight); ++ } else { ++ spin_lock(&GlobalMid_Lock); ++ while(1) { ++ if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){ ++ spin_unlock(&GlobalMid_Lock); ++ wait_event(ses->server->request_q, ++ atomic_read(&ses->server->inFlight) ++ < CIFS_MAX_REQ); ++ spin_lock(&GlobalMid_Lock); ++ } else { ++ if(ses->server->tcpStatus == CifsExiting) { ++ spin_unlock(&GlobalMid_Lock); ++ return -ENOENT; ++ } ++ ++ /* can not count locking commands against total since ++ they are allowed to block on server */ ++ ++ if(long_op < 3) { ++ /* update # of requests on the wire to server */ ++ atomic_inc(&ses->server->inFlight); ++ } ++ spin_unlock(&GlobalMid_Lock); ++ break; ++ } ++ } ++ } ++ /* make sure that we sign in the same order that we send on this socket ++ and avoid races inside tcp sendmsg code that could cause corruption ++ of smb data */ ++ ++ down(&ses->server->tcpSem); ++ ++ if (ses->server->tcpStatus == CifsExiting) { ++ rc = -ENOENT; ++ goto out_unlock; ++ } else if (ses->server->tcpStatus == CifsNeedReconnect) { ++ cFYI(1,("tcp session dead - return to caller to retry")); ++ rc = -EAGAIN; ++ goto out_unlock; ++ } else if (ses->status != CifsGood) { ++ /* check if SMB session is bad because we are setting it up */ ++ if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && ++ (in_buf->Command != SMB_COM_NEGOTIATE)) { ++ rc = -EAGAIN; ++ goto out_unlock; ++ } /* else ok - we are setting up session */ ++ } ++ midQ = AllocMidQEntry(in_buf, ses); ++ if (midQ == NULL) { ++ up(&ses->server->tcpSem); ++ /* If not lock req, update # of requests on wire to server */ ++ if(long_op < 3) { ++ atomic_dec(&ses->server->inFlight); ++ wake_up(&ses->server->request_q); ++ } ++ return -ENOMEM; ++ } ++ ++ if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) { ++ up(&ses->server->tcpSem); ++ cERROR(1, ++ ("Illegal length, greater than maximum frame, %d ", ++ in_buf->smb_buf_length)); ++ DeleteMidQEntry(midQ); ++ /* If not lock req, update # of requests on wire to server */ ++ if(long_op < 3) { ++ atomic_dec(&ses->server->inFlight); ++ wake_up(&ses->server->request_q); ++ } ++ return -EIO; ++ } ++ ++ if (in_buf->smb_buf_length > 12) ++ in_buf->Flags2 = cpu_to_le16(in_buf->Flags2); ++ ++ rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number); ++ ++ midQ->midState = MID_REQUEST_SUBMITTED; ++ rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, ++ (struct sockaddr *) &(ses->server->addr.sockAddr)); ++ if(rc < 0) { ++ DeleteMidQEntry(midQ); ++ up(&ses->server->tcpSem); ++ /* If not lock req, update # of requests on wire to server */ ++ if(long_op < 3) { ++ atomic_dec(&ses->server->inFlight); ++ wake_up(&ses->server->request_q); ++ } ++ return rc; ++ } else ++ up(&ses->server->tcpSem); ++ if (long_op == -1) ++ goto cifs_no_response_exit; ++ else if (long_op == 2) /* writes past end of file can take looooong time */ ++ timeout = 300 * HZ; ++ else if (long_op == 1) ++ timeout = 45 * HZ; /* should be greater than ++ servers oplock break timeout (about 43 seconds) */ ++ else if (long_op > 2) { ++ timeout = MAX_SCHEDULE_TIMEOUT; ++ } else ++ timeout = 15 * HZ; ++ /* wait for 15 seconds or until woken up due to response arriving or ++ due to last connection to this server being unmounted */ ++ if (signal_pending(current)) { ++ /* if signal pending do not hold up user for full smb timeout ++ but we still give response a change to complete */ ++ if(midQ->midState & MID_REQUEST_SUBMITTED) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ timeout = sleep_on_timeout(&ses->server->response_q,2 * HZ); ++ } ++ } else { /* using normal timeout */ ++ /* timeout = wait_event_interruptible_timeout(ses->server->response_q, ++ (midQ->midState & MID_RESPONSE_RECEIVED) || ++ ((ses->server->tcpStatus != CifsGood) && ++ (ses->server->tcpStatus != CifsNew)), ++ timeout); */ ++ /* Can not allow user interrupts- wreaks havoc with performance */ ++ if(midQ->midState & MID_REQUEST_SUBMITTED) { ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ timeout = sleep_on_timeout(&ses->server->response_q,timeout); ++ } ++ } ++ ++ spin_lock(&GlobalMid_Lock); ++ if (midQ->resp_buf) { ++ spin_unlock(&GlobalMid_Lock); ++ receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length); ++ } else { ++ cERROR(1,("No response buffer")); ++ if(midQ->midState == MID_REQUEST_SUBMITTED) { ++ if(ses->server->tcpStatus == CifsExiting) ++ rc = -EHOSTDOWN; ++ else { ++ ses->server->tcpStatus = CifsNeedReconnect; ++ midQ->midState = MID_RETRY_NEEDED; ++ } ++ } ++ ++ if (rc != -EHOSTDOWN) { ++ if(midQ->midState == MID_RETRY_NEEDED) { ++ rc = -EAGAIN; ++ cFYI(1,("marking request for retry")); ++ } else { ++ rc = -EIO; ++ } ++ } ++ spin_unlock(&GlobalMid_Lock); ++ DeleteMidQEntry(midQ); ++ /* If not lock req, update # of requests on wire to server */ ++ if(long_op < 3) { ++ atomic_dec(&ses->server->inFlight); ++ wake_up(&ses->server->request_q); ++ } ++ return rc; ++ } ++ ++ if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) { ++ cERROR(1, ++ ("Frame too large received. Length: %d Xid: %d", ++ receive_len, xid)); ++ rc = -EIO; ++ } else { /* rcvd frame is ok */ ++ ++ if (midQ->resp_buf && out_buf ++ && (midQ->midState == MID_RESPONSE_RECEIVED)) { ++ memcpy(out_buf, midQ->resp_buf, ++ receive_len + ++ 4 /* include 4 byte RFC1001 header */ ); ++ ++ dump_smb(out_buf, 92); ++ /* convert the length into a more usable form */ ++ out_buf->smb_buf_length = ++ be32_to_cpu(out_buf->smb_buf_length); ++ if((out_buf->smb_buf_length > 24) && ++ (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { ++ rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */ ++ if(rc) ++ cFYI(1,("Unexpected signature received from server")); ++ } ++ ++ if (out_buf->smb_buf_length > 12) ++ out_buf->Flags2 = le16_to_cpu(out_buf->Flags2); ++ if (out_buf->smb_buf_length > 28) ++ out_buf->Pid = le16_to_cpu(out_buf->Pid); ++ if (out_buf->smb_buf_length > 28) ++ out_buf->PidHigh = ++ le16_to_cpu(out_buf->PidHigh); ++ ++ *pbytes_returned = out_buf->smb_buf_length; ++ ++ /* BB special case reconnect tid and reconnect uid here? */ ++ rc = map_smb_to_linux_error(out_buf); ++ ++ /* convert ByteCount if necessary */ ++ if (receive_len >= ++ sizeof (struct smb_hdr) - ++ 4 /* do not count RFC1001 header */ + ++ (2 * out_buf->WordCount) + 2 /* bcc */ ) ++ BCC(out_buf) = le16_to_cpu(BCC(out_buf)); ++ } else { ++ rc = -EIO; ++ cFYI(1,("Bad MID state? ")); ++ } ++ } ++cifs_no_response_exit: ++ DeleteMidQEntry(midQ); ++ ++ if(long_op < 3) { ++ atomic_dec(&ses->server->inFlight); ++ wake_up(&ses->server->request_q); ++ } ++ ++ return rc; ++ ++out_unlock: ++ up(&ses->server->tcpSem); ++ /* If not lock req, update # of requests on wire to server */ ++ if(long_op < 3) { ++ atomic_dec(&ses->server->inFlight); ++ wake_up(&ses->server->request_q); ++ } ++ ++ return rc; ++} +diff -urN linux-2.4.29.old/fs/Config.in linux-2.4.29/fs/Config.in +--- linux-2.4.29.old/fs/Config.in 2005-03-21 19:30:22.000000000 +0100 ++++ linux-2.4.29/fs/Config.in 2005-03-21 19:36:51.000000000 +0100 +@@ -146,6 +146,10 @@ + define_bool CONFIG_LOCKD_V4 y + fi + ++ dep_tristate 'CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)' CONFIG_CIFS $CONFIG_INET ++ dep_mbool ' CIFS statistics' CONFIG_CIFS_STATS $CONFIG_CIFS ++ dep_mbool ' CIFS POSIX Protocol Extensions' CONFIG_CIFS_POSIX $CONFIG_CIFS ++ + dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET + if [ "$CONFIG_SMB_FS" != "n" ]; then + bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT +diff -urN linux-2.4.29.old/fs/Makefile linux-2.4.29/fs/Makefile +--- linux-2.4.29.old/fs/Makefile 2005-03-21 19:30:22.000000000 +0100 ++++ linux-2.4.29/fs/Makefile 2005-03-21 19:36:51.000000000 +0100 +@@ -37,6 +37,7 @@ + subdir-$(CONFIG_VFAT_FS) += vfat + subdir-$(CONFIG_BFS_FS) += bfs + subdir-$(CONFIG_ISO9660_FS) += isofs ++subdir-$(CONFIG_CIFS) += cifs + subdir-$(CONFIG_DEVFS_FS) += devfs + subdir-$(CONFIG_HFSPLUS_FS) += hfsplus # Before hfs to find wrapped HFS+ + subdir-$(CONFIG_HFS_FS) += hfs +diff -urN linux-2.4.29.old/fs/nls/Config.in linux-2.4.29/fs/nls/Config.in +--- linux-2.4.29.old/fs/nls/Config.in 2003-08-25 13:44:43.000000000 +0200 ++++ linux-2.4.29/fs/nls/Config.in 2005-03-21 19:36:51.000000000 +0100 +@@ -11,6 +11,7 @@ + + # msdos and Joliet want NLS + if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \ ++ -o "$CONFIG_CIFS" != "n" \ + -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \ + -o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \ + -o "$CONFIG_BEFS_FS" != "n" -o "$CONFIG_HFSPLUS_FS" != "n" ]; then |