]> wimlib.net Git - wimlib/commitdiff
Get rid of code clone from libntfs-3g
authorEric Biggers <ebiggers3@gmail.com>
Sat, 1 Sep 2012 05:45:14 +0000 (00:45 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 1 Sep 2012 05:45:14 +0000 (00:45 -0500)
Makefile.am
README
config.h.in
configure.ac
src/ntfs-3g_security.c [deleted file]

index 9c36d5a12ad210039b93f6509427442f007a091f..f05e58ddd4898eff7d5d1f80ef5f8af6593d270e 100644 (file)
@@ -53,13 +53,6 @@ libwim_la_SOURCES =          \
        src/xpress-decomp.c     \
        src/xpress.h
 
        src/xpress-decomp.c     \
        src/xpress.h
 
-if WITH_NTFS_3G
-if !WITH_NEW_NTFS_3G
-libwim_la_SOURCES += src/ntfs-3g_security.c
-endif
-endif
-
-
 EXTRA_libwim_la_SOURCES = src/sha1-ssse3.asm
 libwim_la_DEPENDENCIES = $(SSSE3_SHA1_OBJ)
 STRIP_FPIC = sh $(top_srcdir)/build-aux/strip_fPIC.sh
 EXTRA_libwim_la_SOURCES = src/sha1-ssse3.asm
 libwim_la_DEPENDENCIES = $(SSSE3_SHA1_OBJ)
 STRIP_FPIC = sh $(top_srcdir)/build-aux/strip_fPIC.sh
diff --git a/README b/README
index 91deb1c064ff4ad895e2647b0512c6231d523b31..364cb77f8d007bf9cd0dfd784beba596a1ab19af 100644 (file)
--- a/README
+++ b/README
@@ -94,11 +94,7 @@ server for PXE booting.  See the main page `doc/mkwinpeiso.1' for more details.
 
 * libntfs-3g
        Unless configured with --without-ntfs-3g, wimlib requires the library
 
 * libntfs-3g
        Unless configured with --without-ntfs-3g, wimlib requires the library
-       and headers for libntfs-3g to be installed.  Currently, the libntfs-3g
-       version dated 2012-1-15 is required because I've cloned some of the code
-       from the library, and it needs to compiled against the same version.
-       I'm hoping to be able to use future version of libntfs-3g without code
-       cloning after submitting some patches, however.
+       and headers for libntfs-3g to be installed.
 
 * cdrkit (optional)
 * mtools (optional)
 
 * cdrkit (optional)
 * mtools (optional)
index ecd767d378190dbb4ed8f53416029b2d509f65db..db9f0e2d8c3d70347883fea918692703d0552d63 100644 (file)
 /* Define to 1 if using libcrypto SHA1 */
 #undef WITH_LIBCRYPTO
 
 /* Define to 1 if using libcrypto SHA1 */
 #undef WITH_LIBCRYPTO
 
-/* Define to 1 to use patched upstream NTFS-3g instead of version 2012-1-15 */
-#undef WITH_NEW_NTFS_3G
-
 /* Define to 1 to enable support for NTFS-specific information */
 #undef WITH_NTFS_3G
 
 /* Define to 1 to enable support for NTFS-specific information */
 #undef WITH_NTFS_3G
 
index 5dcc2ff1eeba998f2390ebde57ce8497dff26dd8..c2156614ce12918fcd5e5482eaf77471bc831e10 100644 (file)
@@ -163,25 +163,6 @@ AM_CONDITIONAL([WITH_NTFS_3G], [test "x$WITH_NTFS_3G" = "xyes"])
 AC_SUBST([LIBNTFS_3G_LDADD], [$LIBNTFS_3G_LDADD])
 AC_SUBST([LIBNTFS_3G_CFLAGS], [$LIBNTFS_3G_CFLAGS])
 
 AC_SUBST([LIBNTFS_3G_LDADD], [$LIBNTFS_3G_LDADD])
 AC_SUBST([LIBNTFS_3G_CFLAGS], [$LIBNTFS_3G_CFLAGS])
 
-AC_MSG_CHECKING([whether to use patched upstream libntfs-3g])
-AC_ARG_WITH([new-ntfs-3g],
-       [AS_HELP_STRING([--with-new-ntfs-3g], [build using patched upstream
-                             NTFS-3g instead of version 2012-1-15])],
-       [WITH_NEW_NTFS_3G=$withval],
-       [WITH_NEW_NTFS_3G=no]
-       )
-
-AC_MSG_RESULT([$WITH_NEW_NTFS_3G])
-if test "x$WITH_NEW_NTFS_3G" = "xyes"; then
-       if test "x$WITH_NTFS_3G" != "xyes"; then
-               AC_MSG_ERROR([Cannot use new NTFS-3g if configuring
-                             --without-ntfs-3g])
-       fi
-       AC_DEFINE([WITH_NEW_NTFS_3G], [1], [Define to 1 to use patched upstream
-                  NTFS-3g instead of version 2012-1-15])
-fi
-AM_CONDITIONAL([WITH_NEW_NTFS_3G], [test "x$WITH_NEW_NTFS_3G" = "xyes"])
-
 AC_MSG_CHECKING([whether to include support for mounting WIMs])
 AC_ARG_WITH([fuse],
                AS_HELP_STRING([--without-fuse], [build without libfuse.  
 AC_MSG_CHECKING([whether to include support for mounting WIMs])
 AC_ARG_WITH([fuse],
                AS_HELP_STRING([--without-fuse], [build without libfuse.  
diff --git a/src/ntfs-3g_security.c b/src/ntfs-3g_security.c
deleted file mode 100644 (file)
index 7c8dec3..0000000
+++ /dev/null
@@ -1,5163 +0,0 @@
-/**
- * security.c - Handling security/ACLs in NTFS.  Originated from the Linux-NTFS project.
- *
- * Copyright (c) 2004 Anton Altaparmakov
- * Copyright (c) 2005-2006 Szabolcs Szakacsits
- * Copyright (c) 2006 Yura Pakhuchiy
- * Copyright (c) 2007-2010 Jean-Pierre Andre
- *
- * This program/include file 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/include file 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 (in the main directory of the NTFS-3G
- * distribution in the file COPYING); if not, write to the Free Software
- * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef ENABLE_XATTR
-#define HAVE_SETXATTR
-#endif
-
-#include <stdarg.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_SETXATTR
-#include <sys/xattr.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#include <unistd.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include <ntfs-3g/param.h>
-#include <ntfs-3g/types.h>
-#include <ntfs-3g/layout.h>
-#include <ntfs-3g/attrib.h>
-#include <ntfs-3g/index.h>
-#include <ntfs-3g/dir.h>
-#include <ntfs-3g/bitmap.h>
-#include <ntfs-3g/security.h>
-#include <ntfs-3g/acls.h>
-#include <ntfs-3g/cache.h>
-#include <ntfs-3g/misc.h>
-
-/*
- *     JPA NTFS constants or structs
- *     should be moved to layout.h
- */
-
-#define ALIGN_SDS_BLOCK 0x40000 /* Alignment for a $SDS block */
-#define ALIGN_SDS_ENTRY 16 /* Alignment for a $SDS entry */
-#define STUFFSZ 0x4000 /* unitary stuffing size for $SDS */
-#define FIRST_SECURITY_ID 0x100 /* Lowest security id */
-
-       /* Mask for attributes which can be forced */
-#define FILE_ATTR_SETTABLE ( FILE_ATTR_READONLY                \
-                               | FILE_ATTR_HIDDEN      \
-                               | FILE_ATTR_SYSTEM      \
-                               | FILE_ATTR_ARCHIVE     \
-                               | FILE_ATTR_TEMPORARY   \
-                               | FILE_ATTR_OFFLINE     \
-                               | FILE_ATTR_NOT_CONTENT_INDEXED )
-
-struct SII {           /* this is an image of an $SII index entry */
-       le16 offs;
-       le16 size;
-       le32 fill1;
-       le16 indexsz;
-       le16 indexksz;
-       le16 flags;
-       le16 fill2;
-       le32 keysecurid;
-
-       /* did not find official description for the following */
-       le32 hash;
-       le32 securid;
-       le32 dataoffsl; /* documented as badly aligned */
-       le32 dataoffsh;
-       le32 datasize;
-} ;
-
-struct SDH {           /* this is an image of an $SDH index entry */
-       le16 offs;
-       le16 size;
-       le32 fill1;
-       le16 indexsz;
-       le16 indexksz;
-       le16 flags;
-       le16 fill2;
-       le32 keyhash;
-       le32 keysecurid;
-
-       /* did not find official description for the following */
-       le32 hash;
-       le32 securid;
-       le32 dataoffsl;
-       le32 dataoffsh;
-       le32 datasize;
-       le32 fill3;
-       } ;
-
-/*
- *     A few useful constants
- */
-
-static ntfschar sii_stream[] = { const_cpu_to_le16('$'),
-                                const_cpu_to_le16('S'),
-                                const_cpu_to_le16('I'),   
-                                const_cpu_to_le16('I'),   
-                                const_cpu_to_le16(0) };
-static ntfschar sdh_stream[] = { const_cpu_to_le16('$'),
-                                const_cpu_to_le16('S'),
-                                const_cpu_to_le16('D'),
-                                const_cpu_to_le16('H'),
-                                const_cpu_to_le16(0) };
-
-/*
- *             null SID (S-1-0-0)
- */
-
-extern const SID *nullsid;
-
-/*
- * The zero GUID.
- */
-
-static const GUID __zero_guid = { const_cpu_to_le32(0), const_cpu_to_le16(0),
-               const_cpu_to_le16(0), { 0, 0, 0, 0, 0, 0, 0, 0 } };
-static const GUID *const zero_guid = &__zero_guid;
-
-/**
- * ntfs_guid_is_zero - check if a GUID is zero
- * @guid:      [IN] guid to check
- *
- * Return TRUE if @guid is a valid pointer to a GUID and it is the zero GUID
- * and FALSE otherwise.
- */
-BOOL ntfs_guid_is_zero(const GUID *guid)
-{
-       return (memcmp(guid, zero_guid, sizeof(*zero_guid)));
-}
-
-/**
- * ntfs_guid_to_mbs - convert a GUID to a multi byte string
- * @guid:      [IN]  guid to convert
- * @guid_str:  [OUT] string in which to return the GUID (optional)
- *
- * Convert the GUID pointed to by @guid to a multi byte string of the form
- * "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".  Therefore, @guid_str (if not NULL)
- * needs to be able to store at least 37 bytes.
- *
- * If @guid_str is not NULL it will contain the converted GUID on return.  If
- * it is NULL a string will be allocated and this will be returned.  The caller
- * is responsible for free()ing the string in that case.
- *
- * On success return the converted string and on failure return NULL with errno
- * set to the error code.
- */
-char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str)
-{
-       char *_guid_str;
-       int res;
-
-       if (!guid) {
-               errno = EINVAL;
-               return NULL;
-       }
-       _guid_str = guid_str;
-       if (!_guid_str) {
-               _guid_str = (char*)ntfs_malloc(37);
-               if (!_guid_str)
-                       return _guid_str;
-       }
-       res = snprintf(_guid_str, 37,
-                       "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-                       (unsigned int)le32_to_cpu(guid->data1),
-                       le16_to_cpu(guid->data2), le16_to_cpu(guid->data3),
-                       guid->data4[0], guid->data4[1],
-                       guid->data4[2], guid->data4[3], guid->data4[4],
-                       guid->data4[5], guid->data4[6], guid->data4[7]);
-       if (res == 36)
-               return _guid_str;
-       if (!guid_str)
-               free(_guid_str);
-       errno = EINVAL;
-       return NULL;
-}
-
-/**
- * ntfs_sid_to_mbs_size - determine maximum size for the string of a SID
- * @sid:       [IN]  SID for which to determine the maximum string size
- *
- * Determine the maximum multi byte string size in bytes which is needed to
- * store the standard textual representation of the SID pointed to by @sid.
- * See ntfs_sid_to_mbs(), below.
- *
- * On success return the maximum number of bytes needed to store the multi byte
- * string and on failure return -1 with errno set to the error code.
- */
-int ntfs_sid_to_mbs_size(const SID *sid)
-{
-       int size, i;
-
-       if (!ntfs_sid_is_valid(sid)) {
-               errno = EINVAL;
-               return -1;
-       }
-       /* Start with "S-". */
-       size = 2;
-       /*
-        * Add the SID_REVISION.  Hopefully the compiler will optimize this
-        * away as SID_REVISION is a constant.
-        */
-       for (i = SID_REVISION; i > 0; i /= 10)
-               size++;
-       /* Add the "-". */
-       size++;
-       /*
-        * Add the identifier authority.  If it needs to be in decimal, the
-        * maximum is 2^32-1 = 4294967295 = 10 characters.  If it needs to be
-        * in hexadecimal, then maximum is 0x665544332211 = 14 characters.
-        */
-       if (!sid->identifier_authority.high_part)
-               size += 10;
-       else
-               size += 14;
-       /*
-        * Finally, add the sub authorities.  For each we have a "-" followed
-        * by a decimal which can be up to 2^32-1 = 4294967295 = 10 characters.
-        */
-       size += (1 + 10) * sid->sub_authority_count;
-       /* We need the zero byte at the end, too. */
-       size++;
-       return size * sizeof(char);
-}
-
-/**
- * ntfs_sid_to_mbs - convert a SID to a multi byte string
- * @sid:               [IN]  SID to convert
- * @sid_str:           [OUT] string in which to return the SID (optional)
- * @sid_str_size:      [IN]  size in bytes of @sid_str
- *
- * Convert the SID pointed to by @sid to its standard textual representation.
- * @sid_str (if not NULL) needs to be able to store at least
- * ntfs_sid_to_mbs_size() bytes.  @sid_str_size is the size in bytes of
- * @sid_str if @sid_str is not NULL.
- *
- * The standard textual representation of the SID is of the form:
- *     S-R-I-S-S...
- * Where:
- *    - The first "S" is the literal character 'S' identifying the following
- *     digits as a SID.
- *    - R is the revision level of the SID expressed as a sequence of digits
- *     in decimal.
- *    - I is the 48-bit identifier_authority, expressed as digits in decimal,
- *     if I < 2^32, or hexadecimal prefixed by "0x", if I >= 2^32.
- *    - S... is one or more sub_authority values, expressed as digits in
- *     decimal.
- *
- * If @sid_str is not NULL it will contain the converted SUID on return.  If it
- * is NULL a string will be allocated and this will be returned.  The caller is
- * responsible for free()ing the string in that case.
- *
- * On success return the converted string and on failure return NULL with errno
- * set to the error code.
- */
-char *ntfs_sid_to_mbs(const SID *sid, char *sid_str, size_t sid_str_size)
-{
-       u64 u;
-       le32 leauth;
-       char *s;
-       int i, j, cnt;
-
-       /*
-        * No need to check @sid if !@sid_str since ntfs_sid_to_mbs_size() will
-        * check @sid, too.  8 is the minimum SID string size.
-        */
-       if (sid_str && (sid_str_size < 8 || !ntfs_sid_is_valid(sid))) {
-               errno = EINVAL;
-               return NULL;
-       }
-       /* Allocate string if not provided. */
-       if (!sid_str) {
-               cnt = ntfs_sid_to_mbs_size(sid);
-               if (cnt < 0)
-                       return NULL;
-               s = (char*)ntfs_malloc(cnt);
-               if (!s)
-                       return s;
-               sid_str = s;
-               /* So we know we allocated it. */
-               sid_str_size = 0;
-       } else {
-               s = sid_str;
-               cnt = sid_str_size;
-       }
-       /* Start with "S-R-". */
-       i = snprintf(s, cnt, "S-%hhu-", (unsigned char)sid->revision);
-       if (i < 0 || i >= cnt)
-               goto err_out;
-       s += i;
-       cnt -= i;
-       /* Add the identifier authority. */
-       for (u = i = 0, j = 40; i < 6; i++, j -= 8)
-               u += (u64)sid->identifier_authority.value[i] << j;
-       if (!sid->identifier_authority.high_part)
-               i = snprintf(s, cnt, "%lu", (unsigned long)u);
-       else
-               i = snprintf(s, cnt, "0x%llx", (unsigned long long)u);
-       if (i < 0 || i >= cnt)
-               goto err_out;
-       s += i;
-       cnt -= i;
-       /* Finally, add the sub authorities. */
-       for (j = 0; j < sid->sub_authority_count; j++) {
-               leauth = sid->sub_authority[j];
-               i = snprintf(s, cnt, "-%u", (unsigned int)
-                               le32_to_cpu(leauth));
-               if (i < 0 || i >= cnt)
-                       goto err_out;
-               s += i;
-               cnt -= i;
-       }
-       return sid_str;
-err_out:
-       if (i >= cnt)
-               i = EMSGSIZE;
-       else
-               i = errno;
-       if (!sid_str_size)
-               free(sid_str);
-       errno = i;
-       return NULL;
-}
-
-/**
- * ntfs_generate_guid - generatates a random current guid.
- * @guid:      [OUT]   pointer to a GUID struct to hold the generated guid.
- *
- * perhaps not a very good random number generator though...
- */
-void ntfs_generate_guid(GUID *guid)
-{
-       unsigned int i;
-       u8 *p = (u8 *)guid;
-
-       for (i = 0; i < sizeof(GUID); i++) {
-               p[i] = (u8)(random() & 0xFF);
-               if (i == 7)
-                       p[7] = (p[7] & 0x0F) | 0x40;
-               if (i == 8)
-                       p[8] = (p[8] & 0x3F) | 0x80;
-       }
-}
-
-/**
- * ntfs_security_hash - calculate the hash of a security descriptor
- * @sd:         self-relative security descriptor whose hash to calculate
- * @length:     size in bytes of the security descritor @sd
- *
- * Calculate the hash of the self-relative security descriptor @sd of length
- * @length bytes.
- *
- * This hash is used in the $Secure system file as the primary key for the $SDH
- * index and is also stored in the header of each security descriptor in the
- * $SDS data stream as well as in the index data of both the $SII and $SDH
- * indexes.  In all three cases it forms part of the SDS_ENTRY_HEADER
- * structure.
- *
- * Return the calculated security hash in little endian.
- */
-le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd, const u32 len)
-{
-       const le32 *pos = (const le32*)sd;
-       const le32 *end = pos + (len >> 2);
-       u32 hash = 0;
-
-       while (pos < end) {
-               hash = le32_to_cpup(pos) + ntfs_rol32(hash, 3);
-               pos++;
-       }
-       return cpu_to_le32(hash);
-}
-
-/*
- *     Get the first entry of current index block
- *     cut and pasted form ntfs_ie_get_first() in index.c
- */
-
-static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
-{
-       return (INDEX_ENTRY*)((u8*)ih + le32_to_cpu(ih->entries_offset));
-}
-
-/*
- *             Stuff a 256KB block into $SDS before writing descriptors
- *     into the block.
- *
- *     This prevents $SDS from being automatically declared as sparse
- *     when the second copy of the first security descriptor is written
- *     256KB further ahead.
- *
- *     Having $SDS declared as a sparse file is not wrong by itself
- *     and chkdsk leaves it as a sparse file. It does however complain
- *     and add a sparse flag (0x0200) into field file_attributes of
- *     STANDARD_INFORMATION of $Secure. This probably means that a
- *     sparse attribute (ATTR_IS_SPARSE) is only allowed in sparse
- *     files (FILE_ATTR_SPARSE_FILE).
- *
- *     Windows normally does not convert to sparse attribute or sparse
- *     file. Stuffing is just a way to get to the same result.
- */
-
-static int entersecurity_stuff(ntfs_volume *vol, off_t offs)
-{
-       int res;
-       int written;
-       unsigned long total;
-       char *stuff;
-
-       res = 0;
-       total = 0;
-       stuff = (char*)ntfs_malloc(STUFFSZ);
-       if (stuff) {
-               memset(stuff, 0, STUFFSZ);
-               do {
-                       written = ntfs_attr_data_write(vol->secure_ni,
-                               STREAM_SDS, 4, stuff, STUFFSZ, offs);
-                       if (written == STUFFSZ) {
-                               total += STUFFSZ;
-                               offs += STUFFSZ;
-                       } else {
-                               errno = ENOSPC;
-                               res = -1;
-                       }
-               } while (!res && (total < ALIGN_SDS_BLOCK));
-               free(stuff);
-       } else {
-               errno = ENOMEM;
-               res = -1;
-       }
-       return (res);
-}
-
-/*
- *             Enter a new security descriptor into $Secure (data only)
- *      it has to be written twice with an offset of 256KB
- *
- *     Should only be called by entersecurityattr() to ensure consistency
- *
- *     Returns zero if sucessful
- */
-
-static int entersecurity_data(ntfs_volume *vol,
-                       const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
-                       le32 hash, le32 keyid, off_t offs, int gap)
-{
-       int res;
-       int written1;
-       int written2;
-       char *fullattr;
-       int fullsz;
-       SECURITY_DESCRIPTOR_HEADER *phsds;
-
-       res = -1;
-       fullsz = attrsz + gap + sizeof(SECURITY_DESCRIPTOR_HEADER);
-       fullattr = (char*)ntfs_malloc(fullsz);
-       if (fullattr) {
-                       /*
-                        * Clear the gap from previous descriptor
-                        * this could be useful for appending the second
-                        * copy to the end of file. When creating a new
-                        * 256K block, the gap is cleared while writing
-                        * the first copy
-                        */
-               if (gap)
-                       memset(fullattr,0,gap);
-               memcpy(&fullattr[gap + sizeof(SECURITY_DESCRIPTOR_HEADER)],
-                               attr,attrsz);
-               phsds = (SECURITY_DESCRIPTOR_HEADER*)&fullattr[gap];
-               phsds->hash = hash;
-               phsds->security_id = keyid;
-               phsds->offset = cpu_to_le64(offs);
-               phsds->length = cpu_to_le32(fullsz - gap);
-               written1 = ntfs_attr_data_write(vol->secure_ni,
-                       STREAM_SDS, 4, fullattr, fullsz,
-                       offs - gap);
-               written2 = ntfs_attr_data_write(vol->secure_ni,
-                       STREAM_SDS, 4, fullattr, fullsz,
-                       offs - gap + ALIGN_SDS_BLOCK);
-               if ((written1 == fullsz)
-                    && (written2 == written1))
-                       res = 0;
-               else
-                       errno = ENOSPC;
-               free(fullattr);
-       } else
-               errno = ENOMEM;
-       return (res);
-}
-
-/*
- *     Enter a new security descriptor in $Secure (indexes only)
- *
- *     Should only be called by entersecurityattr() to ensure consistency
- *
- *     Returns zero if sucessful
- */
-
-static int entersecurity_indexes(ntfs_volume *vol, s64 attrsz,
-                       le32 hash, le32 keyid, off_t offs)
-{
-       union {
-               struct {
-                       le32 dataoffsl;
-                       le32 dataoffsh;
-               } parts;
-               le64 all;
-       } realign;
-       int res;
-       ntfs_index_context *xsii;
-       ntfs_index_context *xsdh;
-       struct SII newsii;
-       struct SDH newsdh;
-
-       res = -1;
-                               /* enter a new $SII record */
-
-       xsii = vol->secure_xsii;
-       ntfs_index_ctx_reinit(xsii);
-       newsii.offs = const_cpu_to_le16(20);
-       newsii.size = const_cpu_to_le16(sizeof(struct SII) - 20);
-       newsii.fill1 = const_cpu_to_le32(0);
-       newsii.indexsz = const_cpu_to_le16(sizeof(struct SII));
-       newsii.indexksz = const_cpu_to_le16(sizeof(SII_INDEX_KEY));
-       newsii.flags = const_cpu_to_le16(0);
-       newsii.fill2 = const_cpu_to_le16(0);
-       newsii.keysecurid = keyid;
-       newsii.hash = hash;
-       newsii.securid = keyid;
-       realign.all = cpu_to_le64(offs);
-       newsii.dataoffsh = realign.parts.dataoffsh;
-       newsii.dataoffsl = realign.parts.dataoffsl;
-       newsii.datasize = cpu_to_le32(attrsz
-                        + sizeof(SECURITY_DESCRIPTOR_HEADER));
-       if (!ntfs_ie_add(xsii,(INDEX_ENTRY*)&newsii)) {
-
-               /* enter a new $SDH record */
-
-               xsdh = vol->secure_xsdh;
-               ntfs_index_ctx_reinit(xsdh);
-               newsdh.offs = const_cpu_to_le16(24);
-               newsdh.size = const_cpu_to_le16(
-                       sizeof(SECURITY_DESCRIPTOR_HEADER));
-               newsdh.fill1 = const_cpu_to_le32(0);
-               newsdh.indexsz = const_cpu_to_le16(
-                               sizeof(struct SDH));
-               newsdh.indexksz = const_cpu_to_le16(
-                               sizeof(SDH_INDEX_KEY));
-               newsdh.flags = const_cpu_to_le16(0);
-               newsdh.fill2 = const_cpu_to_le16(0);
-               newsdh.keyhash = hash;
-               newsdh.keysecurid = keyid;
-               newsdh.hash = hash;
-               newsdh.securid = keyid;
-               newsdh.dataoffsh = realign.parts.dataoffsh;
-               newsdh.dataoffsl = realign.parts.dataoffsl;
-               newsdh.datasize = cpu_to_le32(attrsz
-                        + sizeof(SECURITY_DESCRIPTOR_HEADER));
-                           /* special filler value, Windows generally */
-                           /* fills with 0x00490049, sometimes with zero */
-               newsdh.fill3 = const_cpu_to_le32(0x00490049);
-               if (!ntfs_ie_add(xsdh,(INDEX_ENTRY*)&newsdh))
-                       res = 0;
-       }
-       return (res);
-}
-
-/*
- *     Enter a new security descriptor in $Secure (data and indexes)
- *     Returns id of entry, or zero if there is a problem.
- *     (should not be called for NTFS version < 3.0)
- *
- *     important : calls have to be serialized, however no locking is
- *     needed while fuse is not multithreaded
- */
-
-static le32 entersecurityattr(ntfs_volume *vol,
-                       const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz,
-                       le32 hash)
-{
-       union {
-               struct {
-                       le32 dataoffsl;
-                       le32 dataoffsh;
-               } parts;
-               le64 all;
-       } realign;
-       le32 securid;
-       le32 keyid;
-       u32 newkey;
-       off_t offs;
-       int gap;
-       int size;
-       BOOL found;
-       struct SII *psii;
-       INDEX_ENTRY *entry;
-       INDEX_ENTRY *next;
-       ntfs_index_context *xsii;
-       int retries;
-       ntfs_attr *na;
-       int olderrno;
-
-       /* find the first available securid beyond the last key */
-       /* in $Secure:$SII. This also determines the first */
-       /* available location in $Secure:$SDS, as this stream */
-       /* is always appended to and the id's are allocated */
-       /* in sequence */
-
-       securid = const_cpu_to_le32(0);
-       xsii = vol->secure_xsii;
-       ntfs_index_ctx_reinit(xsii);
-       offs = size = 0;
-       keyid = const_cpu_to_le32(-1);
-       olderrno = errno;
-       found = !ntfs_index_lookup((char*)&keyid,
-                              sizeof(SII_INDEX_KEY), xsii);
-       if (!found && (errno != ENOENT)) {
-               ntfs_log_perror("Inconsistency in index $SII");
-               psii = (struct SII*)NULL;
-       } else {
-                       /* restore errno to avoid misinterpretation */
-               errno = olderrno;
-               entry = xsii->entry;
-               psii = (struct SII*)xsii->entry;
-       }
-       if (psii) {
-               /*
-                * Get last entry in block, but must get first one
-                * one first, as we should already be beyond the
-                * last one. For some reason the search for the last
-                * entry sometimes does not return the last block...
-                * we assume this can only happen in root block
-                */
-               if (xsii->is_in_root)
-                       entry = ntfs_ie_get_first
-                               ((INDEX_HEADER*)&xsii->ir->index);
-               else
-                       entry = ntfs_ie_get_first
-                               ((INDEX_HEADER*)&xsii->ib->index);
-               /*
-                * All index blocks should be at least half full
-                * so there always is a last entry but one,
-                * except when creating the first entry in index root.
-                * This was however found not to be true : chkdsk
-                * sometimes deletes all the (unused) keys in the last
-                * index block without rebalancing the tree.
-                * When this happens, a new search is restarted from
-                * the smallest key.
-                */
-               keyid = const_cpu_to_le32(0);
-               retries = 0;
-               while (entry) {
-                       next = ntfs_index_next(entry,xsii);
-                       if (next) { 
-                               psii = (struct SII*)next;
-                                       /* save last key and */
-                                       /* available position */
-                               keyid = psii->keysecurid;
-                               realign.parts.dataoffsh
-                                                = psii->dataoffsh;
-                               realign.parts.dataoffsl
-                                                = psii->dataoffsl;
-                               offs = le64_to_cpu(realign.all);
-                               size = le32_to_cpu(psii->datasize);
-                       }
-                       entry = next;
-                       if (!entry && !keyid && !retries) {
-                               /* search failed, retry from smallest key */
-                               ntfs_index_ctx_reinit(xsii);
-                               found = !ntfs_index_lookup((char*)&keyid,
-                                              sizeof(SII_INDEX_KEY), xsii);
-                               if (!found && (errno != ENOENT)) {
-                                       ntfs_log_perror("Index $SII is broken");
-                               } else {
-                                               /* restore errno */
-                                       errno = olderrno;
-                                       entry = xsii->entry;
-                               }
-                               retries++;
-                       }
-               }
-       }
-       if (!keyid) {
-               /*
-                * could not find any entry, before creating the first
-                * entry, make a double check by making sure size of $SII
-                * is less than needed for one entry
-                */
-               securid = const_cpu_to_le32(0);
-               na = ntfs_attr_open(vol->secure_ni,AT_INDEX_ROOT,sii_stream,4);
-               if (na) {
-                       if ((size_t)na->data_size < sizeof(struct SII)) {
-                               ntfs_log_error("Creating the first security_id\n");
-                               securid = const_cpu_to_le32(FIRST_SECURITY_ID);
-                       }
-                       ntfs_attr_close(na);
-               }
-               if (!securid) {
-                       ntfs_log_error("Error creating a security_id\n");
-                       errno = EIO;
-               }
-       } else {
-               newkey = le32_to_cpu(keyid) + 1;
-               securid = cpu_to_le32(newkey);
-       }
-       /*
-        * The security attr has to be written twice 256KB
-        * apart. This implies that offsets like
-        * 0x40000*odd_integer must be left available for
-        * the second copy. So align to next block when
-        * the last byte overflows on a wrong block.
-        */
-
-       if (securid) {
-               gap = (-size) & (ALIGN_SDS_ENTRY - 1);
-               offs += gap + size;
-               if ((offs + attrsz + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
-                  & ALIGN_SDS_BLOCK) {
-                       offs = ((offs + attrsz
-                                + sizeof(SECURITY_DESCRIPTOR_HEADER) - 1)
-                               | (ALIGN_SDS_BLOCK - 1)) + 1;
-               }
-               if (!(offs & (ALIGN_SDS_BLOCK - 1)))
-                       entersecurity_stuff(vol, offs);
-               /*
-                * now write the security attr to storage :
-                * first data, then SII, then SDH
-                * If failure occurs while writing SDS, data will never
-                *    be accessed through indexes, and will be overwritten
-                *    by the next allocated descriptor
-                * If failure occurs while writing SII, the id has not
-                *    recorded and will be reallocated later
-                * If failure occurs while writing SDH, the space allocated
-                *    in SDS or SII will not be reused, an inconsistency
-                *    will persist with no significant consequence
-                */
-               if (entersecurity_data(vol, attr, attrsz, hash, securid, offs, gap)
-                   || entersecurity_indexes(vol, attrsz, hash, securid, offs))
-                       securid = const_cpu_to_le32(0);
-       }
-               /* inode now is dirty, synchronize it all */
-       ntfs_index_entry_mark_dirty(vol->secure_xsii);
-       ntfs_index_ctx_reinit(vol->secure_xsii);
-       ntfs_index_entry_mark_dirty(vol->secure_xsdh);
-       ntfs_index_ctx_reinit(vol->secure_xsdh);
-       NInoSetDirty(vol->secure_ni);
-       if (ntfs_inode_sync(vol->secure_ni))
-               ntfs_log_perror("Could not sync $Secure\n");
-       return (securid);
-}
-
-/*
- *             Find a matching security descriptor in $Secure,
- *     if none, allocate a new id and write the descriptor to storage
- *     Returns id of entry, or zero if there is a problem.
- *
- *     important : calls have to be serialized, however no locking is
- *     needed while fuse is not multithreaded
- */
-
-static le32 setsecurityattr(ntfs_volume *vol,
-                       const SECURITY_DESCRIPTOR_RELATIVE *attr, s64 attrsz)
-{
-       struct SDH *psdh;       /* this is an image of index (le) */
-       union {
-               struct {
-                       le32 dataoffsl;
-                       le32 dataoffsh;
-               } parts;
-               le64 all;
-       } realign;
-       BOOL found;
-       BOOL collision;
-       size_t size;
-       size_t rdsize;
-       s64 offs;
-       int res;
-       ntfs_index_context *xsdh;
-       char *oldattr;
-       SDH_INDEX_KEY key;
-       INDEX_ENTRY *entry;
-       le32 securid;
-       le32 hash;
-       int olderrno;
-
-       hash = ntfs_security_hash(attr,attrsz);
-       oldattr = (char*)NULL;
-       securid = const_cpu_to_le32(0);
-       res = 0;
-       xsdh = vol->secure_xsdh;
-       if (vol->secure_ni && xsdh && !vol->secure_reentry++) {
-               ntfs_index_ctx_reinit(xsdh);
-               /*
-                * find the nearest key as (hash,0)
-                * (do not search for partial key : in case of collision,
-                * it could return a key which is not the first one which
-                * collides)
-                */
-               key.hash = hash;
-               key.security_id = const_cpu_to_le32(0);
-               olderrno = errno;
-               found = !ntfs_index_lookup((char*)&key,
-                                sizeof(SDH_INDEX_KEY), xsdh);
-               if (!found && (errno != ENOENT))
-                       ntfs_log_perror("Inconsistency in index $SDH");
-               else {
-                               /* restore errno to avoid misinterpretation */
-                       errno = olderrno;
-                       entry = xsdh->entry;
-                       found = FALSE;
-                       /*
-                        * lookup() may return a node with no data,
-                        * if so get next
-                        */
-                       if (entry->ie_flags & INDEX_ENTRY_END)
-                               entry = ntfs_index_next(entry,xsdh);
-                       do {
-                               collision = FALSE;
-                               psdh = (struct SDH*)entry;
-                               if (psdh)
-                                       size = (size_t) le32_to_cpu(psdh->datasize)
-                                                - sizeof(SECURITY_DESCRIPTOR_HEADER);
-                               else size = 0;
-                          /* if hash is not the same, the key is not present */
-                               if (psdh && (size > 0)
-                                  && (psdh->keyhash == hash)) {
-                                          /* if hash is the same */
-                                          /* check the whole record */
-                                       realign.parts.dataoffsh = psdh->dataoffsh;
-                                       realign.parts.dataoffsl = psdh->dataoffsl;
-                                       offs = le64_to_cpu(realign.all)
-                                               + sizeof(SECURITY_DESCRIPTOR_HEADER);
-                                       oldattr = (char*)ntfs_malloc(size);
-                                       if (oldattr) {
-                                               rdsize = ntfs_attr_data_read(
-                                                       vol->secure_ni,
-                                                       STREAM_SDS, 4,
-                                                       oldattr, size, offs);
-                                               found = (rdsize == size)
-                                                       && !memcmp(oldattr,attr,size);
-                                               free(oldattr);
-                                         /* if the records do not compare */
-                                         /* (hash collision), try next one */
-                                               if (!found) {
-                                                       entry = ntfs_index_next(
-                                                               entry,xsdh);
-                                                       collision = TRUE;
-                                               }
-                                       } else
-                                               res = ENOMEM;
-                               }
-                       } while (collision && entry);
-                       if (found)
-                               securid = psdh->keysecurid;
-                       else {
-                               if (res) {
-                                       errno = res;
-                                       securid = const_cpu_to_le32(0);
-                               } else {
-                                       /*
-                                        * no matching key :
-                                        * have to build a new one
-                                        */
-                                       securid = entersecurityattr(vol,
-                                               attr, attrsz, hash);
-                               }
-                       }
-               }
-       }
-       if (--vol->secure_reentry)
-               ntfs_log_perror("Reentry error, check no multithreading\n");
-       return (securid);
-}
-
-
-/*
- *             Update the security descriptor of a file
- *     Either as an attribute (complying with pre v3.x NTFS version)
- *     or, when possible, as an entry in $Secure (for NTFS v3.x)
- *
- *     returns 0 if success
- */
-
-static int update_secur_descr(ntfs_volume *vol,
-                               char *newattr, ntfs_inode *ni)
-{
-       int newattrsz;
-       int written;
-       int res;
-       ntfs_attr *na;
-
-       newattrsz = ntfs_attr_size(newattr);
-
-#if !FORCE_FORMAT_v1x
-       if ((vol->major_ver < 3) || !vol->secure_ni) {
-#endif
-
-               /* update for NTFS format v1.x */
-
-               /* update the old security attribute */
-               na = ntfs_attr_open(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0);
-               if (na) {
-                       /* resize attribute */
-                       res = ntfs_attr_truncate(na, (s64) newattrsz);
-                       /* overwrite value */
-                       if (!res) {
-                               written = (int)ntfs_attr_pwrite(na, (s64) 0,
-                                        (s64) newattrsz, newattr);
-                               if (written != newattrsz) {
-                                       ntfs_log_error("Failed to update "
-                                               "a v1.x security descriptor\n");
-                                       errno = EIO;
-                                       res = -1;
-                               }
-                       }
-
-                       ntfs_attr_close(na);
-                       /* if old security attribute was found, also */
-                       /* truncate standard information attribute to v1.x */
-                       /* this is needed when security data is wanted */
-                       /* as v1.x though volume is formatted for v3.x */
-                       na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
-                               AT_UNNAMED, 0);
-                       if (na) {
-                               clear_nino_flag(ni, v3_Extensions);
-                       /*
-                        * Truncating the record does not sweep extensions
-                        * from copy in memory. Clear security_id to be safe
-                        */
-                               ni->security_id = const_cpu_to_le32(0);
-                               res = ntfs_attr_truncate(na, (s64)48);
-                               ntfs_attr_close(na);
-                               clear_nino_flag(ni, v3_Extensions);
-                       }
-               } else {
-                       /*
-                        * insert the new security attribute if there
-                        * were none
-                        */
-                       res = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR,
-                                           AT_UNNAMED, 0, (u8*)newattr,
-                                           (s64) newattrsz);
-               }
-#if !FORCE_FORMAT_v1x
-       } else {
-
-               /* update for NTFS format v3.x */
-
-               le32 securid;
-
-               securid = setsecurityattr(vol,
-                       (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
-                       (s64)newattrsz);
-               if (securid) {
-                       na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
-                               AT_UNNAMED, 0);
-                       if (na) {
-                               res = 0;
-                               if (!test_nino_flag(ni, v3_Extensions)) {
-                       /* expand standard information attribute to v3.x */
-                                       res = ntfs_attr_truncate(na,
-                                        (s64)sizeof(STANDARD_INFORMATION));
-                                       ni->owner_id = const_cpu_to_le32(0);
-                                       ni->quota_charged = const_cpu_to_le64(0);
-                                       ni->usn = const_cpu_to_le64(0);
-                                       ntfs_attr_remove(ni,
-                                               AT_SECURITY_DESCRIPTOR,
-                                               AT_UNNAMED, 0);
-                       }
-                               set_nino_flag(ni, v3_Extensions);
-                               ni->security_id = securid;
-                               ntfs_attr_close(na);
-                       } else {
-                               ntfs_log_error("Failed to update "
-                                       "standard informations\n");
-                               errno = EIO;
-                               res = -1;
-                       }
-               } else
-                       res = -1;
-       }
-#endif
-
-       /* mark node as dirty */
-       NInoSetDirty(ni);
-       return (res);
-}
-
-/*
- *             Upgrade the security descriptor of a file
- *     This is intended to allow graceful upgrades for files which
- *     were created in previous versions, with a security attributes
- *     and no security id.
- *     
- *      It will allocate a security id and replace the individual
- *     security attribute by a reference to the global one
- *
- *     Special files are not upgraded (currently / and files in
- *     directories /$*)
- *
- *     Though most code is similar to update_secur_desc() it has
- *     been kept apart to facilitate the further processing of
- *     special cases or even to remove it if found dangerous.
- *
- *     returns 0 if success,
- *             1 if not upgradable. This is not an error.
- *             -1 if there is a problem
- */
-
-static int upgrade_secur_desc(ntfs_volume *vol,
-                               const char *attr, ntfs_inode *ni)
-{
-       int attrsz;
-       int res;
-       le32 securid;
-       ntfs_attr *na;
-
-               /*
-                * upgrade requires NTFS format v3.x
-                * also refuse upgrading for special files
-                * whose number is less than FILE_first_user
-                */
-
-       if ((vol->major_ver >= 3)
-           && (ni->mft_no >= FILE_first_user)) {
-               attrsz = ntfs_attr_size(attr);
-               securid = setsecurityattr(vol,
-                       (const SECURITY_DESCRIPTOR_RELATIVE*)attr,
-                       (s64)attrsz);
-               if (securid) {
-                       na = ntfs_attr_open(ni, AT_STANDARD_INFORMATION,
-                               AT_UNNAMED, 0);
-                       if (na) {
-                       /* expand standard information attribute to v3.x */
-                               res = ntfs_attr_truncate(na,
-                                        (s64)sizeof(STANDARD_INFORMATION));
-                               ni->owner_id = const_cpu_to_le32(0);
-                               ni->quota_charged = const_cpu_to_le64(0);
-                               ni->usn = const_cpu_to_le64(0);
-                               ntfs_attr_remove(ni, AT_SECURITY_DESCRIPTOR,
-                                               AT_UNNAMED, 0);
-                               set_nino_flag(ni, v3_Extensions);
-                               ni->security_id = securid;
-                               ntfs_attr_close(na);
-                       } else {
-                               ntfs_log_error("Failed to upgrade "
-                                       "standard informations\n");
-                               errno = EIO;
-                               res = -1;
-                       }
-               } else
-                       res = -1;
-                       /* mark node as dirty */
-               NInoSetDirty(ni);
-       } else
-               res = 1;
-
-       return (res);
-}
-
-/*
- *             Optional simplified checking of group membership
- *
- *     This only takes into account the groups defined in
- *     /etc/group at initialization time.
- *     It does not take into account the groups dynamically set by
- *     setgroups() nor the changes in /etc/group since initialization
- *
- *     This optional method could be useful if standard checking
- *     leads to a performance concern.
- *
- *     Should not be called for user root, however the group may be root
- *
- */
-
-static BOOL staticgroupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
-{
-       BOOL ingroup;
-       int grcnt;
-       gid_t *groups;
-       struct MAPPING *user;
-
-       ingroup = FALSE;
-       if (uid) {
-               user = scx->mapping[MAPUSERS];
-               while (user && ((uid_t)user->xid != uid))
-                       user = user->next;
-               if (user) {
-                       groups = user->groups;
-                       grcnt = user->grcnt;
-                       while ((--grcnt >= 0) && (groups[grcnt] != gid)) { }
-                       ingroup = (grcnt >= 0);
-               }
-       }
-       return (ingroup);
-}
-
-
-/*
- *             Check whether current thread owner is member of file group
- *
- *     Should not be called for user root, however the group may be root
- *
- * As indicated by Miklos Szeredi :
- *
- * The group list is available in
- *
- *   /proc/$PID/task/$TID/status
- *
- * and fuse supplies TID in get_fuse_context()->pid.  The only problem is
- * finding out PID, for which I have no good solution, except to iterate
- * through all processes.  This is rather slow, but may be speeded up
- * with caching and heuristics (for single threaded programs PID = TID).
- *
- * The following implementation gets the group list from
- *   /proc/$TID/task/$TID/status which apparently exists and
- * contains the same data.
- */
-
-static BOOL groupmember(struct SECURITY_CONTEXT *scx, uid_t uid, gid_t gid)
-{
-       static char key[] = "\nGroups:";
-       char buf[BUFSZ+1];
-       char filename[64];
-       enum { INKEY, INSEP, INNUM, INEND } state;
-       int fd;
-       char c;
-       int matched;
-       BOOL ismember;
-       int got;
-       char *p;
-       gid_t grp;
-       pid_t tid;
-
-       if (scx->vol->secure_flags & (1 << SECURITY_STATICGRPS))
-               ismember = staticgroupmember(scx, uid, gid);
-       else {
-               ismember = FALSE; /* default return */
-               tid = scx->tid;
-               sprintf(filename,"/proc/%u/task/%u/status",tid,tid);
-               fd = open(filename,O_RDONLY);
-               if (fd >= 0) {
-                       got = read(fd, buf, BUFSZ);
-                       buf[got] = 0;
-                       state = INKEY;
-                       matched = 0;
-                       p = buf;
-                       grp = 0;
-                               /*
-                                *  A simple automaton to process lines like
-                                *  Groups: 14 500 513
-                                */
-                       do {
-                               c = *p++;
-                               if (!c) {
-                                       /* refill buffer */
-                                       got = read(fd, buf, BUFSZ);
-                                       buf[got] = 0;
-                                       p = buf;
-                                       c = *p++; /* 0 at end of file */
-                               }
-                               switch (state) {
-                               case INKEY :
-                                       if (key[matched] == c) {
-                                               if (!key[++matched])
-                                                       state = INSEP;
-                                       } else
-                                               if (key[0] == c)
-                                                       matched = 1;
-                                               else
-                                                       matched = 0;
-                                       break;
-                               case INSEP :
-                                       if ((c >= '0') && (c <= '9')) {
-                                               grp = c - '0';
-                                               state = INNUM;
-                                       } else
-                                               if ((c != ' ') && (c != '\t'))
-                                                       state = INEND;
-                                       break;
-                               case INNUM :
-                                       if ((c >= '0') && (c <= '9'))
-                                               grp = grp*10 + c - '0';
-                                       else {
-                                               ismember = (grp == gid);
-                                               if ((c != ' ') && (c != '\t'))
-                                                       state = INEND;
-                                               else
-                                                       state = INSEP;
-                                       }
-                               default :
-                                       break;
-                               }
-                       } while (!ismember && c && (state != INEND));
-               close(fd);
-               if (!c)
-                       ntfs_log_error("No group record found in %s\n",filename);
-               } else
-                       ntfs_log_error("Could not open %s\n",filename);
-       }
-       return (ismember);
-}
-
-/*
- *     Cacheing is done two-way :
- *     - from uid, gid and perm to securid (CACHED_SECURID)
- *     - from a securid to uid, gid and perm (CACHED_PERMISSIONS)
- *
- *     CACHED_SECURID data is kept in a most-recent-first list
- *     which should not be too long to be efficient. Its optimal
- *     size is depends on usage and is hard to determine.
- *
- *     CACHED_PERMISSIONS data is kept in a two-level indexed array. It
- *     is optimal at the expense of storage. Use of a most-recent-first
- *     list would save memory and provide similar performances for
- *     standard usage, but not for file servers with too many file
- *     owners
- *
- *     CACHED_PERMISSIONS_LEGACY is a special case for CACHED_PERMISSIONS
- *     for legacy directories which were not allocated a security_id
- *     it is organized in a most-recent-first list.
- *
- *     In main caches, data is never invalidated, as the meaning of
- *     a security_id only changes when user mapping is changed, which
- *     current implies remounting. However returned entries may be
- *     overwritten at next update, so data has to be copied elsewhere
- *     before another cache update is made.
- *     In legacy cache, data has to be invalidated when protection is
- *     changed.
- *
- *     Though the same data may be found in both list, they
- *     must be kept separately : the interpretation of ACL
- *     in both direction are approximations which could be non
- *     reciprocal for some configuration of the user mapping data
- *
- *     During the process of recompiling ntfs-3g from a tgz archive,
- *     security processing added 7.6% to the cpu time used by ntfs-3g
- *     and 30% if the cache is disabled.
- */
-
-static struct PERMISSIONS_CACHE *create_caches(struct SECURITY_CONTEXT *scx,
-                       u32 securindex)
-{
-       struct PERMISSIONS_CACHE *cache;
-       unsigned int index1;
-       unsigned int i;
-
-       cache = (struct PERMISSIONS_CACHE*)NULL;
-               /* create the first permissions blocks */
-       index1 = securindex >> CACHE_PERMISSIONS_BITS;
-       cache = (struct PERMISSIONS_CACHE*)
-               ntfs_malloc(sizeof(struct PERMISSIONS_CACHE)
-                     + index1*sizeof(struct CACHED_PERMISSIONS*));
-       if (cache) {
-               cache->head.last = index1;
-               cache->head.p_reads = 0;
-               cache->head.p_hits = 0;
-               cache->head.p_writes = 0;
-               *scx->pseccache = cache;
-               for (i=0; i<=index1; i++)
-                       cache->cachetable[i]
-                          = (struct CACHED_PERMISSIONS*)NULL;
-       }
-       return (cache);
-}
-
-/*
- *             Free memory used by caches
- *     The only purpose is to facilitate the detection of memory leaks
- */
-
-static void free_caches(struct SECURITY_CONTEXT *scx)
-{
-       unsigned int index1;
-       struct PERMISSIONS_CACHE *pseccache;
-
-       pseccache = *scx->pseccache;
-       if (pseccache) {
-               for (index1=0; index1<=pseccache->head.last; index1++)
-                       if (pseccache->cachetable[index1]) {
-#if POSIXACLS
-                               struct CACHED_PERMISSIONS *cacheentry;
-                               unsigned int index2;
-
-                               for (index2=0; index2<(1<< CACHE_PERMISSIONS_BITS); index2++) {
-                                       cacheentry = &pseccache->cachetable[index1][index2];
-                                       if (cacheentry->valid
-                                           && cacheentry->pxdesc)
-                                               free(cacheentry->pxdesc);
-                                       }
-#endif
-                               free(pseccache->cachetable[index1]);
-                       }
-               free(pseccache);
-       }
-}
-
-static int compare(const struct CACHED_SECURID *cached,
-                       const struct CACHED_SECURID *item)
-{
-#if POSIXACLS
-       size_t csize;
-       size_t isize;
-
-               /* only compare data and sizes */
-       csize = (cached->variable ?
-               sizeof(struct POSIX_ACL)
-               + (((struct POSIX_SECURITY*)cached->variable)->acccnt
-                  + ((struct POSIX_SECURITY*)cached->variable)->defcnt)
-                       *sizeof(struct POSIX_ACE) :
-               0);
-       isize = (item->variable ?
-               sizeof(struct POSIX_ACL)
-               + (((struct POSIX_SECURITY*)item->variable)->acccnt
-                  + ((struct POSIX_SECURITY*)item->variable)->defcnt)
-                       *sizeof(struct POSIX_ACE) :
-               0);
-       return ((cached->uid != item->uid)
-                || (cached->gid != item->gid)
-                || (cached->dmode != item->dmode)
-                || (csize != isize)
-                || (csize
-                   && isize
-                   && memcmp(&((struct POSIX_SECURITY*)cached->variable)->acl,
-                      &((struct POSIX_SECURITY*)item->variable)->acl, csize)));
-#else
-       return ((cached->uid != item->uid)
-                || (cached->gid != item->gid)
-                || (cached->dmode != item->dmode));
-#endif
-}
-
-static int leg_compare(const struct CACHED_PERMISSIONS_LEGACY *cached,
-                       const struct CACHED_PERMISSIONS_LEGACY *item)
-{
-       return (cached->mft_no != item->mft_no);
-}
-
-/*
- *     Resize permission cache table
- *     do not call unless resizing is needed
- *     
- *     If allocation fails, the cache size is not updated
- *     Lack of memory is not considered as an error, the cache is left
- *     consistent and errno is not set.
- */
-
-static void resize_cache(struct SECURITY_CONTEXT *scx,
-                       u32 securindex)
-{
-       struct PERMISSIONS_CACHE *oldcache;
-       struct PERMISSIONS_CACHE *newcache;
-       int newcnt;
-       int oldcnt;
-       unsigned int index1;
-       unsigned int i;
-
-       oldcache = *scx->pseccache;
-       index1 = securindex >> CACHE_PERMISSIONS_BITS;
-       newcnt = index1 + 1;
-       if (newcnt <= ((CACHE_PERMISSIONS_SIZE
-                       + (1 << CACHE_PERMISSIONS_BITS)
-                       - 1) >> CACHE_PERMISSIONS_BITS)) {
-               /* expand cache beyond current end, do not use realloc() */
-               /* to avoid losing data when there is no more memory */
-               oldcnt = oldcache->head.last + 1;
-               newcache = (struct PERMISSIONS_CACHE*)
-                       ntfs_malloc(
-                           sizeof(struct PERMISSIONS_CACHE)
-                             + (newcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
-               if (newcache) {
-                       memcpy(newcache,oldcache,
-                           sizeof(struct PERMISSIONS_CACHE)
-                             + (oldcnt - 1)*sizeof(struct CACHED_PERMISSIONS*));
-                       free(oldcache);
-                            /* mark new entries as not valid */
-                       for (i=newcache->head.last+1; i<=index1; i++)
-                               newcache->cachetable[i]
-                                        = (struct CACHED_PERMISSIONS*)NULL;
-                       newcache->head.last = index1;
-                       *scx->pseccache = newcache;
-               }
-       }
-}
-
-/*
- *     Enter uid, gid and mode into cache, if possible
- *
- *     returns the updated or created cache entry,
- *     or NULL if not possible (typically if there is no
- *             security id associated)
- */
-
-#if POSIXACLS
-static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
-               ntfs_inode *ni, uid_t uid, gid_t gid,
-               struct POSIX_SECURITY *pxdesc)
-#else
-static struct CACHED_PERMISSIONS *enter_cache(struct SECURITY_CONTEXT *scx,
-               ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode)
-#endif
-{
-       struct CACHED_PERMISSIONS *cacheentry;
-       struct CACHED_PERMISSIONS *cacheblock;
-       struct PERMISSIONS_CACHE *pcache;
-       u32 securindex;
-#if POSIXACLS
-       int pxsize;
-       struct POSIX_SECURITY *pxcached;
-#endif
-       unsigned int index1;
-       unsigned int index2;
-       int i;
-
-       /* cacheing is only possible if a security_id has been defined */
-       if (test_nino_flag(ni, v3_Extensions)
-          && ni->security_id) {
-               /*
-                *  Immediately test the most frequent situation
-                *  where the entry exists
-                */
-               securindex = le32_to_cpu(ni->security_id);
-               index1 = securindex >> CACHE_PERMISSIONS_BITS;
-               index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
-               pcache = *scx->pseccache;
-               if (pcache
-                    && (pcache->head.last >= index1)
-                    && pcache->cachetable[index1]) {
-                       cacheentry = &pcache->cachetable[index1][index2];
-                       cacheentry->uid = uid;
-                       cacheentry->gid = gid;
-#if POSIXACLS
-                       if (cacheentry->valid && cacheentry->pxdesc)
-                               free(cacheentry->pxdesc);
-                       if (pxdesc) {
-                               pxsize = sizeof(struct POSIX_SECURITY)
-                                       + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
-                               pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
-                               if (pxcached) {
-                                       memcpy(pxcached, pxdesc, pxsize);
-                                       cacheentry->pxdesc = pxcached;
-                               } else {
-                                       cacheentry->valid = 0;
-                                       cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-                               }
-                               cacheentry->mode = pxdesc->mode & 07777;
-                       } else
-                               cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
-#else
-                       cacheentry->mode = mode & 07777;
-#endif
-                       cacheentry->inh_fileid = const_cpu_to_le32(0);
-                       cacheentry->inh_dirid = const_cpu_to_le32(0);
-                       cacheentry->valid = 1;
-                       pcache->head.p_writes++;
-               } else {
-                       if (!pcache) {
-                               /* create the first cache block */
-                               pcache = create_caches(scx, securindex);
-                       } else {
-                               if (index1 > pcache->head.last) {
-                                       resize_cache(scx, securindex);
-                                       pcache = *scx->pseccache;
-                               }
-                       }
-                       /* allocate block, if cache table was allocated */
-                       if (pcache && (index1 <= pcache->head.last)) {
-                               cacheblock = (struct CACHED_PERMISSIONS*)
-                                       malloc(sizeof(struct CACHED_PERMISSIONS)
-                                               << CACHE_PERMISSIONS_BITS);
-                               pcache->cachetable[index1] = cacheblock;
-                               for (i=0; i<(1 << CACHE_PERMISSIONS_BITS); i++)
-                                       cacheblock[i].valid = 0;
-                               cacheentry = &cacheblock[index2];
-                               if (cacheentry) {
-                                       cacheentry->uid = uid;
-                                       cacheentry->gid = gid;
-#if POSIXACLS
-                                       if (pxdesc) {
-                                               pxsize = sizeof(struct POSIX_SECURITY)
-                                                       + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
-                                               pxcached = (struct POSIX_SECURITY*)malloc(pxsize);
-                                               if (pxcached) {
-                                                       memcpy(pxcached, pxdesc, pxsize);
-                                                       cacheentry->pxdesc = pxcached;
-                                               } else {
-                                                       cacheentry->valid = 0;
-                                                       cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-                                               }
-                                               cacheentry->mode = pxdesc->mode & 07777;
-                                       } else
-                                               cacheentry->pxdesc = (struct POSIX_SECURITY*)NULL;
-#else
-                                       cacheentry->mode = mode & 07777;
-#endif
-                                       cacheentry->inh_fileid = const_cpu_to_le32(0);
-                                       cacheentry->inh_dirid = const_cpu_to_le32(0);
-                                       cacheentry->valid = 1;
-                                       pcache->head.p_writes++;
-                               }
-                       } else
-                               cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-               }
-       } else {
-               cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-#if CACHE_LEGACY_SIZE
-               if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
-                       struct CACHED_PERMISSIONS_LEGACY wanted;
-                       struct CACHED_PERMISSIONS_LEGACY *legacy;
-
-                       wanted.perm.uid = uid;
-                       wanted.perm.gid = gid;
-#if POSIXACLS
-                       wanted.perm.mode = pxdesc->mode & 07777;
-                       wanted.perm.inh_fileid = const_cpu_to_le32(0);
-                       wanted.perm.inh_dirid = const_cpu_to_le32(0);
-                       wanted.mft_no = ni->mft_no;
-                       wanted.variable = (void*)pxdesc;
-                       wanted.varsize = sizeof(struct POSIX_SECURITY)
-                                       + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
-#else
-                       wanted.perm.mode = mode & 07777;
-                       wanted.perm.inh_fileid = const_cpu_to_le32(0);
-                       wanted.perm.inh_dirid = const_cpu_to_le32(0);
-                       wanted.mft_no = ni->mft_no;
-                       wanted.variable = (void*)NULL;
-                       wanted.varsize = 0;
-#endif
-                       legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_enter_cache(
-                               scx->vol->legacy_cache, GENERIC(&wanted),
-                               (cache_compare)leg_compare);
-                       if (legacy) {
-                               cacheentry = &legacy->perm;
-#if POSIXACLS
-                               /*
-                                * give direct access to the cached pxdesc
-                                * in the permissions structure
-                                */
-                               cacheentry->pxdesc = legacy->variable;
-#endif
-                       }
-               }
-#endif
-       }
-       return (cacheentry);
-}
-
-/*
- *     Fetch owner, group and permission of a file, if cached
- *
- *     Beware : do not use the returned entry after a cache update :
- *     the cache may be relocated making the returned entry meaningless
- *
- *     returns the cache entry, or NULL if not available
- */
-
-static struct CACHED_PERMISSIONS *fetch_cache(struct SECURITY_CONTEXT *scx,
-               ntfs_inode *ni)
-{
-       struct CACHED_PERMISSIONS *cacheentry;
-       struct PERMISSIONS_CACHE *pcache;
-       u32 securindex;
-       unsigned int index1;
-       unsigned int index2;
-
-       /* cacheing is only possible if a security_id has been defined */
-       cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-       if (test_nino_flag(ni, v3_Extensions)
-          && (ni->security_id)) {
-               securindex = le32_to_cpu(ni->security_id);
-               index1 = securindex >> CACHE_PERMISSIONS_BITS;
-               index2 = securindex & ((1 << CACHE_PERMISSIONS_BITS) - 1);
-               pcache = *scx->pseccache;
-               if (pcache
-                    && (pcache->head.last >= index1)
-                    && pcache->cachetable[index1]) {
-                       cacheentry = &pcache->cachetable[index1][index2];
-                       /* reject if entry is not valid */
-                       if (!cacheentry->valid)
-                               cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-                       else
-                               pcache->head.p_hits++;
-               if (pcache)
-                       pcache->head.p_reads++;
-               }
-       }
-#if CACHE_LEGACY_SIZE
-       else {
-               cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-               if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
-                       struct CACHED_PERMISSIONS_LEGACY wanted;
-                       struct CACHED_PERMISSIONS_LEGACY *legacy;
-
-                       wanted.mft_no = ni->mft_no;
-                       wanted.variable = (void*)NULL;
-                       wanted.varsize = 0;
-                       legacy = (struct CACHED_PERMISSIONS_LEGACY*)ntfs_fetch_cache(
-                               scx->vol->legacy_cache, GENERIC(&wanted),
-                               (cache_compare)leg_compare);
-                       if (legacy) cacheentry = &legacy->perm;
-               }
-       }
-#endif
-#if POSIXACLS
-       if (cacheentry && !cacheentry->pxdesc) {
-               ntfs_log_error("No Posix descriptor in cache\n");
-               cacheentry = (struct CACHED_PERMISSIONS*)NULL;
-       }
-#endif
-       return (cacheentry);
-}
-
-/*
- *     Retrieve a security attribute from $Secure
- */
-
-static char *retrievesecurityattr(ntfs_volume *vol, SII_INDEX_KEY id)
-{
-       struct SII *psii;
-       union {
-               struct {
-                       le32 dataoffsl;
-                       le32 dataoffsh;
-               } parts;
-               le64 all;
-       } realign;
-       int found;
-       size_t size;
-       size_t rdsize;
-       s64 offs;
-       ntfs_inode *ni;
-       ntfs_index_context *xsii;
-       char *securattr;
-
-       securattr = (char*)NULL;
-       ni = vol->secure_ni;
-       xsii = vol->secure_xsii;
-       if (ni && xsii) {
-               ntfs_index_ctx_reinit(xsii);
-               found =
-                   !ntfs_index_lookup((char*)&id,
-                                      sizeof(SII_INDEX_KEY), xsii);
-               if (found) {
-                       psii = (struct SII*)xsii->entry;
-                       size =
-                           (size_t) le32_to_cpu(psii->datasize)
-                                - sizeof(SECURITY_DESCRIPTOR_HEADER);
-                       /* work around bad alignment problem */
-                       realign.parts.dataoffsh = psii->dataoffsh;
-                       realign.parts.dataoffsl = psii->dataoffsl;
-                       offs = le64_to_cpu(realign.all)
-                               + sizeof(SECURITY_DESCRIPTOR_HEADER);
-
-                       securattr = (char*)ntfs_malloc(size);
-                       if (securattr) {
-                               rdsize = ntfs_attr_data_read(
-                                       ni, STREAM_SDS, 4,
-                                       securattr, size, offs);
-                               if ((rdsize != size)
-                                       || !ntfs_valid_descr(securattr,
-                                               rdsize)) {
-                                       /* error to be logged by caller */
-                                       free(securattr);
-                                       securattr = (char*)NULL;
-                               }
-                       }
-               } else
-                       if (errno != ENOENT)
-                               ntfs_log_perror("Inconsistency in index $SII");
-       }
-       if (!securattr) {
-               ntfs_log_error("Failed to retrieve a security descriptor\n");
-               errno = EIO;
-       }
-       return (securattr);
-}
-
-/*
- *             Get the security descriptor associated to a file
- *
- *     Either :
- *        - read the security descriptor attribute (v1.x format)
- *        - or find the descriptor in $Secure:$SDS (v3.x format)
- *
- *     in both case, sanity checks are done on the attribute and
- *     the descriptor can be assumed safe
- *
- *     The returned descriptor is dynamically allocated and has to be freed
- */
-
-static char *getsecurityattr(ntfs_volume *vol, ntfs_inode *ni)
-{
-       SII_INDEX_KEY securid;
-       char *securattr;
-       s64 readallsz;
-
-               /*
-                * Warning : in some situations, after fixing by chkdsk,
-                * v3_Extensions are marked present (long standard informations)
-                * with a default security descriptor inserted in an
-                * attribute
-                */
-       if (test_nino_flag(ni, v3_Extensions)
-                       && vol->secure_ni && ni->security_id) {
-                       /* get v3.x descriptor in $Secure */
-               securid.security_id = ni->security_id;
-               securattr = retrievesecurityattr(vol,securid);
-               if (!securattr)
-                       ntfs_log_error("Bad security descriptor for 0x%lx\n",
-                                       (long)le32_to_cpu(ni->security_id));
-       } else {
-                       /* get v1.x security attribute */
-               readallsz = 0;
-               securattr = ntfs_attr_readall(ni, AT_SECURITY_DESCRIPTOR,
-                               AT_UNNAMED, 0, &readallsz);
-               if (securattr && !ntfs_valid_descr(securattr, readallsz)) {
-                       ntfs_log_error("Bad security descriptor for inode %lld\n",
-                               (long long)ni->mft_no);
-                       free(securattr);
-                       securattr = (char*)NULL;
-               }
-       }
-       if (!securattr) {
-                       /*
-                        * in some situations, there is no security
-                        * descriptor, and chkdsk does not detect or fix
-                        * anything. This could be a normal situation.
-                        * When this happens, simulate a descriptor with
-                        * minimum rights, so that a real descriptor can
-                        * be created by chown or chmod
-                        */
-               ntfs_log_error("No security descriptor found for inode %lld\n",
-                               (long long)ni->mft_no);
-               securattr = ntfs_build_descr(0, 0, adminsid, adminsid);
-       }
-       return (securattr);
-}
-
-#if POSIXACLS
-
-/*
- *             Determine which access types to a file are allowed
- *     according to the relation of current process to the file
- *
- *     Do not call if default_permissions is set
- */
-
-static int access_check_posix(struct SECURITY_CONTEXT *scx,
-                       struct POSIX_SECURITY *pxdesc, mode_t request,
-                       uid_t uid, gid_t gid)
-{
-       struct POSIX_ACE *pxace;
-       int userperms;
-       int groupperms;
-       int mask;
-       BOOL somegroup;
-       BOOL needgroups;
-       mode_t perms;
-       int i;
-
-       perms = pxdesc->mode;
-                                       /* owner and root access */
-       if (!scx->uid || (uid == scx->uid)) {
-               if (!scx->uid) {
-                                       /* root access if owner or other execution */
-                       if (perms & 0101)
-                               perms = 07777;
-                       else {
-                                       /* root access if some group execution */
-                               groupperms = 0;
-                               mask = 7;
-                               for (i=pxdesc->acccnt-1; i>=0 ; i--) {
-                                       pxace = &pxdesc->acl.ace[i];
-                                       switch (pxace->tag) {
-                                       case POSIX_ACL_USER_OBJ :
-                                       case POSIX_ACL_GROUP_OBJ :
-                                       case POSIX_ACL_GROUP :
-                                               groupperms |= pxace->perms;
-                                               break;
-                                       case POSIX_ACL_MASK :
-                                               mask = pxace->perms & 7;
-                                               break;
-                                       default :
-                                               break;
-                                       }
-                               }
-                               perms = (groupperms & mask & 1) | 6;
-                       }
-               } else
-                       perms &= 07700;
-       } else {
-                               /*
-                                * analyze designated users, get mask
-                                * and identify whether we need to check
-                                * the group memberships. The groups are
-                                * not needed when all groups have the
-                                * same permissions as other for the
-                                * requested modes.
-                                */
-               userperms = -1;
-               groupperms = -1;
-               needgroups = FALSE;
-               mask = 7;
-               for (i=pxdesc->acccnt-1; i>=0 ; i--) {
-                       pxace = &pxdesc->acl.ace[i];
-                       switch (pxace->tag) {
-                       case POSIX_ACL_USER :
-                               if ((uid_t)pxace->id == scx->uid)
-                                       userperms = pxace->perms;
-                               break;
-                       case POSIX_ACL_MASK :
-                               mask = pxace->perms & 7;
-                               break;
-                       case POSIX_ACL_GROUP_OBJ :
-                       case POSIX_ACL_GROUP :
-                               if (((pxace->perms & mask) ^ perms)
-                                   & (request >> 6) & 7)
-                                       needgroups = TRUE;
-                               break;
-                       default :
-                               break;
-                       }
-               }
-                                       /* designated users */
-               if (userperms >= 0)
-                       perms = (perms & 07000) + (userperms & mask);
-               else if (!needgroups)
-                               perms &= 07007;
-               else {
-                                       /* owning group */
-                       if (!(~(perms >> 3) & request & mask)
-                           && ((gid == scx->gid)
-                               || groupmember(scx, scx->uid, gid)))
-                               perms &= 07070;
-                       else {
-                                       /* other groups */
-                               groupperms = -1;
-                               somegroup = FALSE;
-                               for (i=pxdesc->acccnt-1; i>=0 ; i--) {
-                                       pxace = &pxdesc->acl.ace[i];
-                                       if ((pxace->tag == POSIX_ACL_GROUP)
-                                           && groupmember(scx, uid, pxace->id)) {
-                                               if (!(~pxace->perms & request & mask))
-                                                       groupperms = pxace->perms;
-                                               somegroup = TRUE;
-                                       }
-                               }
-                               if (groupperms >= 0)
-                                       perms = (perms & 07000) + (groupperms & mask);
-                               else
-                                       if (somegroup)
-                                               perms = 0;
-                                       else
-                                               perms &= 07007;
-                       }
-               }
-       }
-       return (perms);
-}
-
-/*
- *             Get permissions to access a file
- *     Takes into account the relation of user to file (owner, group, ...)
- *     Do no use as mode of the file
- *     Do no call if default_permissions is set
- *
- *     returns -1 if there is a problem
- */
-
-static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
-                ntfs_inode * ni, mode_t request)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       const struct CACHED_PERMISSIONS *cached;
-       char *securattr;
-       const SID *usid;        /* owner of file/directory */
-       const SID *gsid;        /* group of file/directory */
-       uid_t uid;
-       gid_t gid;
-       int perm;
-       BOOL isdir;
-       struct POSIX_SECURITY *pxdesc;
-
-       if (!scx->mapping[MAPUSERS])
-               perm = 07777;
-       else {
-               /* check whether available in cache */
-               cached = fetch_cache(scx,ni);
-               if (cached) {
-                       uid = cached->uid;
-                       gid = cached->gid;
-                       perm = access_check_posix(scx,cached->pxdesc,request,uid,gid);
-               } else {
-                       perm = 0;       /* default to no permission */
-                       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                               != const_cpu_to_le16(0);
-                       securattr = getsecurityattr(scx->vol, ni);
-                       if (securattr) {
-                               phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
-                                       securattr;
-                               gsid = (const SID*)&
-                                          securattr[le32_to_cpu(phead->group)];
-                               gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-#if OWNERFROMACL
-                               usid = ntfs_acl_owner(securattr);
-                               pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
-                                                usid, gsid, isdir);
-                               if (pxdesc)
-                                       perm = pxdesc->mode & 07777;
-                               else
-                                       perm = -1;
-                               uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#else
-                               usid = (const SID*)&
-                                           securattr[le32_to_cpu(phead->owner)];
-                               pxdesc = ntfs_build_permissions_posix(scx,securattr,
-                                                usid, gsid, isdir);
-                               if (pxdesc)
-                                       perm = pxdesc->mode & 07777;
-                               else
-                                       perm = -1;
-                               if (!perm && ntfs_same_sid(usid, adminsid)) {
-                                       uid = find_tenant(scx, securattr);
-                                       if (uid)
-                                               perm = 0700;
-                               } else
-                                       uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#endif
-                               /*
-                                *  Create a security id if there were none
-                                * and upgrade option is selected
-                                */
-                               if (!test_nino_flag(ni, v3_Extensions)
-                                  && (perm >= 0)
-                                  && (scx->vol->secure_flags
-                                    & (1 << SECURITY_ADDSECURIDS))) {
-                                       upgrade_secur_desc(scx->vol,
-                                               securattr, ni);
-                                       /*
-                                        * fetch owner and group for cacheing
-                                        * if there is a securid
-                                        */
-                               }
-                               if (test_nino_flag(ni, v3_Extensions)
-                                   && (perm >= 0)) {
-                                       enter_cache(scx, ni, uid,
-                                                       gid, pxdesc);
-                               }
-                               if (pxdesc) {
-                                       perm = access_check_posix(scx,pxdesc,request,uid,gid);
-                                       free(pxdesc);
-                               }
-                               free(securattr);
-                       } else {
-                               perm = -1;
-                               uid = gid = 0;
-                       }
-               }
-       }
-       return (perm);
-}
-
-/*
- *             Get a Posix ACL
- *
- *     returns size or -errno if there is a problem
- *     if size was too small, no copy is done and errno is not set,
- *     the caller is expected to issue a new call
- */
-
-int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-                       const char *name, char *value, size_t size) 
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       struct POSIX_SECURITY *pxdesc;
-       const struct CACHED_PERMISSIONS *cached;
-       char *securattr;
-       const SID *usid;        /* owner of file/directory */
-       const SID *gsid;        /* group of file/directory */
-       uid_t uid;
-       gid_t gid;
-       BOOL isdir;
-       size_t outsize;
-
-       outsize = 0;    /* default to error */
-       if (!scx->mapping[MAPUSERS])
-               errno = ENOTSUP;
-       else {
-                       /* check whether available in cache */
-               cached = fetch_cache(scx,ni);
-               if (cached)
-                       pxdesc = cached->pxdesc;
-               else {
-                       securattr = getsecurityattr(scx->vol, ni);
-                       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                               != const_cpu_to_le16(0);
-                       if (securattr) {
-                               phead =
-                                   (const SECURITY_DESCRIPTOR_RELATIVE*)
-                                               securattr;
-                               gsid = (const SID*)&
-                                         securattr[le32_to_cpu(phead->group)];
-#if OWNERFROMACL
-                               usid = ntfs_acl_owner(securattr);
-#else
-                               usid = (const SID*)&
-                                         securattr[le32_to_cpu(phead->owner)];
-#endif
-                               pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
-                                         usid, gsid, isdir);
-
-                                       /*
-                                        * fetch owner and group for cacheing
-                                        */
-                               if (pxdesc) {
-                               /*
-                                *  Create a security id if there were none
-                                * and upgrade option is selected
-                                */
-                                       if (!test_nino_flag(ni, v3_Extensions)
-                                          && (scx->vol->secure_flags
-                                            & (1 << SECURITY_ADDSECURIDS))) {
-                                               upgrade_secur_desc(scx->vol,
-                                                        securattr, ni);
-                                       }
-#if OWNERFROMACL
-                                       uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#else
-                                       if (!(pxdesc->mode & 07777)
-                                           && ntfs_same_sid(usid, adminsid)) {
-                                               uid = find_tenant(scx,
-                                                               securattr);
-                                       } else
-                                               uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#endif
-                                       gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-                                       if (pxdesc->tagsset & POSIX_ACL_EXTENSIONS)
-                                       enter_cache(scx, ni, uid,
-                                                       gid, pxdesc);
-                               }
-                               free(securattr);
-                       } else
-                               pxdesc = (struct POSIX_SECURITY*)NULL;
-               }
-
-               if (pxdesc) {
-                       if (ntfs_valid_posix(pxdesc)) {
-                               if (!strcmp(name,"system.posix_acl_default")) {
-                                       if (ni->mrec->flags
-                                                   & MFT_RECORD_IS_DIRECTORY)
-                                               outsize = sizeof(struct POSIX_ACL)
-                                                       + pxdesc->defcnt*sizeof(struct POSIX_ACE);
-                                       else {
-                                       /*
-                                        * getting default ACL from plain file :
-                                        * return EACCES if size > 0 as
-                                        * indicated in the man, but return ok
-                                        * if size == 0, so that ls does not
-                                        * display an error
-                                        */
-                                               if (size > 0) {
-                                                       outsize = 0;
-                                                       errno = EACCES;
-                                               } else
-                                                       outsize = sizeof(struct POSIX_ACL);
-                                       }
-                                       if (outsize && (outsize <= size)) {
-                                               memcpy(value,&pxdesc->acl,sizeof(struct POSIX_ACL));
-                                               memcpy(&value[sizeof(struct POSIX_ACL)],
-                                                       &pxdesc->acl.ace[pxdesc->firstdef],
-                                                       outsize-sizeof(struct POSIX_ACL));
-                                       }
-                               } else {
-                                       outsize = sizeof(struct POSIX_ACL)
-                                               + pxdesc->acccnt*sizeof(struct POSIX_ACE);
-                                       if (outsize <= size)
-                                               memcpy(value,&pxdesc->acl,outsize);
-                               }
-                       } else {
-                               outsize = 0;
-                               errno = EIO;
-                               ntfs_log_error("Invalid Posix ACL built\n");
-                       }
-                       if (!cached)
-                               free(pxdesc);
-               } else
-                       outsize = 0;
-       }
-       return (outsize ? (int)outsize : -errno);
-}
-
-#else /* POSIXACLS */
-
-
-/*
- *             Get permissions to access a file
- *     Takes into account the relation of user to file (owner, group, ...)
- *     Do no use as mode of the file
- *
- *     returns -1 if there is a problem
- */
-
-static int ntfs_get_perm(struct SECURITY_CONTEXT *scx,
-               ntfs_inode *ni, mode_t request)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       const struct CACHED_PERMISSIONS *cached;
-       char *securattr;
-       const SID *usid;        /* owner of file/directory */
-       const SID *gsid;        /* group of file/directory */
-       BOOL isdir;
-       uid_t uid;
-       gid_t gid;
-       int perm;
-
-       if (!scx->mapping[MAPUSERS] || (!scx->uid && !(request & S_IEXEC)))
-               perm = 07777;
-       else {
-               /* check whether available in cache */
-               cached = fetch_cache(scx,ni);
-               if (cached) {
-                       perm = cached->mode;
-                       uid = cached->uid;
-                       gid = cached->gid;
-               } else {
-                       perm = 0;       /* default to no permission */
-                       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                               != const_cpu_to_le16(0);
-                       securattr = getsecurityattr(scx->vol, ni);
-                       if (securattr) {
-                               phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
-                                       securattr;
-                               gsid = (const SID*)&
-                                          securattr[le32_to_cpu(phead->group)];
-                               gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-#if OWNERFROMACL
-                               usid = ntfs_acl_owner(securattr);
-                               perm = ntfs_build_permissions(securattr,
-                                                usid, gsid, isdir);
-                               uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#else
-                               usid = (const SID*)&
-                                           securattr[le32_to_cpu(phead->owner)];
-                               perm = ntfs_build_permissions(securattr,
-                                                usid, gsid, isdir);
-                               if (!perm && ntfs_same_sid(usid, adminsid)) {
-                                       uid = find_tenant(scx, securattr);
-                                       if (uid)
-                                               perm = 0700;
-                               } else
-                                       uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#endif
-                               /*
-                                *  Create a security id if there were none
-                                * and upgrade option is selected
-                                */
-                               if (!test_nino_flag(ni, v3_Extensions)
-                                  && (perm >= 0)
-                                  && (scx->vol->secure_flags
-                                    & (1 << SECURITY_ADDSECURIDS))) {
-                                       upgrade_secur_desc(scx->vol,
-                                               securattr, ni);
-                                       /*
-                                        * fetch owner and group for cacheing
-                                        * if there is a securid
-                                        */
-                               }
-                               if (test_nino_flag(ni, v3_Extensions)
-                                   && (perm >= 0)) {
-                                       enter_cache(scx, ni, uid,
-                                                       gid, perm);
-                               }
-                               free(securattr);
-                       } else {
-                               perm = -1;
-                               uid = gid = 0;
-                       }
-               }
-               if (perm >= 0) {
-                       if (!scx->uid) {
-                               /* root access and execution */
-                               if (perm & 0111)
-                                       perm = 07777;
-                               else
-                                       perm = 0;
-                       } else
-                               if (uid == scx->uid)
-                                       perm &= 07700;
-                               else
-                               /*
-                                * avoid checking group membership
-                                * when the requested perms for group
-                                * are the same as perms for other
-                                */
-                                       if ((gid == scx->gid)
-                                         || ((((perm >> 3) ^ perm)
-                                               & (request >> 6) & 7)
-                                           && groupmember(scx, scx->uid, gid)))
-                                               perm &= 07070;
-                                       else
-                                               perm &= 07007;
-               }
-       }
-       return (perm);
-}
-
-#endif /* POSIXACLS */
-
-/*
- *             Get an NTFS ACL
- *
- *     Returns size or -errno if there is a problem
- *     if size was too small, no copy is done and errno is not set,
- *     the caller is expected to issue a new call
- */
-
-int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-                       char *value, size_t size)
-{
-       char *securattr;
-       size_t outsize;
-
-       outsize = 0;    /* default to no data and no error */
-       securattr = getsecurityattr(scx->vol, ni);
-       if (securattr) {
-               outsize = ntfs_attr_size(securattr);
-               if (outsize <= size) {
-                       memcpy(value,securattr,outsize);
-               }
-               free(securattr);
-       }
-       return (outsize ? (int)outsize : -errno);
-}
-
-/*
- *             Get owner, group and permissions in an stat structure
- *     returns permissions, or -1 if there is a problem
- */
-
-int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
-               ntfs_inode * ni, struct stat *stbuf)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       char *securattr;
-       const SID *usid;        /* owner of file/directory */
-       const SID *gsid;        /* group of file/directory */
-       const struct CACHED_PERMISSIONS *cached;
-       int perm;
-       BOOL isdir;
-#if POSIXACLS
-       struct POSIX_SECURITY *pxdesc;
-#endif
-
-       if (!scx->mapping[MAPUSERS])
-               perm = 07777;
-       else {
-                       /* check whether available in cache */
-               cached = fetch_cache(scx,ni);
-               if (cached) {
-                       perm = cached->mode;
-                       stbuf->st_uid = cached->uid;
-                       stbuf->st_gid = cached->gid;
-                       stbuf->st_mode = (stbuf->st_mode & ~07777) + perm;
-               } else {
-                       perm = -1;      /* default to error */
-                       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                               != const_cpu_to_le16(0);
-                       securattr = getsecurityattr(scx->vol, ni);
-                       if (securattr) {
-                               phead =
-                                   (const SECURITY_DESCRIPTOR_RELATIVE*)
-                                               securattr;
-                               gsid = (const SID*)&
-                                         securattr[le32_to_cpu(phead->group)];
-#if OWNERFROMACL
-                               usid = ntfs_acl_owner(securattr);
-#else
-                               usid = (const SID*)&
-                                         securattr[le32_to_cpu(phead->owner)];
-#endif
-#if POSIXACLS
-                               pxdesc = ntfs_build_permissions_posix(scx->mapping, securattr,
-                                         usid, gsid, isdir);
-                               if (pxdesc)
-                                       perm = pxdesc->mode & 07777;
-                               else
-                                       perm = -1;
-#else
-                               perm = ntfs_build_permissions(securattr,
-                                         usid, gsid, isdir);
-#endif
-                                       /*
-                                        * fetch owner and group for cacheing
-                                        */
-                               if (perm >= 0) {
-                               /*
-                                *  Create a security id if there were none
-                                * and upgrade option is selected
-                                */
-                                       if (!test_nino_flag(ni, v3_Extensions)
-                                          && (scx->vol->secure_flags
-                                            & (1 << SECURITY_ADDSECURIDS))) {
-                                               upgrade_secur_desc(scx->vol,
-                                                        securattr, ni);
-                                       }
-#if OWNERFROMACL
-                                       stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#else
-                                       if (!perm && ntfs_same_sid(usid, adminsid)) {
-                                               stbuf->st_uid = 
-                                                       find_tenant(scx,
-                                                               securattr);
-                                               if (stbuf->st_uid)
-                                                       perm = 0700;
-                                       } else
-                                               stbuf->st_uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#endif
-                                       stbuf->st_gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-                                       stbuf->st_mode =
-                                           (stbuf->st_mode & ~07777) + perm;
-#if POSIXACLS
-                                       enter_cache(scx, ni, stbuf->st_uid,
-                                               stbuf->st_gid, pxdesc);
-                                       free(pxdesc);
-#else
-                                       enter_cache(scx, ni, stbuf->st_uid,
-                                               stbuf->st_gid, perm);
-#endif
-                               }
-                               free(securattr);
-                       }
-               }
-       }
-       return (perm);
-}
-
-#if POSIXACLS
-
-/*
- *             Get the base for a Posix inheritance and
- *     build an inherited Posix descriptor
- */
-
-static struct POSIX_SECURITY *inherit_posix(struct SECURITY_CONTEXT *scx,
-                       ntfs_inode *dir_ni, mode_t mode, BOOL isdir)
-{
-       const struct CACHED_PERMISSIONS *cached;
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       struct POSIX_SECURITY *pxdesc;
-       struct POSIX_SECURITY *pydesc;
-       char *securattr;
-       const SID *usid;
-       const SID *gsid;
-       uid_t uid;
-       gid_t gid;
-
-       pydesc = (struct POSIX_SECURITY*)NULL;
-               /* check whether parent directory is available in cache */
-       cached = fetch_cache(scx,dir_ni);
-       if (cached) {
-               uid = cached->uid;
-               gid = cached->gid;
-               pxdesc = cached->pxdesc;
-               if (pxdesc) {
-                       pydesc = ntfs_build_inherited_posix(pxdesc,mode,
-                                       scx->umask,isdir);
-               }
-       } else {
-               securattr = getsecurityattr(scx->vol, dir_ni);
-               if (securattr) {
-                       phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
-                               securattr;
-                       gsid = (const SID*)&
-                                  securattr[le32_to_cpu(phead->group)];
-                       gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-#if OWNERFROMACL
-                       usid = ntfs_acl_owner(securattr);
-                       pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
-                                                usid, gsid, TRUE);
-                       uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#else
-                       usid = (const SID*)&
-                                   securattr[le32_to_cpu(phead->owner)];
-                       pxdesc = ntfs_build_permissions_posix(scx->mapping,securattr,
-                                                usid, gsid, TRUE);
-                       if (pxdesc && ntfs_same_sid(usid, adminsid)) {
-                               uid = find_tenant(scx, securattr);
-                       } else
-                               uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-#endif
-                       if (pxdesc) {
-                               /*
-                                *  Create a security id if there were none
-                                * and upgrade option is selected
-                                */
-                               if (!test_nino_flag(dir_ni, v3_Extensions)
-                                  && (scx->vol->secure_flags
-                                    & (1 << SECURITY_ADDSECURIDS))) {
-                                       upgrade_secur_desc(scx->vol,
-                                               securattr, dir_ni);
-                                       /*
-                                        * fetch owner and group for cacheing
-                                        * if there is a securid
-                                        */
-                               }
-                               if (test_nino_flag(dir_ni, v3_Extensions)) {
-                                       enter_cache(scx, dir_ni, uid,
-                                                       gid, pxdesc);
-                               }
-                               pydesc = ntfs_build_inherited_posix(pxdesc,
-                                       mode, scx->umask, isdir);
-                               free(pxdesc);
-                       }
-                       free(securattr);
-               }
-       }
-       return (pydesc);
-}
-
-/*
- *             Allocate a security_id for a file being created
- *     
- *     Returns zero if not possible (NTFS v3.x required)
- */
-
-le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
-               uid_t uid, gid_t gid, ntfs_inode *dir_ni,
-               mode_t mode, BOOL isdir)
-{
-#if !FORCE_FORMAT_v1x
-       const struct CACHED_SECURID *cached;
-       struct CACHED_SECURID wanted;
-       struct POSIX_SECURITY *pxdesc;
-       char *newattr;
-       int newattrsz;
-       const SID *usid;
-       const SID *gsid;
-       BIGSID defusid;
-       BIGSID defgsid;
-       le32 securid;
-#endif
-
-       securid = const_cpu_to_le32(0);
-
-#if !FORCE_FORMAT_v1x
-
-       pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
-       if (pxdesc) {
-               /* check whether target securid is known in cache */
-
-               wanted.uid = uid;
-               wanted.gid = gid;
-               wanted.dmode = pxdesc->mode & mode & 07777;
-               if (isdir) wanted.dmode |= 0x10000;
-               wanted.variable = (void*)pxdesc;
-               wanted.varsize = sizeof(struct POSIX_SECURITY)
-                               + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
-               cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
-                               scx->vol->securid_cache, GENERIC(&wanted),
-                               (cache_compare)compare);
-                       /* quite simple, if we are lucky */
-               if (cached)
-                       securid = cached->securid;
-
-                       /* not in cache : make sure we can create ids */
-
-               if (!cached && (scx->vol->major_ver >= 3)) {
-                       usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
-                       gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
-                       if (!usid || !gsid) {
-                               ntfs_log_error("File created by an unmapped user/group %d/%d\n",
-                                               (int)uid, (int)gid);
-                               usid = gsid = adminsid;
-                       }
-                       newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
-                                       isdir, usid, gsid);
-                       if (newattr) {
-                               newattrsz = ntfs_attr_size(newattr);
-                               securid = setsecurityattr(scx->vol,
-                                       (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
-                                       newattrsz);
-                               if (securid) {
-                                       /* update cache, for subsequent use */
-                                       wanted.securid = securid;
-                                       ntfs_enter_cache(scx->vol->securid_cache,
-                                                       GENERIC(&wanted),
-                                                       (cache_compare)compare);
-                               }
-                               free(newattr);
-                       } else {
-                               /*
-                                * could not build new security attribute
-                                * errno set by ntfs_build_descr()
-                                */
-                       }
-               }
-       free(pxdesc);
-       }
-#endif
-       return (securid);
-}
-
-/*
- *             Apply Posix inheritance to a newly created file
- *     (for NTFS 1.x only : no securid)
- */
-
-int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
-               ntfs_inode *ni, uid_t uid, gid_t gid,
-               ntfs_inode *dir_ni, mode_t mode)
-{
-       struct POSIX_SECURITY *pxdesc;
-       char *newattr;
-       const SID *usid;
-       const SID *gsid;
-       BIGSID defusid;
-       BIGSID defgsid;
-       BOOL isdir;
-       int res;
-
-       res = -1;
-       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
-       pxdesc = inherit_posix(scx, dir_ni, mode, isdir);
-       if (pxdesc) {
-               usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
-               gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
-               if (!usid || !gsid) {
-                       ntfs_log_error("File created by an unmapped user/group %d/%d\n",
-                                       (int)uid, (int)gid);
-                       usid = gsid = adminsid;
-               }
-               newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
-                                       isdir, usid, gsid);
-               if (newattr) {
-                               /* Adjust Windows read-only flag */
-                       res = update_secur_descr(scx->vol, newattr, ni);
-                       if (!res && !isdir) {
-                               if (mode & S_IWUSR)
-                                       ni->flags &= ~FILE_ATTR_READONLY;
-                               else
-                                       ni->flags |= FILE_ATTR_READONLY;
-                       }
-#if CACHE_LEGACY_SIZE
-                       /* also invalidate legacy cache */
-                       if (isdir && !ni->security_id) {
-                               struct CACHED_PERMISSIONS_LEGACY legacy;
-
-                               legacy.mft_no = ni->mft_no;
-                               legacy.variable = pxdesc;
-                               legacy.varsize = sizeof(struct POSIX_SECURITY)
-                                       + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
-                               ntfs_invalidate_cache(scx->vol->legacy_cache,
-                                               GENERIC(&legacy),
-                                               (cache_compare)leg_compare,0);
-                       }
-#endif
-                       free(newattr);
-
-               } else {
-                       /*
-                        * could not build new security attribute
-                        * errno set by ntfs_build_descr()
-                        */
-               }
-       }
-       return (res);
-}
-
-#else
-
-le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
-               uid_t uid, gid_t gid, mode_t mode, BOOL isdir)
-{
-#if !FORCE_FORMAT_v1x
-       const struct CACHED_SECURID *cached;
-       struct CACHED_SECURID wanted;
-       char *newattr;
-       int newattrsz;
-       const SID *usid;
-       const SID *gsid;
-       BIGSID defusid;
-       BIGSID defgsid;
-       le32 securid;
-#endif
-
-       securid = const_cpu_to_le32(0);
-
-#if !FORCE_FORMAT_v1x
-               /* check whether target securid is known in cache */
-
-       wanted.uid = uid;
-       wanted.gid = gid;
-       wanted.dmode = mode & 07777;
-       if (isdir) wanted.dmode |= 0x10000;
-       wanted.variable = (void*)NULL;
-       wanted.varsize = 0;
-       cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
-                       scx->vol->securid_cache, GENERIC(&wanted),
-                       (cache_compare)compare);
-               /* quite simple, if we are lucky */
-       if (cached)
-               securid = cached->securid;
-
-               /* not in cache : make sure we can create ids */
-
-       if (!cached && (scx->vol->major_ver >= 3)) {
-               usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
-               gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
-               if (!usid || !gsid) {
-                       ntfs_log_error("File created by an unmapped user/group %d/%d\n",
-                                       (int)uid, (int)gid);
-                       usid = gsid = adminsid;
-               }
-               newattr = ntfs_build_descr(mode, isdir, usid, gsid);
-               if (newattr) {
-                       newattrsz = ntfs_attr_size(newattr);
-                       securid = setsecurityattr(scx->vol,
-                               (const SECURITY_DESCRIPTOR_RELATIVE*)newattr,
-                               newattrsz);
-                       if (securid) {
-                               /* update cache, for subsequent use */
-                               wanted.securid = securid;
-                               ntfs_enter_cache(scx->vol->securid_cache,
-                                               GENERIC(&wanted),
-                                               (cache_compare)compare);
-                       }
-                       free(newattr);
-               } else {
-                       /*
-                        * could not build new security attribute
-                        * errno set by ntfs_build_descr()
-                        */
-               }
-       }
-#endif
-       return (securid);
-}
-
-#endif
-
-/*
- *             Update ownership and mode of a file, reusing an existing
- *     security descriptor when possible
- *     
- *     Returns zero if successful
- */
-
-#if POSIXACLS
-int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-               uid_t uid, gid_t gid, mode_t mode,
-               struct POSIX_SECURITY *pxdesc)
-#else
-int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-               uid_t uid, gid_t gid, mode_t mode)
-#endif
-{
-       int res;
-       const struct CACHED_SECURID *cached;
-       struct CACHED_SECURID wanted;
-       char *newattr;
-       const SID *usid;
-       const SID *gsid;
-       BIGSID defusid;
-       BIGSID defgsid;
-       BOOL isdir;
-
-       res = 0;
-
-               /* check whether target securid is known in cache */
-
-       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
-       wanted.uid = uid;
-       wanted.gid = gid;
-       wanted.dmode = mode & 07777;
-       if (isdir) wanted.dmode |= 0x10000;
-#if POSIXACLS
-       wanted.variable = (void*)pxdesc;
-       if (pxdesc)
-               wanted.varsize = sizeof(struct POSIX_SECURITY)
-                       + (pxdesc->acccnt + pxdesc->defcnt)*sizeof(struct POSIX_ACE);
-       else
-               wanted.varsize = 0;
-#else
-       wanted.variable = (void*)NULL;
-       wanted.varsize = 0;
-#endif
-       if (test_nino_flag(ni, v3_Extensions)) {
-               cached = (const struct CACHED_SECURID*)ntfs_fetch_cache(
-                               scx->vol->securid_cache, GENERIC(&wanted),
-                               (cache_compare)compare);
-                       /* quite simple, if we are lucky */
-               if (cached) {
-                       ni->security_id = cached->securid;
-                       NInoSetDirty(ni);
-               }
-       } else cached = (struct CACHED_SECURID*)NULL;
-
-       if (!cached) {
-                       /*
-                        * Do not use usid and gsid from former attributes,
-                        * but recompute them to get repeatable results
-                        * which can be kept in cache.
-                        */
-               usid = ntfs_find_usid(scx->mapping[MAPUSERS],uid,(SID*)&defusid);
-               gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS],gid,(SID*)&defgsid);
-               if (!usid || !gsid) {
-                       ntfs_log_error("File made owned by an unmapped user/group %d/%d\n",
-                               uid, gid);
-                       usid = gsid = adminsid;
-               }
-#if POSIXACLS
-               if (pxdesc)
-                       newattr = ntfs_build_descr_posix(scx->mapping, pxdesc,
-                                        isdir, usid, gsid);
-               else
-                       newattr = ntfs_build_descr(mode,
-                                        isdir, usid, gsid);
-#else
-               newattr = ntfs_build_descr(mode,
-                                        isdir, usid, gsid);
-#endif
-               if (newattr) {
-                       res = update_secur_descr(scx->vol, newattr, ni);
-                       if (!res) {
-                               /* adjust Windows read-only flag */
-                               if (!isdir) {
-                                       if (mode & S_IWUSR)
-                                               ni->flags &= ~FILE_ATTR_READONLY;
-                                       else
-                                               ni->flags |= FILE_ATTR_READONLY;
-                                       NInoFileNameSetDirty(ni);
-                               }
-                               /* update cache, for subsequent use */
-                               if (test_nino_flag(ni, v3_Extensions)) {
-                                       wanted.securid = ni->security_id;
-                                       ntfs_enter_cache(scx->vol->securid_cache,
-                                                       GENERIC(&wanted),
-                                                       (cache_compare)compare);
-                               }
-#if CACHE_LEGACY_SIZE
-                               /* also invalidate legacy cache */
-                               if (isdir && !ni->security_id) {
-                                       struct CACHED_PERMISSIONS_LEGACY legacy;
-
-                                       legacy.mft_no = ni->mft_no;
-#if POSIXACLS
-                                       legacy.variable = wanted.variable;
-                                       legacy.varsize = wanted.varsize;
-#else
-                                       legacy.variable = (void*)NULL;
-                                       legacy.varsize = 0;
-#endif
-                                       ntfs_invalidate_cache(scx->vol->legacy_cache,
-                                               GENERIC(&legacy),
-                                               (cache_compare)leg_compare,0);
-                               }
-#endif
-                       }
-                       free(newattr);
-               } else {
-                       /*
-                        * could not build new security attribute
-                        * errno set by ntfs_build_descr()
-                        */
-                       res = -1;
-               }
-       }
-       return (res);
-}
-
-/*
- *             Check whether user has ownership rights on a file
- *
- *     Returns TRUE if allowed
- *             if not, errno tells why
- */
-
-BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
-{
-       const struct CACHED_PERMISSIONS *cached;
-       char *oldattr;
-       const SID *usid;
-       uid_t processuid;
-       uid_t uid;
-       BOOL gotowner;
-       int allowed;
-
-       processuid = scx->uid;
-/* TODO : use CAP_FOWNER process capability */
-       /*
-        * Always allow for root
-        * Also always allow if no mapping has been defined
-        */
-       if (!scx->mapping[MAPUSERS] || !processuid)
-               allowed = TRUE;
-       else {
-               gotowner = FALSE; /* default */
-               /* get the owner, either from cache or from old attribute  */
-               cached = fetch_cache(scx, ni);
-               if (cached) {
-                       uid = cached->uid;
-                       gotowner = TRUE;
-               } else {
-                       oldattr = getsecurityattr(scx->vol, ni);
-                       if (oldattr) {
-#if OWNERFROMACL
-                               usid = ntfs_acl_owner(oldattr);
-#else
-                               const SECURITY_DESCRIPTOR_RELATIVE *phead;
-
-                               phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
-                                                               oldattr;
-                               usid = (const SID*)&oldattr
-                                               [le32_to_cpu(phead->owner)];
-#endif
-                               uid = ntfs_find_user(scx->mapping[MAPUSERS],
-                                               usid);
-                               gotowner = TRUE;
-                               free(oldattr);
-                       }
-               }
-               allowed = FALSE;
-               if (gotowner) {
-/* TODO : use CAP_FOWNER process capability */
-                       if (!processuid || (processuid == uid))
-                               allowed = TRUE;
-                       else
-                               errno = EPERM;
-               }
-       }
-       return (allowed);
-}
-
-#ifdef HAVE_SETXATTR    /* extended attributes interface required */
-
-#if POSIXACLS
-
-/*
- *             Set a new access or default Posix ACL to a file
- *             (or remove ACL if no input data)
- *     Validity of input data is checked after merging
- *
- *     Returns 0, or -1 if there is a problem which errno describes
- */
-
-int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-                       const char *name, const char *value, size_t size,
-                       int flags)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       const struct CACHED_PERMISSIONS *cached;
-       char *oldattr;
-       uid_t processuid;
-       const SID *usid;
-       const SID *gsid;
-       uid_t uid;
-       uid_t gid;
-       int res;
-       BOOL isdir;
-       BOOL deflt;
-       BOOL exist;
-       int count;
-       struct POSIX_SECURITY *oldpxdesc;
-       struct POSIX_SECURITY *newpxdesc;
-
-       /* get the current pxsec, either from cache or from old attribute  */
-       res = -1;
-       deflt = !strcmp(name,"system.posix_acl_default");
-       if (size)
-               count = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
-       else
-               count = 0;
-       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
-       newpxdesc = (struct POSIX_SECURITY*)NULL;
-       if ((!value
-               || (((const struct POSIX_ACL*)value)->version == POSIX_VERSION))
-           && (!deflt || isdir || (!size && !value))) {
-               cached = fetch_cache(scx, ni);
-               if (cached) {
-                       uid = cached->uid;
-                       gid = cached->gid;
-                       oldpxdesc = cached->pxdesc;
-                       if (oldpxdesc) {
-                               newpxdesc = ntfs_replace_acl(oldpxdesc,
-                                               (const struct POSIX_ACL*)value,count,deflt);
-                               }
-               } else {
-                       oldattr = getsecurityattr(scx->vol, ni);
-                       if (oldattr) {
-                               phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
-#if OWNERFROMACL
-                               usid = ntfs_acl_owner(oldattr);
-#else
-                               usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
-#endif
-                               gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
-                               uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-                               gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-                               oldpxdesc = ntfs_build_permissions_posix(scx->mapping,
-                                       oldattr, usid, gsid, isdir);
-                               if (oldpxdesc) {
-                                       if (deflt)
-                                               exist = oldpxdesc->defcnt > 0;
-                                       else
-                                               exist = oldpxdesc->acccnt > 3;
-                                       if ((exist && (flags & XATTR_CREATE))
-                                         || (!exist && (flags & XATTR_REPLACE))) {
-                                               errno = (exist ? EEXIST : ENODATA);
-                                       } else {
-                                               newpxdesc = ntfs_replace_acl(oldpxdesc,
-                                                       (const struct POSIX_ACL*)value,count,deflt);
-                                       }
-                                       free(oldpxdesc);
-                               }
-                               free(oldattr);
-                       }
-               }
-       } else
-               errno = EINVAL;
-
-       if (newpxdesc) {
-               processuid = scx->uid;
-/* TODO : use CAP_FOWNER process capability */
-               if (!processuid || (uid == processuid)) {
-                               /*
-                                * clear setgid if file group does
-                                * not match process group
-                                */
-                       if (processuid && (gid != scx->gid)
-                           && !groupmember(scx, scx->uid, gid)) {
-                               newpxdesc->mode &= ~S_ISGID;
-                       }
-                       res = ntfs_set_owner_mode(scx, ni, uid, gid,
-                               newpxdesc->mode, newpxdesc);
-               } else
-                       errno = EPERM;
-               free(newpxdesc);
-       }
-       return (res ? -1 : 0);
-}
-
-/*
- *             Remove a default Posix ACL from a file
- *
- *     Returns 0, or -1 if there is a problem which errno describes
- */
-
-int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-                       const char *name)
-{
-       return (ntfs_set_posix_acl(scx, ni, name,
-                       (const char*)NULL, 0, 0));
-}
-
-#endif
-
-/*
- *             Set a new NTFS ACL to a file
- *
- *     Returns 0, or -1 if there is a problem
- */
-
-int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-                       const char *value, size_t size, int flags)
-{
-       char *attr;
-       int res;
-
-       res = -1;
-       if ((size > 0)
-          && !(flags & XATTR_CREATE)
-          && ntfs_valid_descr(value,size)
-          && (ntfs_attr_size(value) == size)) {
-                       /* need copying in order to write */
-               attr = (char*)ntfs_malloc(size);
-               if (attr) {
-                       memcpy(attr,value,size);
-                       res = update_secur_descr(scx->vol, attr, ni);
-                       /*
-                        * No need to invalidate standard caches :
-                        * the relation between a securid and
-                        * the associated protection is unchanged,
-                        * only the relation between a file and
-                        * its securid and protection is changed.
-                        */
-#if CACHE_LEGACY_SIZE
-                       /*
-                        * we must however invalidate the legacy
-                        * cache, which is based on inode numbers.
-                        * For safety, invalidate even if updating
-                        * failed.
-                        */
-                       if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                          && !ni->security_id) {
-                               struct CACHED_PERMISSIONS_LEGACY legacy;
-
-                               legacy.mft_no = ni->mft_no;
-                               legacy.variable = (char*)NULL;
-                               legacy.varsize = 0;
-                               ntfs_invalidate_cache(scx->vol->legacy_cache,
-                                       GENERIC(&legacy),
-                                       (cache_compare)leg_compare,0);
-                       }
-#endif
-                       free(attr);
-               } else
-                       errno = ENOMEM;
-       } else
-               errno = EINVAL;
-       return (res ? -1 : 0);
-}
-
-#endif /* HAVE_SETXATTR */
-
-/*
- *             Set new permissions to a file
- *     Checks user mapping has been defined before request for setting
- *
- *     rejected if request is not originated by owner or root
- *
- *     returns 0 on success
- *             -1 on failure, with errno = EIO
- */
-
-int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       const struct CACHED_PERMISSIONS *cached;
-       char *oldattr;
-       const SID *usid;
-       const SID *gsid;
-       uid_t processuid;
-       uid_t uid;
-       uid_t gid;
-       int res;
-#if POSIXACLS
-       BOOL isdir;
-       int pxsize;
-       const struct POSIX_SECURITY *oldpxdesc;
-       struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
-#endif
-
-       /* get the current owner, either from cache or from old attribute  */
-       res = 0;
-       cached = fetch_cache(scx, ni);
-       if (cached) {
-               uid = cached->uid;
-               gid = cached->gid;
-#if POSIXACLS
-               oldpxdesc = cached->pxdesc;
-               if (oldpxdesc) {
-                               /* must copy before merging */
-                       pxsize = sizeof(struct POSIX_SECURITY)
-                               + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
-                       newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
-                       if (newpxdesc) {
-                               memcpy(newpxdesc, oldpxdesc, pxsize);
-                               if (ntfs_merge_mode_posix(newpxdesc, mode))
-                                       res = -1;
-                       } else
-                               res = -1;
-               } else
-                       newpxdesc = (struct POSIX_SECURITY*)NULL;
-#endif
-       } else {
-               oldattr = getsecurityattr(scx->vol, ni);
-               if (oldattr) {
-                       phead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
-#if OWNERFROMACL
-                       usid = ntfs_acl_owner(oldattr);
-#else
-                       usid = (const SID*)&oldattr[le32_to_cpu(phead->owner)];
-#endif
-                       gsid = (const SID*)&oldattr[le32_to_cpu(phead->group)];
-                       uid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-                       gid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-#if POSIXACLS
-                       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) != const_cpu_to_le16(0);
-                       newpxdesc = ntfs_build_permissions_posix(scx->mapping,
-                               oldattr, usid, gsid, isdir);
-                       if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
-                               res = -1;
-#endif
-                       free(oldattr);
-               } else
-                       res = -1;
-       }
-
-       if (!res) {
-               processuid = scx->uid;
-/* TODO : use CAP_FOWNER process capability */
-               if (!processuid || (uid == processuid)) {
-                               /*
-                                * clear setgid if file group does
-                                * not match process group
-                                */
-                       if (processuid && (gid != scx->gid)
-                           && !groupmember(scx, scx->uid, gid))
-                               mode &= ~S_ISGID;
-#if POSIXACLS
-                       if (newpxdesc) {
-                               newpxdesc->mode = mode;
-                               res = ntfs_set_owner_mode(scx, ni, uid, gid,
-                                       mode, newpxdesc);
-                       } else
-                               res = ntfs_set_owner_mode(scx, ni, uid, gid,
-                                       mode, newpxdesc);
-#else
-                       res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
-#endif
-               } else {
-                       errno = EPERM;
-                       res = -1;       /* neither owner nor root */
-               }
-       } else {
-               /*
-                * Should not happen : a default descriptor is generated
-                * by getsecurityattr() when there are none
-                */
-               ntfs_log_error("File has no security descriptor\n");
-               res = -1;
-               errno = EIO;
-       }
-#if POSIXACLS
-       if (newpxdesc) free(newpxdesc);
-#endif
-       return (res ? -1 : 0);
-}
-
-/*
- *     Create a default security descriptor for files whose descriptor
- *     cannot be inherited
- */
-
-int ntfs_sd_add_everyone(ntfs_inode *ni)
-{
-       /* JPA SECURITY_DESCRIPTOR_ATTR *sd; */
-       SECURITY_DESCRIPTOR_RELATIVE *sd;
-       ACL *acl;
-       ACCESS_ALLOWED_ACE *ace;
-       SID *sid;
-       int ret, sd_len;
-       
-       /* Create SECURITY_DESCRIPTOR attribute (everyone has full access). */
-       /*
-        * Calculate security descriptor length. We have 2 sub-authorities in
-        * owner and group SIDs, but structure SID contain only one, so add
-        * 4 bytes to every SID.
-        */
-       sd_len = sizeof(SECURITY_DESCRIPTOR_ATTR) + 2 * (sizeof(SID) + 4) +
-               sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE); 
-       sd = (SECURITY_DESCRIPTOR_RELATIVE*)ntfs_calloc(sd_len);
-       if (!sd)
-               return -1;
-       
-       sd->revision = SECURITY_DESCRIPTOR_REVISION;
-       sd->control = SE_DACL_PRESENT | SE_SELF_RELATIVE;
-       
-       sid = (SID*)((u8*)sd + sizeof(SECURITY_DESCRIPTOR_ATTR));
-       sid->revision = SID_REVISION;
-       sid->sub_authority_count = 2;
-       sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
-       sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
-       sid->identifier_authority.value[5] = 5;
-       sd->owner = cpu_to_le32((u8*)sid - (u8*)sd);
-       
-       sid = (SID*)((u8*)sid + sizeof(SID) + 4); 
-       sid->revision = SID_REVISION;
-       sid->sub_authority_count = 2;
-       sid->sub_authority[0] = const_cpu_to_le32(SECURITY_BUILTIN_DOMAIN_RID);
-       sid->sub_authority[1] = const_cpu_to_le32(DOMAIN_ALIAS_RID_ADMINS);
-       sid->identifier_authority.value[5] = 5;
-       sd->group = cpu_to_le32((u8*)sid - (u8*)sd);
-       
-       acl = (ACL*)((u8*)sid + sizeof(SID) + 4);
-       acl->revision = ACL_REVISION;
-       acl->size = const_cpu_to_le16(sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE));
-       acl->ace_count = const_cpu_to_le16(1);
-       sd->dacl = cpu_to_le32((u8*)acl - (u8*)sd);
-       
-       ace = (ACCESS_ALLOWED_ACE*)((u8*)acl + sizeof(ACL));
-       ace->type = ACCESS_ALLOWED_ACE_TYPE;
-       ace->flags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
-       ace->size = const_cpu_to_le16(sizeof(ACCESS_ALLOWED_ACE));
-       ace->mask = const_cpu_to_le32(0x1f01ff); /* FIXME */
-       ace->sid.revision = SID_REVISION;
-       ace->sid.sub_authority_count = 1;
-       ace->sid.sub_authority[0] = const_cpu_to_le32(0);
-       ace->sid.identifier_authority.value[5] = 1;
-
-       ret = ntfs_attr_add(ni, AT_SECURITY_DESCRIPTOR, AT_UNNAMED, 0, (u8*)sd,
-                           sd_len);
-       if (ret)
-               ntfs_log_perror("Failed to add initial SECURITY_DESCRIPTOR");
-       
-       free(sd);
-       return ret;
-}
-
-/*
- *             Check whether user can access a file in a specific way
- *
- *     Returns 1 if access is allowed, including user is root or no
- *               user mapping defined
- *             2 if sticky and accesstype is S_IWRITE + S_IEXEC + S_ISVTX
- *             0 and sets errno if there is a problem or if access
- *               is not allowed
- *
- *     This is used for Posix ACL and checking creation of DOS file names
- */
-
-int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
-               ntfs_inode *ni,
-               int accesstype) /* access type required (S_Ixxx values) */
-{
-       int perm;
-       int res;
-       int allow;
-       struct stat stbuf;
-
-       /*
-        * Always allow for root unless execution is requested.
-        * (was checked by fuse until kernel 2.6.29)
-        * Also always allow if no mapping has been defined
-        */
-       if (!scx->mapping[MAPUSERS]
-           || (!scx->uid
-               && (!(accesstype & S_IEXEC)
-                   || (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY))))
-               allow = 1;
-       else {
-               perm = ntfs_get_perm(scx, ni, accesstype);
-               if (perm >= 0) {
-                       res = EACCES;
-                       switch (accesstype) {
-                       case S_IEXEC:
-                               allow = (perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
-                               break;
-                       case S_IWRITE:
-                               allow = (perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0;
-                               break;
-                       case S_IWRITE + S_IEXEC:
-                               allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
-                                   && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
-                               break;
-                       case S_IREAD:
-                               allow = (perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0;
-                               break;
-                       case S_IREAD + S_IEXEC:
-                               allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
-                                   && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
-                               break;
-                       case S_IREAD + S_IWRITE:
-                               allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
-                                   && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0);
-                               break;
-                       case S_IWRITE + S_IEXEC + S_ISVTX:
-                               if (perm & S_ISVTX) {
-                                       if ((ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
-                                           && (stbuf.st_uid == scx->uid))
-                                               allow = 1;
-                                       else
-                                               allow = 2;
-                               } else
-                                       allow = ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
-                                           && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
-                               break;
-                       case S_IREAD + S_IWRITE + S_IEXEC:
-                               allow = ((perm & (S_IRUSR | S_IRGRP | S_IROTH)) != 0)
-                                   && ((perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
-                                   && ((perm & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
-                               break;
-                       default :
-                               res = EINVAL;
-                               allow = 0;
-                               break;
-                       }
-                       if (!allow)
-                               errno = res;
-               } else
-                       allow = 0;
-       }
-       return (allow);
-}
-
-#if 0 /* not needed any more */
-
-/*
- *             Check whether user can access the parent directory
- *     of a file in a specific way
- *
- *     Returns true if access is allowed, including user is root and
- *             no user mapping defined
- *     
- *     Sets errno if there is a problem or if not allowed
- *
- *     This is used for Posix ACL and checking creation of DOS file names
- */
-
-BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
-               const char *path, int accesstype)
-{
-       int allow;
-       char *dirpath;
-       char *name;
-       ntfs_inode *ni;
-       ntfs_inode *dir_ni;
-       struct stat stbuf;
-
-       allow = 0;
-       dirpath = strdup(path);
-       if (dirpath) {
-               /* the root of file system is seen as a parent of itself */
-               /* is that correct ? */
-               name = strrchr(dirpath, '/');
-               *name = 0;
-               dir_ni = ntfs_pathname_to_inode(scx->vol, NULL, dirpath);
-               if (dir_ni) {
-                       allow = ntfs_allowed_access(scx,
-                                dir_ni, accesstype);
-                       ntfs_inode_close(dir_ni);
-                               /*
-                                * for an not-owned sticky directory, have to
-                                * check whether file itself is owned
-                                */
-                       if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX))
-                          && (allow == 2)) {
-                               ni = ntfs_pathname_to_inode(scx->vol, NULL,
-                                        path);
-                               allow = FALSE;
-                               if (ni) {
-                                       allow = (ntfs_get_owner_mode(scx,ni,&stbuf) >= 0)
-                                               && (stbuf.st_uid == scx->uid);
-                               ntfs_inode_close(ni);
-                               }
-                       }
-               }
-               free(dirpath);
-       }
-       return (allow);         /* errno is set if not allowed */
-}
-
-#endif
-
-/*
- *             Define a new owner/group to a file
- *
- *     returns zero if successful
- */
-
-int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-                       uid_t uid, gid_t gid)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       const struct CACHED_PERMISSIONS *cached;
-       char *oldattr;
-       const SID *usid;
-       const SID *gsid;
-       uid_t fileuid;
-       uid_t filegid;
-       mode_t mode;
-       int perm;
-       BOOL isdir;
-       int res;
-#if POSIXACLS
-       struct POSIX_SECURITY *pxdesc;
-       BOOL pxdescbuilt = FALSE;
-#endif
-
-       res = 0;
-       /* get the current owner and mode from cache or security attributes */
-       oldattr = (char*)NULL;
-       cached = fetch_cache(scx,ni);
-       if (cached) {
-               fileuid = cached->uid;
-               filegid = cached->gid;
-               mode = cached->mode;
-#if POSIXACLS
-               pxdesc = cached->pxdesc;
-               if (!pxdesc)
-                       res = -1;
-#endif
-       } else {
-               fileuid = 0;
-               filegid = 0;
-               mode = 0;
-               oldattr = getsecurityattr(scx->vol, ni);
-               if (oldattr) {
-                       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                               != const_cpu_to_le16(0);
-                       phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
-                               oldattr;
-                       gsid = (const SID*)
-                               &oldattr[le32_to_cpu(phead->group)];
-#if OWNERFROMACL
-                       usid = ntfs_acl_owner(oldattr);
-#else
-                       usid = (const SID*)
-                               &oldattr[le32_to_cpu(phead->owner)];
-#endif
-#if POSIXACLS
-                       pxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
-                                       usid, gsid, isdir);
-                       if (pxdesc) {
-                               pxdescbuilt = TRUE;
-                               fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-                               filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-                               mode = perm = pxdesc->mode;
-                       } else
-                               res = -1;
-#else
-                       mode = perm = ntfs_build_permissions(oldattr,
-                                        usid, gsid, isdir);
-                       if (perm >= 0) {
-                               fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-                               filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-                       } else
-                               res = -1;
-#endif
-                       free(oldattr);
-               } else
-                       res = -1;
-       }
-       if (!res) {
-               /* check requested by root */
-               /* or chgrp requested by owner to an owned group */
-               if (!scx->uid
-                  || ((((int)uid < 0) || (uid == fileuid))
-                     && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
-                     && (fileuid == scx->uid))) {
-                       /* replace by the new usid and gsid */
-                       /* or reuse old gid and sid for cacheing */
-                       if ((int)uid < 0)
-                               uid = fileuid;
-                       if ((int)gid < 0)
-                               gid = filegid;
-                       /* clear setuid and setgid if owner has changed */
-                        /* unless request originated by root */
-                       if (uid && (fileuid != uid))
-                               mode &= 01777;
-#if POSIXACLS
-                       res = ntfs_set_owner_mode(scx, ni, uid, gid, 
-                               mode, pxdesc);
-#else
-                       res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
-#endif
-               } else {
-                       res = -1;       /* neither owner nor root */
-                       errno = EPERM;
-               }
-#if POSIXACLS
-               if (pxdescbuilt)
-                       free(pxdesc);
-#endif
-       } else {
-               /*
-                * Should not happen : a default descriptor is generated
-                * by getsecurityattr() when there are none
-                */
-               ntfs_log_error("File has no security descriptor\n");
-               res = -1;
-               errno = EIO;
-       }
-       return (res ? -1 : 0);
-}
-
-/*
- *             Define new owner/group and mode to a file
- *
- *     returns zero if successful
- */
-
-int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
-                       uid_t uid, gid_t gid, const mode_t mode)
-{
-       const struct CACHED_PERMISSIONS *cached;
-       char *oldattr;
-       uid_t fileuid;
-       uid_t filegid;
-       int res;
-#if POSIXACLS
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       const SID *usid;
-       const SID *gsid;
-       BOOL isdir;
-       const struct POSIX_SECURITY *oldpxdesc;
-       struct POSIX_SECURITY *newpxdesc = (struct POSIX_SECURITY*)NULL;
-       int pxsize;
-#endif
-
-       res = 0;
-       /* get the current owner and mode from cache or security attributes */
-       oldattr = (char*)NULL;
-       cached = fetch_cache(scx,ni);
-       if (cached) {
-               fileuid = cached->uid;
-               filegid = cached->gid;
-#if POSIXACLS
-               oldpxdesc = cached->pxdesc;
-               if (oldpxdesc) {
-                               /* must copy before merging */
-                       pxsize = sizeof(struct POSIX_SECURITY)
-                               + (oldpxdesc->acccnt + oldpxdesc->defcnt)*sizeof(struct POSIX_ACE);
-                       newpxdesc = (struct POSIX_SECURITY*)malloc(pxsize);
-                       if (newpxdesc) {
-                               memcpy(newpxdesc, oldpxdesc, pxsize);
-                               if (ntfs_merge_mode_posix(newpxdesc, mode))
-                                       res = -1;
-                       } else
-                               res = -1;
-               }
-#endif
-       } else {
-               fileuid = 0;
-               filegid = 0;
-               oldattr = getsecurityattr(scx->vol, ni);
-               if (oldattr) {
-#if POSIXACLS
-                       isdir = (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                               != const_cpu_to_le16(0);
-                       phead = (const SECURITY_DESCRIPTOR_RELATIVE*)
-                               oldattr;
-                       gsid = (const SID*)
-                               &oldattr[le32_to_cpu(phead->group)];
-#if OWNERFROMACL
-                       usid = ntfs_acl_owner(oldattr);
-#else
-                       usid = (const SID*)
-                               &oldattr[le32_to_cpu(phead->owner)];
-#endif
-                       newpxdesc = ntfs_build_permissions_posix(scx->mapping, oldattr,
-                                       usid, gsid, isdir);
-                       if (!newpxdesc || ntfs_merge_mode_posix(newpxdesc, mode))
-                               res = -1;
-                       else {
-                               fileuid = ntfs_find_user(scx->mapping[MAPUSERS],usid);
-                               filegid = ntfs_find_group(scx->mapping[MAPGROUPS],gsid);
-                       }
-#endif
-                       free(oldattr);
-               } else
-                       res = -1;
-       }
-       if (!res) {
-               /* check requested by root */
-               /* or chgrp requested by owner to an owned group */
-               if (!scx->uid
-                  || ((((int)uid < 0) || (uid == fileuid))
-                     && ((gid == scx->gid) || groupmember(scx, scx->uid, gid))
-                     && (fileuid == scx->uid))) {
-                       /* replace by the new usid and gsid */
-                       /* or reuse old gid and sid for cacheing */
-                       if ((int)uid < 0)
-                               uid = fileuid;
-                       if ((int)gid < 0)
-                               gid = filegid;
-#if POSIXACLS
-                       res = ntfs_set_owner_mode(scx, ni, uid, gid, 
-                               mode, newpxdesc);
-#else
-                       res = ntfs_set_owner_mode(scx, ni, uid, gid, mode);
-#endif
-               } else {
-                       res = -1;       /* neither owner nor root */
-                       errno = EPERM;
-               }
-       } else {
-               /*
-                * Should not happen : a default descriptor is generated
-                * by getsecurityattr() when there are none
-                */
-               ntfs_log_error("File has no security descriptor\n");
-               res = -1;
-               errno = EIO;
-       }
-#if POSIXACLS
-       free(newpxdesc);
-#endif
-       return (res ? -1 : 0);
-}
-
-/*
- *             Build a security id for a descriptor inherited from
- *     parent directory the Windows way
- */
-
-static le32 build_inherited_id(struct SECURITY_CONTEXT *scx,
-                       const char *parentattr, BOOL fordir)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *pphead;
-       const ACL *ppacl;
-       const SID *usid;
-       const SID *gsid;
-       BIGSID defusid;
-       BIGSID defgsid;
-       int offpacl;
-       int offowner;
-       int offgroup;
-       SECURITY_DESCRIPTOR_RELATIVE *pnhead;
-       ACL *pnacl;
-       int parentattrsz;
-       char *newattr;
-       int newattrsz;
-       int aclsz;
-       int usidsz;
-       int gsidsz;
-       int pos;
-       le32 securid;
-
-       parentattrsz = ntfs_attr_size(parentattr);
-       pphead = (const SECURITY_DESCRIPTOR_RELATIVE*)parentattr;
-       if (scx->mapping[MAPUSERS]) {
-               usid = ntfs_find_usid(scx->mapping[MAPUSERS], scx->uid, (SID*)&defusid);
-               gsid = ntfs_find_gsid(scx->mapping[MAPGROUPS], scx->gid, (SID*)&defgsid);
-               if (!usid)
-                       usid = adminsid;
-               if (!gsid)
-                       gsid = adminsid;
-       } else {
-               /*
-                * If there is no user mapping, we have to copy owner
-                * and group from parent directory.
-                * Windows never has to do that, because it can always
-                * rely on a user mapping
-                */
-               offowner = le32_to_cpu(pphead->owner);
-               usid = (const SID*)&parentattr[offowner];
-               offgroup = le32_to_cpu(pphead->group);
-               gsid = (const SID*)&parentattr[offgroup];
-       }
-               /*
-                * new attribute is smaller than parent's
-                * except for differences in SIDs which appear in
-                * owner, group and possible grants and denials in
-                * generic creator-owner and creator-group ACEs.
-                * For directories, an ACE may be duplicated for
-                * access and inheritance, so we double the count.
-                */
-       usidsz = ntfs_sid_size(usid);
-       gsidsz = ntfs_sid_size(gsid);
-       newattrsz = parentattrsz + 3*usidsz + 3*gsidsz;
-       if (fordir)
-               newattrsz *= 2;
-       newattr = (char*)ntfs_malloc(newattrsz);
-       if (newattr) {
-               pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)newattr;
-               pnhead->revision = SECURITY_DESCRIPTOR_REVISION;
-               pnhead->alignment = 0;
-               pnhead->control = SE_SELF_RELATIVE;
-               pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
-                       /*
-                        * locate and inherit DACL
-                        * do not test SE_DACL_PRESENT (wrong for "DR Watson")
-                        */
-               pnhead->dacl = const_cpu_to_le32(0);
-               if (pphead->dacl) {
-                       offpacl = le32_to_cpu(pphead->dacl);
-                       ppacl = (const ACL*)&parentattr[offpacl];
-                       pnacl = (ACL*)&newattr[pos];
-                       aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
-                       if (aclsz) {
-                               pnhead->dacl = cpu_to_le32(pos);
-                               pos += aclsz;
-                               pnhead->control |= SE_DACL_PRESENT;
-                       }
-               }
-                       /*
-                        * locate and inherit SACL
-                        */
-               pnhead->sacl = const_cpu_to_le32(0);
-               if (pphead->sacl) {
-                       offpacl = le32_to_cpu(pphead->sacl);
-                       ppacl = (const ACL*)&parentattr[offpacl];
-                       pnacl = (ACL*)&newattr[pos];
-                       aclsz = ntfs_inherit_acl(ppacl, pnacl, usid, gsid, fordir);
-                       if (aclsz) {
-                               pnhead->sacl = cpu_to_le32(pos);
-                               pos += aclsz;
-                               pnhead->control |= SE_SACL_PRESENT;
-                       }
-               }
-                       /*
-                        * inherit or redefine owner
-                        */
-               memcpy(&newattr[pos],usid,usidsz);
-               pnhead->owner = cpu_to_le32(pos);
-               pos += usidsz;
-                       /*
-                        * inherit or redefine group
-                        */
-               memcpy(&newattr[pos],gsid,gsidsz);
-               pnhead->group = cpu_to_le32(pos);
-               pos += usidsz;
-               securid = setsecurityattr(scx->vol,
-                       (SECURITY_DESCRIPTOR_RELATIVE*)newattr, pos);
-               free(newattr);
-       } else
-               securid = const_cpu_to_le32(0);
-       return (securid);
-}
-
-/*
- *             Get an inherited security id
- *
- *     For Windows compatibility, the normal initial permission setting
- *     may be inherited from the parent directory instead of being
- *     defined by the creation arguments.
- *
- *     The following creates an inherited id for that purpose.
- *
- *     Note : the owner and group of parent directory are also
- *     inherited (which is not the case on Windows) if no user mapping
- *     is defined.
- *
- *     Returns the inherited id, or zero if not possible (eg on NTFS 1.x)
- */
-
-le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
-                       ntfs_inode *dir_ni, BOOL fordir)
-{
-       struct CACHED_PERMISSIONS *cached;
-       char *parentattr;
-       le32 securid;
-
-       securid = const_cpu_to_le32(0);
-       cached = (struct CACHED_PERMISSIONS*)NULL;
-               /*
-                * Try to get inherited id from cache
-                */
-       if (test_nino_flag(dir_ni, v3_Extensions)
-                       && dir_ni->security_id) {
-               cached = fetch_cache(scx, dir_ni);
-               if (cached)
-                       securid = (fordir ? cached->inh_dirid
-                                       : cached->inh_fileid);
-       }
-               /*
-                * Not cached or not available in cache, compute it all
-                * Note : if parent directory has no id, it is not cacheable
-                */
-       if (!securid) {
-               parentattr = getsecurityattr(scx->vol, dir_ni);
-               if (parentattr) {
-                       securid = build_inherited_id(scx,
-                                               parentattr, fordir);
-                       free(parentattr);
-                       /*
-                        * Store the result into cache for further use
-                        */
-                       if (securid) {
-                               cached = fetch_cache(scx, dir_ni);
-                               if (cached) {
-                                       if (fordir)
-                                               cached->inh_dirid = securid;
-                                       else
-                                               cached->inh_fileid = securid;
-                               }
-                       }
-               }
-       }
-       return (securid);
-}
-
-/*
- *             Link a group to a member of group
- *
- *     Returns 0 if OK, -1 (and errno set) if error
- */
-
-static int link_single_group(struct MAPPING *usermapping, struct passwd *user,
-                       gid_t gid)
-{
-       struct group *group;
-       char **grmem;
-       int grcnt;
-       gid_t *groups;
-       int res;
-
-       res = 0;
-       group = getgrgid(gid);
-       if (group && group->gr_mem) {
-               grcnt = usermapping->grcnt;
-               groups = usermapping->groups;
-               grmem = group->gr_mem;
-               while (*grmem && strcmp(user->pw_name, *grmem))
-                       grmem++;
-               if (*grmem) {
-                       if (!grcnt)
-                               groups = (gid_t*)malloc(sizeof(gid_t));
-                       else
-                               groups = (gid_t*)realloc(groups,
-                                       (grcnt+1)*sizeof(gid_t));
-                       if (groups)
-                               groups[grcnt++] = gid;
-                       else {
-                               res = -1;
-                               errno = ENOMEM;
-                       }
-               }
-               usermapping->grcnt = grcnt;
-               usermapping->groups = groups;
-       }
-       return (res);
-}
-
-
-/*
- *             Statically link group to users
- *     This is based on groups defined in /etc/group and does not take
- *     the groups dynamically set by setgroups() nor any changes in
- *     /etc/group into account
- *
- *     Only mapped groups and root group are linked to mapped users
- *
- *     Returns 0 if OK, -1 (and errno set) if error
- *
- */
-
-static int link_group_members(struct SECURITY_CONTEXT *scx)
-{
-       struct MAPPING *usermapping;
-       struct MAPPING *groupmapping;
-       struct passwd *user;
-       int res;
-
-       res = 0;
-       for (usermapping=scx->mapping[MAPUSERS]; usermapping && !res;
-                       usermapping=usermapping->next) {
-               usermapping->grcnt = 0;
-               usermapping->groups = (gid_t*)NULL;
-               user = getpwuid(usermapping->xid);
-               if (user && user->pw_name) {
-                       for (groupmapping=scx->mapping[MAPGROUPS];
-                                       groupmapping && !res;
-                                       groupmapping=groupmapping->next) {
-                               if (link_single_group(usermapping, user,
-                                   groupmapping->xid))
-                                       res = -1;
-                               }
-                       if (!res && link_single_group(usermapping,
-                                        user, (gid_t)0))
-                               res = -1;
-               }
-       }
-       return (res);
-}
-
-/*
- *             Apply default single user mapping
- *     returns zero if successful
- */
-
-static int ntfs_do_default_mapping(struct SECURITY_CONTEXT *scx,
-                        uid_t uid, gid_t gid, const SID *usid)
-{
-       struct MAPPING *usermapping;
-       struct MAPPING *groupmapping;
-       SID *sid;
-       int sidsz;
-       int res;
-
-       res = -1;
-       sidsz = ntfs_sid_size(usid);
-       sid = (SID*)ntfs_malloc(sidsz);
-       if (sid) {
-               memcpy(sid,usid,sidsz);
-               usermapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
-               if (usermapping) {
-                       groupmapping = (struct MAPPING*)ntfs_malloc(sizeof(struct MAPPING));
-                       if (groupmapping) {
-                               usermapping->sid = sid;
-                               usermapping->xid = uid;
-                               usermapping->next = (struct MAPPING*)NULL;
-                               groupmapping->sid = sid;
-                               groupmapping->xid = gid;
-                               groupmapping->next = (struct MAPPING*)NULL;
-                               scx->mapping[MAPUSERS] = usermapping;
-                               scx->mapping[MAPGROUPS] = groupmapping;
-                               res = 0;
-                       }
-               }
-       }
-       return (res);
-}
-
-/*
- *             Make sure there are no ambiguous mapping
- *     Ambiguous mapping may lead to undesired configurations and
- *     we had rather be safe until the consequences are understood
- */
-
-#if 0 /* not activated for now */
-
-static BOOL check_mapping(const struct MAPPING *usermapping,
-               const struct MAPPING *groupmapping)
-{
-       const struct MAPPING *mapping1;
-       const struct MAPPING *mapping2;
-       BOOL ambiguous;
-
-       ambiguous = FALSE;
-       for (mapping1=usermapping; mapping1; mapping1=mapping1->next)
-               for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
-                       if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
-                               if (mapping1->xid != mapping2->xid)
-                                       ambiguous = TRUE;
-                       } else {
-                               if (mapping1->xid == mapping2->xid)
-                                       ambiguous = TRUE;
-                       }
-       for (mapping1=groupmapping; mapping1; mapping1=mapping1->next)
-               for (mapping2=mapping1->next; mapping2; mapping1=mapping2->next)
-                       if (ntfs_same_sid(mapping1->sid,mapping2->sid)) {
-                               if (mapping1->xid != mapping2->xid)
-                                       ambiguous = TRUE;
-                       } else {
-                               if (mapping1->xid == mapping2->xid)
-                                       ambiguous = TRUE;
-                       }
-       return (ambiguous);
-}
-
-#endif
-
-#if 0 /* not used any more */
-
-/*
- *             Try and apply default single user mapping
- *     returns zero if successful
- */
-
-static int ntfs_default_mapping(struct SECURITY_CONTEXT *scx)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       ntfs_inode *ni;
-       char *securattr;
-       const SID *usid;
-       int res;
-
-       res = -1;
-       ni = ntfs_pathname_to_inode(scx->vol, NULL, "/.");
-       if (ni) {
-               securattr = getsecurityattr(scx->vol, ni);
-               if (securattr) {
-                       phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
-                       usid = (SID*)&securattr[le32_to_cpu(phead->owner)];
-                       if (ntfs_is_user_sid(usid))
-                               res = ntfs_do_default_mapping(scx,
-                                               scx->uid, scx->gid, usid);
-                       free(securattr);
-               }
-               ntfs_inode_close(ni);
-       }
-       return (res);
-}
-
-#endif
-
-/*
- *             Basic read from a user mapping file on another volume
- */
-
-static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
-{
-       return (read(*(int*)fileid, buf, size));
-}
-
-
-/*
- *             Read from a user mapping file on current NTFS partition
- */
-
-static int localread(void *fileid, char *buf, size_t size, off_t offs)
-{
-       return (ntfs_attr_data_read((ntfs_inode*)fileid,
-                       AT_UNNAMED, 0, buf, size, offs));
-}
-
-/*
- *             Build the user mapping
- *     - according to a mapping file if defined (or default present),
- *     - or try default single user mapping if possible
- *
- *     The mapping is specific to a mounted device
- *     No locking done, mounting assumed non multithreaded
- *
- *     returns zero if mapping is successful
- *     (failure should not be interpreted as an error)
- */
-
-int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
-                       BOOL allowdef)
-{
-       struct MAPLIST *item;
-       struct MAPLIST *firstitem;
-       struct MAPPING *usermapping;
-       struct MAPPING *groupmapping;
-       ntfs_inode *ni;
-       int fd;
-       static struct {
-               u8 revision;
-               u8 levels;
-               be16 highbase;
-               be32 lowbase;
-               le32 level1;
-               le32 level2;
-               le32 level3;
-               le32 level4;
-               le32 level5;
-       } defmap = {
-               1, 5, const_cpu_to_be16(0), const_cpu_to_be32(5),
-               const_cpu_to_le32(21),
-               const_cpu_to_le32(DEFSECAUTH1), const_cpu_to_le32(DEFSECAUTH2),
-               const_cpu_to_le32(DEFSECAUTH3), const_cpu_to_le32(DEFSECBASE)
-       } ;
-
-       /* be sure not to map anything until done */
-       scx->mapping[MAPUSERS] = (struct MAPPING*)NULL;
-       scx->mapping[MAPGROUPS] = (struct MAPPING*)NULL;
-
-       if (!usermap_path) usermap_path = MAPPINGFILE;
-       if (usermap_path[0] == '/') {
-               fd = open(usermap_path,O_RDONLY);
-               if (fd > 0) {
-                       firstitem = ntfs_read_mapping(basicread, (void*)&fd);
-                       close(fd);
-               } else
-                       firstitem = (struct MAPLIST*)NULL;
-       } else {
-               ni = ntfs_pathname_to_inode(scx->vol, NULL, usermap_path);
-               if (ni) {
-                       firstitem = ntfs_read_mapping(localread, ni);
-                       ntfs_inode_close(ni);
-               } else
-                       firstitem = (struct MAPLIST*)NULL;
-       }
-
-
-       if (firstitem) {
-               usermapping = ntfs_do_user_mapping(firstitem);
-               groupmapping = ntfs_do_group_mapping(firstitem);
-               if (usermapping && groupmapping) {
-                       scx->mapping[MAPUSERS] = usermapping;
-                       scx->mapping[MAPGROUPS] = groupmapping;
-               } else
-                       ntfs_log_error("There were no valid user or no valid group\n");
-               /* now we can free the memory copy of input text */
-               /* and rely on internal representation */
-               while (firstitem) {
-                       item = firstitem->next;
-                       free(firstitem);
-                       firstitem = item;
-               }
-       } else {
-                       /* no mapping file, try a default mapping */
-               if (allowdef) {
-                       if (!ntfs_do_default_mapping(scx,
-                                       0, 0, (const SID*)&defmap))
-                               ntfs_log_info("Using default user mapping\n");
-               }
-       }
-       return (!scx->mapping[MAPUSERS] || link_group_members(scx));
-}
-
-#ifdef HAVE_SETXATTR    /* extended attributes interface required */
-
-/*
- *             Get the ntfs attribute into an extended attribute
- *     The attribute is returned according to cpu endianness
- */
-
-int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size)
-{
-       u32 attrib;
-       size_t outsize;
-
-       outsize = 0;    /* default to no data and no error */
-       if (ni) {
-               attrib = le32_to_cpu(ni->flags);
-               if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                       attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
-               else
-                       attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
-               if (!attrib)
-                       attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
-               outsize = sizeof(FILE_ATTR_FLAGS);
-               if (size >= outsize) {
-                       if (value)
-                               memcpy(value,&attrib,outsize);
-                       else
-                               errno = EINVAL;
-               }
-       }
-       return (outsize ? (int)outsize : -errno);
-}
-
-/*
- *             Get the ntfs attributes from an inode
- *     The attributes are returned according to cpu endianness
- *
- *     Returns the attributes if successful (cannot be zero)
- *             0 if failed (errno to tell why)
- */
-
-u32 ntfs_get_inode_attributes(ntfs_inode *ni)
-{
-       u32 attrib = -1;
-
-       if (ni) {
-               attrib = le32_to_cpu(ni->flags);
-               if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-                       attrib |= const_le32_to_cpu(FILE_ATTR_DIRECTORY);
-               else
-                       attrib &= ~const_le32_to_cpu(FILE_ATTR_DIRECTORY);
-               if (!attrib)
-                       attrib |= const_le32_to_cpu(FILE_ATTR_NORMAL);
-       } else
-               errno = EINVAL;
-       return (attrib);
-}
-
-/*
- *             Set the ntfs attributes on an inode
- *     The attribute is expected according to cpu endianness
- *
- *     Returns 0 if successful
- *             -1 if failed (errno to tell why)
- */
-
-int ntfs_set_inode_attributes(ntfs_inode *ni, u32 attrib)
-{
-       le32 settable;
-       ATTR_FLAGS dirflags;
-       int res;
-
-       res = -1;
-       if (ni) {
-               settable = FILE_ATTR_SETTABLE;
-               res = 0;
-               if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
-                       /*
-                        * Accept changing compression for a directory
-                        * and set index root accordingly
-                        */
-                       settable |= FILE_ATTR_COMPRESSED;
-                       if ((ni->flags ^ cpu_to_le32(attrib))
-                                    & FILE_ATTR_COMPRESSED) {
-                               if (ni->flags & FILE_ATTR_COMPRESSED)
-                                       dirflags = const_cpu_to_le16(0);
-                               else
-                                       dirflags = ATTR_IS_COMPRESSED;
-                               res = ntfs_attr_set_flags(ni, AT_INDEX_ROOT,
-                                       NTFS_INDEX_I30, 4, dirflags,
-                                       ATTR_COMPRESSION_MASK);
-                       }
-               }
-               if (!res) {
-                       ni->flags = (ni->flags & ~settable)
-                                | (cpu_to_le32(attrib) & settable);
-                       NInoFileNameSetDirty(ni);
-                       NInoSetDirty(ni);
-               }
-       } else
-               errno = EINVAL;
-       return (res);
-}
-
-/*
- *             Return the ntfs attribute into an extended attribute
- *     The attribute is expected according to cpu endianness
- *
- *     Returns 0, or -1 if there is a problem
- */
-
-int ntfs_set_ntfs_attrib(ntfs_inode *ni,
-                       const char *value, size_t size, int flags)
-{
-       u32 attrib;
-       int res;
-
-       res = -1;
-       if (ni && value && (size >= sizeof(FILE_ATTR_FLAGS))) {
-               if (!(flags & XATTR_CREATE)) {
-                       /* copy to avoid alignment problems */
-                       memcpy(&attrib,value,sizeof(FILE_ATTR_FLAGS));
-                       res = ntfs_set_inode_attributes(ni, attrib);
-               } else
-                       errno = EEXIST;
-       } else
-               errno = EINVAL;
-       return (res ? -1 : 0);
-}
-
-#endif /* HAVE_SETXATTR */
-
-/*
- *     Open $Secure once for all
- *     returns zero if it succeeds
- *             non-zero if it fails. This is not an error (on NTFS v1.x)
- */
-
-
-int ntfs_open_secure(ntfs_volume *vol)
-{
-       ntfs_inode *ni;
-       int res;
-
-       res = -1;
-       vol->secure_ni = (ntfs_inode*)NULL;
-       vol->secure_xsii = (ntfs_index_context*)NULL;
-       vol->secure_xsdh = (ntfs_index_context*)NULL;
-       if (vol->major_ver >= 3) {
-                       /* make sure this is a genuine $Secure inode 9 */
-               ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
-               if (ni && (ni->mft_no == 9)) {
-                       vol->secure_reentry = 0;
-                       vol->secure_xsii = ntfs_index_ctx_get(ni,
-                                               sii_stream, 4);
-                       vol->secure_xsdh = ntfs_index_ctx_get(ni,
-                                               sdh_stream, 4);
-                       if (ni && vol->secure_xsii && vol->secure_xsdh) {
-                               vol->secure_ni = ni;
-                               res = 0;
-                       }
-               }
-       }
-       return (res);
-}
-
-/*
- *             Final cleaning
- *     Allocated memory is freed to facilitate the detection of memory leaks
- */
-
-void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
-{
-       ntfs_volume *vol;
-
-       vol = scx->vol;
-       if (vol->secure_ni) {
-               ntfs_index_ctx_put(vol->secure_xsii);
-               ntfs_index_ctx_put(vol->secure_xsdh);
-               ntfs_inode_close(vol->secure_ni);
-               
-       }
-       ntfs_free_mapping(scx->mapping);
-       free_caches(scx);
-}
-
-/*
- *             API for direct access to security descriptors
- *     based on Win32 API
- */
-
-
-/*
- *             Selective feeding of a security descriptor into user buffer
- *
- *     Returns TRUE if successful
- */
-
-static BOOL feedsecurityattr(const char *attr, u32 selection,
-               char *buf, u32 buflen, u32 *psize)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       SECURITY_DESCRIPTOR_RELATIVE *pnhead;
-       const ACL *pdacl;
-       const ACL *psacl;
-       const SID *pusid;
-       const SID *pgsid;
-       unsigned int offdacl;
-       unsigned int offsacl;
-       unsigned int offowner;
-       unsigned int offgroup;
-       unsigned int daclsz;
-       unsigned int saclsz;
-       unsigned int usidsz;
-       unsigned int gsidsz;
-       unsigned int size; /* size of requested attributes */
-       BOOL ok;
-       unsigned int pos;
-       unsigned int avail;
-       le16 control;
-
-       avail = 0;
-       control = SE_SELF_RELATIVE;
-       phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
-       size = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
-
-               /* locate DACL if requested and available */
-       if (phead->dacl && (selection & DACL_SECURITY_INFORMATION)) {
-               offdacl = le32_to_cpu(phead->dacl);
-               pdacl = (const ACL*)&attr[offdacl];
-               daclsz = le16_to_cpu(pdacl->size);
-               size += daclsz;
-               avail |= DACL_SECURITY_INFORMATION;
-       } else
-               offdacl = daclsz = 0;
-
-               /* locate owner if requested and available */
-       offowner = le32_to_cpu(phead->owner);
-       if (offowner && (selection & OWNER_SECURITY_INFORMATION)) {
-                       /* find end of USID */
-               pusid = (const SID*)&attr[offowner];
-               usidsz = ntfs_sid_size(pusid);
-               size += usidsz;
-               avail |= OWNER_SECURITY_INFORMATION;
-       } else
-               offowner = usidsz = 0;
-
-               /* locate group if requested and available */
-       offgroup = le32_to_cpu(phead->group);
-       if (offgroup && (selection & GROUP_SECURITY_INFORMATION)) {
-                       /* find end of GSID */
-               pgsid = (const SID*)&attr[offgroup];
-               gsidsz = ntfs_sid_size(pgsid);
-               size += gsidsz;
-               avail |= GROUP_SECURITY_INFORMATION;
-       } else
-               offgroup = gsidsz = 0;
-
-               /* locate SACL if requested and available */
-       if (phead->sacl && (selection & SACL_SECURITY_INFORMATION)) {
-                       /* find end of SACL */
-               offsacl = le32_to_cpu(phead->sacl);
-               psacl = (const ACL*)&attr[offsacl];
-               saclsz = le16_to_cpu(psacl->size);
-               size += saclsz;
-               avail |= SACL_SECURITY_INFORMATION;
-       } else
-               offsacl = saclsz = 0;
-
-               /*
-                * Check having enough size in destination buffer
-                * (required size is returned nevertheless so that
-                * the request can be reissued with adequate size)
-                */
-       if (size > buflen) {
-               *psize = size;
-               errno = EINVAL;
-               ok = FALSE;
-       } else {
-               if (selection & OWNER_SECURITY_INFORMATION)
-                       control |= phead->control & SE_OWNER_DEFAULTED;
-               if (selection & GROUP_SECURITY_INFORMATION)
-                       control |= phead->control & SE_GROUP_DEFAULTED;
-               if (selection & DACL_SECURITY_INFORMATION)
-                       control |= phead->control
-                                       & (SE_DACL_PRESENT
-                                          | SE_DACL_DEFAULTED
-                                          | SE_DACL_AUTO_INHERITED
-                                          | SE_DACL_PROTECTED);
-               if (selection & SACL_SECURITY_INFORMATION)
-                       control |= phead->control
-                                       & (SE_SACL_PRESENT
-                                          | SE_SACL_DEFAULTED
-                                          | SE_SACL_AUTO_INHERITED
-                                          | SE_SACL_PROTECTED);
-               /*
-                * copy header and feed new flags, even if no detailed data
-                */
-               memcpy(buf,attr,sizeof(SECURITY_DESCRIPTOR_RELATIVE));
-               pnhead = (SECURITY_DESCRIPTOR_RELATIVE*)buf;
-               pnhead->control = control;
-               pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
-
-               /* copy DACL if requested and available */
-               if (selection & avail & DACL_SECURITY_INFORMATION) {
-                       pnhead->dacl = cpu_to_le32(pos);
-                       memcpy(&buf[pos],&attr[offdacl],daclsz);
-                       pos += daclsz;
-               } else
-                       pnhead->dacl = const_cpu_to_le32(0);
-
-               /* copy SACL if requested and available */
-               if (selection & avail & SACL_SECURITY_INFORMATION) {
-                       pnhead->sacl = cpu_to_le32(pos);
-                       memcpy(&buf[pos],&attr[offsacl],saclsz);
-                       pos += saclsz;
-               } else
-                       pnhead->sacl = const_cpu_to_le32(0);
-
-               /* copy owner if requested and available */
-               if (selection & avail & OWNER_SECURITY_INFORMATION) {
-                       pnhead->owner = cpu_to_le32(pos);
-                       memcpy(&buf[pos],&attr[offowner],usidsz);
-                       pos += usidsz;
-               } else
-                       pnhead->owner = const_cpu_to_le32(0);
-
-               /* copy group if requested and available */
-               if (selection & avail & GROUP_SECURITY_INFORMATION) {
-                       pnhead->group = cpu_to_le32(pos);
-                       memcpy(&buf[pos],&attr[offgroup],gsidsz);
-                       pos += gsidsz;
-               } else
-                       pnhead->group = const_cpu_to_le32(0);
-               if (pos != size)
-                       ntfs_log_error("Error in security descriptor size\n");
-               *psize = size;
-               ok = TRUE;
-       }
-
-       return (ok);
-}
-
-/*
- *             Merge a new security descriptor into the old one
- *     and assign to designated file
- *
- *     Returns TRUE if successful
- */
-
-static BOOL mergesecurityattr(ntfs_volume *vol, const char *oldattr,
-               const char *newattr, u32 selection, ntfs_inode *ni)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *oldhead;
-       const SECURITY_DESCRIPTOR_RELATIVE *newhead;
-       SECURITY_DESCRIPTOR_RELATIVE *targhead;
-       const ACL *pdacl;
-       const ACL *psacl;
-       const SID *powner;
-       const SID *pgroup;
-       int offdacl;
-       int offsacl;
-       int offowner;
-       int offgroup;
-       unsigned int size;
-       le16 control;
-       char *target;
-       int pos;
-       int oldattrsz;
-       int newattrsz;
-       BOOL ok;
-
-       ok = FALSE; /* default return */
-       oldhead = (const SECURITY_DESCRIPTOR_RELATIVE*)oldattr;
-       newhead = (const SECURITY_DESCRIPTOR_RELATIVE*)newattr;
-       oldattrsz = ntfs_attr_size(oldattr);
-       newattrsz = ntfs_attr_size(newattr);
-       target = (char*)ntfs_malloc(oldattrsz + newattrsz);
-       if (target) {
-               targhead = (SECURITY_DESCRIPTOR_RELATIVE*)target;
-               pos = sizeof(SECURITY_DESCRIPTOR_RELATIVE);
-               control = SE_SELF_RELATIVE;
-                       /*
-                        * copy new DACL if selected
-                        * or keep old DACL if any
-                        */
-               if ((selection & DACL_SECURITY_INFORMATION) ?
-                               newhead->dacl : oldhead->dacl) {
-                       if (selection & DACL_SECURITY_INFORMATION) {
-                               offdacl = le32_to_cpu(newhead->dacl);
-                               pdacl = (const ACL*)&newattr[offdacl];
-                       } else {
-                               offdacl = le32_to_cpu(oldhead->dacl);
-                               pdacl = (const ACL*)&oldattr[offdacl];
-                       }
-                       size = le16_to_cpu(pdacl->size);
-                       memcpy(&target[pos], pdacl, size);
-                       targhead->dacl = cpu_to_le32(pos);
-                       pos += size;
-               } else
-                       targhead->dacl = const_cpu_to_le32(0);
-               if (selection & DACL_SECURITY_INFORMATION) {
-                       control |= newhead->control
-                                       & (SE_DACL_PRESENT
-                                          | SE_DACL_DEFAULTED
-                                          | SE_DACL_PROTECTED);
-                       if (newhead->control & SE_DACL_AUTO_INHERIT_REQ)
-                               control |= SE_DACL_AUTO_INHERITED;
-               } else
-                       control |= oldhead->control
-                                       & (SE_DACL_PRESENT
-                                          | SE_DACL_DEFAULTED
-                                          | SE_DACL_AUTO_INHERITED
-                                          | SE_DACL_PROTECTED);
-                       /*
-                        * copy new SACL if selected
-                        * or keep old SACL if any
-                        */
-               if ((selection & SACL_SECURITY_INFORMATION) ?
-                               newhead->sacl : oldhead->sacl) {
-                       if (selection & SACL_SECURITY_INFORMATION) {
-                               offsacl = le32_to_cpu(newhead->sacl);
-                               psacl = (const ACL*)&newattr[offsacl];
-                       } else {
-                               offsacl = le32_to_cpu(oldhead->sacl);
-                               psacl = (const ACL*)&oldattr[offsacl];
-                       }
-                       size = le16_to_cpu(psacl->size);
-                       memcpy(&target[pos], psacl, size);
-                       targhead->sacl = cpu_to_le32(pos);
-                       pos += size;
-               } else
-                       targhead->sacl = const_cpu_to_le32(0);
-               if (selection & SACL_SECURITY_INFORMATION) {
-                       control |= newhead->control
-                                       & (SE_SACL_PRESENT
-                                          | SE_SACL_DEFAULTED
-                                          | SE_SACL_PROTECTED);
-                       if (newhead->control & SE_SACL_AUTO_INHERIT_REQ)
-                               control |= SE_SACL_AUTO_INHERITED;
-               } else
-                       control |= oldhead->control
-                                       & (SE_SACL_PRESENT
-                                          | SE_SACL_DEFAULTED
-                                          | SE_SACL_AUTO_INHERITED
-                                          | SE_SACL_PROTECTED);
-                       /*
-                        * copy new OWNER if selected
-                        * or keep old OWNER if any
-                        */
-               if ((selection & OWNER_SECURITY_INFORMATION) ?
-                               newhead->owner : oldhead->owner) {
-                       if (selection & OWNER_SECURITY_INFORMATION) {
-                               offowner = le32_to_cpu(newhead->owner);
-                               powner = (const SID*)&newattr[offowner];
-                       } else {
-                               offowner = le32_to_cpu(oldhead->owner);
-                               powner = (const SID*)&oldattr[offowner];
-                       }
-                       size = ntfs_sid_size(powner);
-                       memcpy(&target[pos], powner, size);
-                       targhead->owner = cpu_to_le32(pos);
-                       pos += size;
-               } else
-                       targhead->owner = const_cpu_to_le32(0);
-               if (selection & OWNER_SECURITY_INFORMATION)
-                       control |= newhead->control & SE_OWNER_DEFAULTED;
-               else
-                       control |= oldhead->control & SE_OWNER_DEFAULTED;
-                       /*
-                        * copy new GROUP if selected
-                        * or keep old GROUP if any
-                        */
-               if ((selection & GROUP_SECURITY_INFORMATION) ?
-                               newhead->group : oldhead->group) {
-                       if (selection & GROUP_SECURITY_INFORMATION) {
-                               offgroup = le32_to_cpu(newhead->group);
-                               pgroup = (const SID*)&newattr[offgroup];
-                               control |= newhead->control
-                                                & SE_GROUP_DEFAULTED;
-                       } else {
-                               offgroup = le32_to_cpu(oldhead->group);
-                               pgroup = (const SID*)&oldattr[offgroup];
-                               control |= oldhead->control
-                                                & SE_GROUP_DEFAULTED;
-                       }
-                       size = ntfs_sid_size(pgroup);
-                       memcpy(&target[pos], pgroup, size);
-                       targhead->group = cpu_to_le32(pos);
-                       pos += size;
-               } else
-                       targhead->group = const_cpu_to_le32(0);
-               if (selection & GROUP_SECURITY_INFORMATION)
-                       control |= newhead->control & SE_GROUP_DEFAULTED;
-               else
-                       control |= oldhead->control & SE_GROUP_DEFAULTED;
-               targhead->revision = SECURITY_DESCRIPTOR_REVISION;
-               targhead->alignment = 0;
-               targhead->control = control;
-               ok = !update_secur_descr(vol, target, ni);
-               free(target);
-       }
-       return (ok);
-}
-
-int ntfs_get_inode_security(ntfs_inode *ni, u32 selection,
-                           char *buf, u32 buflen, u32 *psize)
-{
-       int res;
-       char *attr;
-
-       res = 0;
-       if (ni) {
-               attr = getsecurityattr(ni->vol, ni);
-               if (attr) {
-                       if (feedsecurityattr(attr, selection,
-                                       buf, buflen, psize)) {
-                               if (test_nino_flag(ni, v3_Extensions)
-                                   && ni->security_id)
-                                       res = le32_to_cpu(
-                                               ni->security_id);
-                               else
-                                       res = -1;
-                       }
-                       free(attr);
-               }
-       } else
-               errno = EINVAL;
-       return (res);
-}
-
-int ntfs_set_inode_security(ntfs_inode *ni, u32 selection, const char *attr)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       int attrsz;
-       BOOL missing;
-       char *oldattr;
-       int res;
-
-       res = -1; /* default return */
-       if (ni) {
-               phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
-               attrsz = ntfs_attr_size(attr);
-               /* if selected, owner and group must be present or defaulted */
-               missing = ((selection & OWNER_SECURITY_INFORMATION)
-                               && !phead->owner
-                               && !(phead->control & SE_OWNER_DEFAULTED))
-                       || ((selection & GROUP_SECURITY_INFORMATION)
-                               && !phead->group
-                               && !(phead->control & SE_GROUP_DEFAULTED));
-               if (!missing
-                   && (phead->control & SE_SELF_RELATIVE)
-                   && ntfs_valid_descr(attr, attrsz)) {
-                       oldattr = getsecurityattr(ni->vol, ni);
-                       if (oldattr) {
-                               if (mergesecurityattr(ni->vol, oldattr, attr,
-                                                       selection, ni)) {
-                                       res = 0;
-                               }
-                               free(oldattr);
-                       }
-               } else
-                       errno = EINVAL;
-       } else
-               errno = EINVAL;
-       return (res);
-}
-
-/*
- *             Return the security descriptor of a file
- *     This is intended to be similar to GetFileSecurity() from Win32
- *     in order to facilitate the development of portable tools
- *
- *     returns zero if unsuccessful (following Win32 conventions)
- *             -1 if no securid
- *             the securid if any
- *
- *  The Win32 API is :
- *
- *  BOOL WINAPI GetFileSecurity(
- *    __in          LPCTSTR lpFileName,
- *    __in          SECURITY_INFORMATION RequestedInformation,
- *    __out_opt     PSECURITY_DESCRIPTOR pSecurityDescriptor,
- *    __in          DWORD nLength,
- *    __out         LPDWORD lpnLengthNeeded
- *  );
- *
- */
-
-int ntfs_get_file_security(struct SECURITY_API *scapi,
-               const char *path, u32 selection,
-               char *buf, u32 buflen, u32 *psize)
-{
-       ntfs_inode *ni;
-       char *attr;
-       int res;
-
-       res = 0; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API)) {
-               ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
-               if (ni) {
-                       attr = getsecurityattr(scapi->security.vol, ni);
-                       if (attr) {
-                               if (feedsecurityattr(attr,selection,
-                                               buf,buflen,psize)) {
-                                       if (test_nino_flag(ni, v3_Extensions)
-                                           && ni->security_id)
-                                               res = le32_to_cpu(
-                                                       ni->security_id);
-                                       else
-                                               res = -1;
-                               }
-                               free(attr);
-                       }
-                       ntfs_inode_close(ni);
-               } else
-                       errno = ENOENT;
-               if (!res) *psize = 0;
-       } else
-               errno = EINVAL; /* do not clear *psize */
-       return (res);
-}
-
-
-/*
- *             Set the security descriptor of a file or directory
- *     This is intended to be similar to SetFileSecurity() from Win32
- *     in order to facilitate the development of portable tools
- *
- *     returns zero if unsuccessful (following Win32 conventions)
- *             -1 if no securid
- *             the securid if any
- *
- *  The Win32 API is :
- *
- *  BOOL WINAPI SetFileSecurity(
- *    __in          LPCTSTR lpFileName,
- *    __in          SECURITY_INFORMATION SecurityInformation,
- *    __in          PSECURITY_DESCRIPTOR pSecurityDescriptor
- *  );
- */
-
-int ntfs_set_file_security(struct SECURITY_API *scapi,
-               const char *path, u32 selection, const char *attr)
-{
-       const SECURITY_DESCRIPTOR_RELATIVE *phead;
-       ntfs_inode *ni;
-       int attrsz;
-       BOOL missing;
-       char *oldattr;
-       int res;
-
-       res = 0; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API) && attr) {
-               phead = (const SECURITY_DESCRIPTOR_RELATIVE*)attr;
-               attrsz = ntfs_attr_size(attr);
-               /* if selected, owner and group must be present or defaulted */
-               missing = ((selection & OWNER_SECURITY_INFORMATION)
-                               && !phead->owner
-                               && !(phead->control & SE_OWNER_DEFAULTED))
-                       || ((selection & GROUP_SECURITY_INFORMATION)
-                               && !phead->group
-                               && !(phead->control & SE_GROUP_DEFAULTED));
-               if (!missing
-                   && (phead->control & SE_SELF_RELATIVE)
-                   && ntfs_valid_descr(attr, attrsz)) {
-                       ni = ntfs_pathname_to_inode(scapi->security.vol,
-                               NULL, path);
-                       if (ni) {
-                               oldattr = getsecurityattr(scapi->security.vol,
-                                               ni);
-                               if (oldattr) {
-                                       if (mergesecurityattr(
-                                               scapi->security.vol,
-                                               oldattr, attr,
-                                               selection, ni)) {
-                                               if (test_nino_flag(ni,
-                                                           v3_Extensions))
-                                                       res = le32_to_cpu(
-                                                           ni->security_id);
-                                               else
-                                                       res = -1;
-                                       }
-                                       free(oldattr);
-                               }
-                               ntfs_inode_close(ni);
-                       }
-               } else
-                       errno = EINVAL;
-       } else
-               errno = EINVAL;
-       return (res);
-}
-
-
-/*
- *             Return the attributes of a file
- *     This is intended to be similar to GetFileAttributes() from Win32
- *     in order to facilitate the development of portable tools
- *
- *     returns -1 if unsuccessful (Win32 : INVALID_FILE_ATTRIBUTES)
- *
- *  The Win32 API is :
- *
- *  DWORD WINAPI GetFileAttributes(
- *   __in  LPCTSTR lpFileName
- *  );
- */
-
-int ntfs_get_file_attributes(struct SECURITY_API *scapi, const char *path)
-{
-       ntfs_inode *ni;
-       s32 attrib;
-
-       attrib = -1; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API) && path) {
-               ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
-               if (ni) {
-                       attrib = ntfs_get_inode_attributes(ni);
-                       ntfs_inode_close(ni);
-               } else
-                       errno = ENOENT;
-       } else
-               errno = EINVAL; /* do not clear *psize */
-       return (attrib);
-}
-
-
-/*
- *             Set attributes to a file or directory
- *     This is intended to be similar to SetFileAttributes() from Win32
- *     in order to facilitate the development of portable tools
- *
- *     Only a few flags can be set (same list as Win32)
- *
- *     returns zero if unsuccessful (following Win32 conventions)
- *             nonzero if successful
- *
- *  The Win32 API is :
- *
- *  BOOL WINAPI SetFileAttributes(
- *    __in  LPCTSTR lpFileName,
- *    __in  DWORD dwFileAttributes
- *  );
- */
-
-BOOL ntfs_set_file_attributes(struct SECURITY_API *scapi,
-               const char *path, s32 attrib)
-{
-       ntfs_inode *ni;
-       int res;
-
-       res = 0; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API) && path) {
-               ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
-               if (ni) {
-                       /* Win32 convention here : -1 means successful */
-                       if (!ntfs_set_inode_attributes(ni, attrib))
-                               res = -1;
-                       if (ntfs_inode_close(ni))
-                               res = 0;
-               } else
-                       errno = ENOENT;
-       }
-       return (res);
-}
-
-
-BOOL ntfs_read_directory(struct SECURITY_API *scapi,
-               const char *path, ntfs_filldir_t callback, void *context)
-{
-       ntfs_inode *ni;
-       BOOL ok;
-       s64 pos;
-
-       ok = FALSE; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API) && callback) {
-               ni = ntfs_pathname_to_inode(scapi->security.vol, NULL, path);
-               if (ni) {
-                       if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
-                               pos = 0;
-                               ntfs_readdir(ni,&pos,context,callback);
-                               ok = !ntfs_inode_close(ni);
-                       } else {
-                               ntfs_inode_close(ni);
-                               errno = ENOTDIR;
-                       }
-               } else
-                       errno = ENOENT;
-       } else
-               errno = EINVAL; /* do not clear *psize */
-       return (ok);
-}
-
-/*
- *             read $SDS (for auditing security data)
- *
- *     Returns the number or read bytes, or -1 if there is an error
- */
-
-int ntfs_read_sds(struct SECURITY_API *scapi,
-               char *buf, u32 size, u32 offset)
-{
-       int got;
-
-       got = -1; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API)) {
-               if (scapi->security.vol->secure_ni)
-                       got = ntfs_attr_data_read(scapi->security.vol->secure_ni,
-                               STREAM_SDS, 4, buf, size, offset);
-               else
-                       errno = EOPNOTSUPP;
-       } else
-               errno = EINVAL;
-       return (got);
-}
-
-/*
- *             read $SII (for auditing security data)
- *
- *     Returns next entry, or NULL if there is an error
- */
-
-INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
-               INDEX_ENTRY *entry)
-{
-       SII_INDEX_KEY key;
-       INDEX_ENTRY *ret;
-       BOOL found;
-       ntfs_index_context *xsii;
-
-       ret = (INDEX_ENTRY*)NULL; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API)) {
-               xsii = scapi->security.vol->secure_xsii;
-               if (xsii) {
-                       if (!entry) {
-                               key.security_id = const_cpu_to_le32(0);
-                               found = !ntfs_index_lookup((char*)&key,
-                                               sizeof(SII_INDEX_KEY), xsii);
-                               /* not supposed to find */
-                               if (!found && (errno == ENOENT))
-                                       ret = xsii->entry;
-                       } else
-                               ret = ntfs_index_next(entry,xsii);
-                       if (!ret)
-                               errno = ENODATA;
-               } else
-                       errno = EOPNOTSUPP;
-       } else
-               errno = EINVAL;
-       return (ret);
-}
-
-/*
- *             read $SDH (for auditing security data)
- *
- *     Returns next entry, or NULL if there is an error
- */
-
-INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
-               INDEX_ENTRY *entry)
-{
-       SDH_INDEX_KEY key;
-       INDEX_ENTRY *ret;
-       BOOL found;
-       ntfs_index_context *xsdh;
-
-       ret = (INDEX_ENTRY*)NULL; /* default return */
-       if (scapi && (scapi->magic == MAGIC_API)) {
-               xsdh = scapi->security.vol->secure_xsdh;
-               if (xsdh) {
-                       if (!entry) {
-                               key.hash = const_cpu_to_le32(0);
-                               key.security_id = const_cpu_to_le32(0);
-                               found = !ntfs_index_lookup((char*)&key,
-                                               sizeof(SDH_INDEX_KEY), xsdh);
-                               /* not supposed to find */
-                               if (!found && (errno == ENOENT))
-                                       ret = xsdh->entry;
-                       } else
-                               ret = ntfs_index_next(entry,xsdh);
-                       if (!ret)
-                               errno = ENODATA;
-               } else errno = ENOTSUP;
-       } else
-               errno = EINVAL;
-       return (ret);
-}
-
-/*
- *             Get the mapped user SID
- *     A buffer of 40 bytes has to be supplied
- *
- *     returns the size of the SID, or zero and errno set if not found
- */
-
-int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf)
-{
-       const SID *usid;
-       BIGSID defusid;
-       int size;
-
-       size = 0;
-       if (scapi && (scapi->magic == MAGIC_API)) {
-               usid = ntfs_find_usid(scapi->security.mapping[MAPUSERS], uid, (SID*)&defusid);
-               if (usid) {
-                       size = ntfs_sid_size(usid);
-                       memcpy(buf,usid,size);
-               } else
-                       errno = ENODATA;
-       } else
-               errno = EINVAL;
-       return (size);
-}
-
-/*
- *             Get the mapped group SID
- *     A buffer of 40 bytes has to be supplied
- *
- *     returns the size of the SID, or zero and errno set if not found
- */
-
-int ntfs_get_gsid(struct SECURITY_API *scapi, gid_t gid, char *buf)
-{
-       const SID *gsid;
-       BIGSID defgsid;
-       int size;
-
-       size = 0;
-       if (scapi && (scapi->magic == MAGIC_API)) {
-               gsid = ntfs_find_gsid(scapi->security.mapping[MAPGROUPS], gid, (SID*)&defgsid);
-               if (gsid) {
-                       size = ntfs_sid_size(gsid);
-                       memcpy(buf,gsid,size);
-               } else
-                       errno = ENODATA;
-       } else
-               errno = EINVAL;
-       return (size);
-}
-
-/*
- *             Get the user mapped to a SID
- *
- *     returns the uid, or -1 if not found
- */
-
-int ntfs_get_user(struct SECURITY_API *scapi, const SID *usid)
-{
-       int uid;
-
-       uid = -1;
-       if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(usid)) {
-               if (ntfs_same_sid(usid,adminsid))
-                       uid = 0;
-               else {
-                       uid = ntfs_find_user(scapi->security.mapping[MAPUSERS], usid);
-                       if (!uid) {
-                               uid = -1;
-                               errno = ENODATA;
-                       }
-               }
-       } else
-               errno = EINVAL;
-       return (uid);
-}
-
-/*
- *             Get the group mapped to a SID
- *
- *     returns the uid, or -1 if not found
- */
-
-int ntfs_get_group(struct SECURITY_API *scapi, const SID *gsid)
-{
-       int gid;
-
-       gid = -1;
-       if (scapi && (scapi->magic == MAGIC_API) && ntfs_valid_sid(gsid)) {
-               if (ntfs_same_sid(gsid,adminsid))
-                       gid = 0;
-               else {
-                       gid = ntfs_find_group(scapi->security.mapping[MAPGROUPS], gsid);
-                       if (!gid) {
-                               gid = -1;
-                               errno = ENODATA;
-                       }
-               }
-       } else
-               errno = EINVAL;
-       return (gid);
-}
-
-/*
- *             Initializations before calling ntfs_get_file_security()
- *     ntfs_set_file_security() and ntfs_read_directory()
- *
- *     Only allowed for root
- *
- *     Returns an (obscured) struct SECURITY_API* needed for further calls
- *             NULL if not root (EPERM) or device is mounted (EBUSY)
- */
-
-struct SECURITY_API *ntfs_initialize_file_security(const char *device,
-                               unsigned long flags)
-{
-       ntfs_volume *vol;
-       unsigned long mntflag;
-       int mnt;
-       struct SECURITY_API *scapi;
-       struct SECURITY_CONTEXT *scx;
-
-       scapi = (struct SECURITY_API*)NULL;
-       mnt = ntfs_check_if_mounted(device, &mntflag);
-       if (!mnt && !(mntflag & NTFS_MF_MOUNTED) && !getuid()) {
-               vol = ntfs_mount(device, flags);
-               if (vol) {
-                       scapi = (struct SECURITY_API*)
-                               ntfs_malloc(sizeof(struct SECURITY_API));
-                       if (!ntfs_volume_get_free_space(vol)
-                           && scapi) {
-                               scapi->magic = MAGIC_API;
-                               scapi->seccache = (struct PERMISSIONS_CACHE*)NULL;
-                               scx = &scapi->security;
-                               scx->vol = vol;
-                               scx->uid = getuid();
-                               scx->gid = getgid();
-                               scx->pseccache = &scapi->seccache;
-                               scx->vol->secure_flags = 0;
-                                       /* accept no mapping and no $Secure */
-                               ntfs_build_mapping(scx,(const char*)NULL,TRUE);
-                               ntfs_open_secure(vol);
-                       } else {
-                               if (scapi)
-                                       free(scapi);
-                               else
-                                       errno = ENOMEM;
-                               mnt = ntfs_umount(vol,FALSE);
-                               scapi = (struct SECURITY_API*)NULL;
-                       }
-               }
-       } else
-               if (getuid())
-                       errno = EPERM;
-               else
-                       errno = EBUSY;
-       return (scapi);
-}
-
-/*
- *             Leaving after ntfs_initialize_file_security()
- *
- *     Returns FALSE if FAILED
- */
-
-BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
-{
-       int ok;
-       ntfs_volume *vol;
-
-       ok = FALSE;
-       if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
-               vol = scapi->security.vol;
-               ntfs_close_secure(&scapi->security);
-               free(scapi);
-               if (!ntfs_umount(vol, 0))
-                       ok = TRUE;
-       }
-       return (ok);
-}
-