Merge tag '2017.2.15' into edge.strict_endians
Conflicts: include/ntfs-3g/layout.h include/ntfs-3g/logfile.h libntfs-3g/reparse.c libntfs-3g/unistr.c ntfsprogs/ntfsdump_logfile.c ntfsprogs/ntfsfix.c ntfsprogs/ntfsinfo.c ntfsprogs/ntfsrecover.c ntfsprogs/ntfsresize.c ntfsprogs/playlog.c src/lowntfs-3g.c src/ntfs-3g.cedge.strict_endians
commit
26ed262ae4
15
README
15
README
|
@ -16,8 +16,10 @@ reliability and feature richness per invested effort wise.
|
|||
|
||||
Besides the common file system features, NTFS-3G has support for file
|
||||
ownership and permissions, POSIX ACLs, junction points, extended attributes
|
||||
and creating compressed files. Parameter files in the directory .NTFS-3G may
|
||||
be required to enable them, please get the instructions from
|
||||
and creating internally compressed files (parameter files in the directory
|
||||
.NTFS-3G may be required to enable them). The new compressed file formats
|
||||
available in Windows 10 can also be read through a plugin. For using
|
||||
advanced features, please get the instructions from
|
||||
|
||||
http://www.tuxera.com/community/ntfs-3g-advanced/
|
||||
|
||||
|
@ -59,6 +61,8 @@ typing :
|
|||
|
||||
Below are a few specific options to ./configure :
|
||||
--disable-ntfsprogs : do not build the ntfsprogs tools,
|
||||
--enable-extras : build more ntfsprogs tools,
|
||||
--disable-plugins : disable support for plugins
|
||||
--enable-posix-acls : enable support for Posix ACLs
|
||||
--enable-xattr-mappings : enable system extended attributes mappings
|
||||
--with-fuse=external : use external fuse (overriding Linux default)
|
||||
|
@ -145,9 +149,16 @@ partition. See man 8 ntfscluster for details.
|
|||
ntfsinfo - Show some information about an NTFS partition or one of the files
|
||||
or directories within it. See man 8 ntfsinfo for details.
|
||||
|
||||
ntfsrecover - Recover updates committed by Windows but interrupted before
|
||||
being synced.
|
||||
|
||||
ntfsls - List information about files in a directory residing on an NTFS
|
||||
partition. See man 8 ntfsls for details.
|
||||
|
||||
ntfscat - Concatenate files and print their contents on the standard output.
|
||||
|
||||
ntfscp - Overwrite files on an NTFS partition.
|
||||
|
||||
ntfssecaudit : audit the security metadata.
|
||||
|
||||
ntfsusermap : assistance for building a user mapping file.
|
||||
|
|
33
configure.ac
33
configure.ac
|
@ -24,8 +24,8 @@
|
|||
|
||||
# Autoconf
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT([ntfs-3g],[2016.2.22],[ntfs-3g-devel@lists.sf.net])
|
||||
LIBNTFS_3G_VERSION="87"
|
||||
AC_INIT([ntfs-3g],[2017.2.15],[ntfs-3g-devel@lists.sf.net])
|
||||
LIBNTFS_3G_VERSION="88"
|
||||
AC_CONFIG_SRCDIR([src/ntfs-3g.c])
|
||||
|
||||
# Environment
|
||||
|
@ -121,6 +121,14 @@ AC_ARG_ENABLE(
|
|||
[enable_xattr_mappings="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[plugins],
|
||||
[AS_HELP_STRING([--disable-plugins], [Disable external reparse point
|
||||
plugins for the ntfs-3g FUSE driver])],
|
||||
[if test x${enableval} = "xyes"; then disable_plugins="no"; fi],
|
||||
[disable_plugins="no"]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(
|
||||
[device-default-io-ops],
|
||||
[AS_HELP_STRING([--disable-device-default-io-ops],[install default IO ops])],
|
||||
|
@ -465,12 +473,13 @@ fi
|
|||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_MAJOR
|
||||
AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
|
||||
mntent.h stddef.h stdint.h stdlib.h stdio.h stdarg.h string.h \
|
||||
strings.h errno.h time.h unistd.h utime.h wchar.h getopt.h features.h \
|
||||
regex.h endian.h byteswap.h sys/byteorder.h sys/disk.h sys/endian.h \
|
||||
sys/param.h sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h \
|
||||
sys/vfs.h sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h \
|
||||
sys/param.h sys/ioctl.h sys/mount.h sys/stat.h sys/types.h \
|
||||
sys/vfs.h sys/statvfs.h linux/major.h linux/fd.h \
|
||||
linux/fs.h inttypes.h linux/hdreg.h \
|
||||
machine/endian.h windows.h syslog.h pwd.h malloc.h])
|
||||
|
||||
|
@ -534,6 +543,16 @@ AC_CHECK_FUNCS([ \
|
|||
])
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
# The dlopen API might be in libc or in libdl. Check libc first, then
|
||||
# fall back to libdl.
|
||||
LIBDL=""
|
||||
if test "x${disable_plugins}" = "xno"; then
|
||||
AC_CHECK_LIB(c, dlopen, ,
|
||||
[AC_CHECK_LIB(dl, dlopen, [LIBDL="-ldl"],
|
||||
[AC_MSG_ERROR(["Unable to find libdl (required for external plugin support)"])])])
|
||||
fi
|
||||
AC_SUBST([LIBDL])
|
||||
|
||||
if test "$GCC" = "yes" ; then
|
||||
# We add -Wall to enable some compiler warnings.
|
||||
CFLAGS="${CFLAGS} -Wall"
|
||||
|
@ -566,6 +585,7 @@ test "${enable_device_default_io_ops}" = "no" && AC_DEFINE(
|
|||
test "${enable_mtab}" = "no" && AC_DEFINE([IGNORE_MTAB], [1], [Don't update /etc/mtab])
|
||||
test "${enable_posix_acls}" != "no" && AC_DEFINE([POSIXACLS], [1], [POSIX ACL support])
|
||||
test "${enable_xattr_mappings}" != "no" && AC_DEFINE([XATTR_MAPPINGS], [1], [system extended attributes mappings])
|
||||
test "${disable_plugins}" != "no" && AC_DEFINE([DISABLE_PLUGINS], [1], [Define to 1 for disabling reparse plugins])
|
||||
|
||||
test "${enable_really_static}" = "yes" && enable_library="no"
|
||||
test "${enable_library}" = "no" && enable_ldconfig="no"
|
||||
|
@ -617,6 +637,7 @@ AM_CONDITIONAL([ENABLE_NTFS_3G], [test "${enable_ntfs_3g}" = "yes"])
|
|||
AM_CONDITIONAL([ENABLE_NTFSPROGS], [test "${enable_ntfsprogs}" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_EXTRAS], [test "${enable_extras}" = "yes"])
|
||||
AM_CONDITIONAL([ENABLE_QUARANTINED], [test "${enable_quarantined}" = "yes"])
|
||||
AM_CONDITIONAL([DISABLE_PLUGINS], [test "${disable_plugins}" != "no"])
|
||||
|
||||
# workaround for <autoconf-2.60
|
||||
if test -z "${docdir}"; then
|
||||
|
@ -658,11 +679,11 @@ AC_CONFIG_FILES([
|
|||
ntfsprogs/ntfstruncate.8
|
||||
ntfsprogs/ntfsfallocate.8
|
||||
ntfsprogs/ntfsrecover.8
|
||||
ntfsprogs/ntfsusermap.8
|
||||
ntfsprogs/ntfssecaudit.8
|
||||
src/Makefile
|
||||
src/ntfs-3g.8
|
||||
src/ntfs-3g.probe.8
|
||||
src/ntfs-3g.usermap.8
|
||||
src/ntfs-3g.secaudit.8
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
|
|
|
@ -44,8 +44,10 @@ extern "C" {
|
|||
#ifdef POSIXACLS
|
||||
/*
|
||||
* FUSE_CAP_DONT_MASK: don't apply umask to file mode on create operations
|
||||
* FUSE_CAP_POSIX_ACL: process Posix ACLs within the kernel
|
||||
*/
|
||||
#define FUSE_CAP_DONT_MASK (1 << 6)
|
||||
#define FUSE_CAP_POSIX_ACL (1 << 18)
|
||||
#endif
|
||||
|
||||
#define FUSE_CAP_BIG_WRITES (1 << 5)
|
||||
|
|
|
@ -138,12 +138,14 @@ struct fuse_file_lock {
|
|||
* FUSE_BIG_WRITES: allow big writes to be issued to the file system
|
||||
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
|
||||
* FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
|
||||
* FUSE_POSIX_ACL: kernel supports Posix ACLs
|
||||
*/
|
||||
#define FUSE_ASYNC_READ (1 << 0)
|
||||
#define FUSE_POSIX_LOCKS (1 << 1)
|
||||
#define FUSE_BIG_WRITES (1 << 5)
|
||||
#define FUSE_DONT_MASK (1 << 6)
|
||||
#define FUSE_HAS_IOCTL_DIR (1 << 11)
|
||||
#define FUSE_POSIX_ACL (1 << 19)
|
||||
|
||||
/**
|
||||
* Release flags
|
||||
|
|
|
@ -30,7 +30,8 @@ headers = \
|
|||
mst.h \
|
||||
ntfstime.h \
|
||||
object_id.h \
|
||||
param.h \
|
||||
param.h \
|
||||
plugin.h \
|
||||
realpath.h \
|
||||
reparse.h \
|
||||
runlist.h \
|
||||
|
|
|
@ -37,16 +37,6 @@
|
|||
#define CACHE_PERMISSIONS_BITS 6 /* log2 of unitary allocation of permissions */
|
||||
#define CACHE_PERMISSIONS_SIZE 262144 /* max cacheable permissions */
|
||||
|
||||
/*
|
||||
* Macro definitions needed to share code with secaudit
|
||||
*/
|
||||
|
||||
#define NTFS_FIND_USID(map,uid,buf) ntfs_find_usid(map,uid,buf)
|
||||
#define NTFS_FIND_GSID(map,gid,buf) ntfs_find_gsid(map,gid,buf)
|
||||
#define NTFS_FIND_USER(map,usid) ntfs_find_user(map,usid)
|
||||
#define NTFS_FIND_GROUP(map,gsid) ntfs_find_group(map,gsid)
|
||||
|
||||
|
||||
/*
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
|
@ -102,10 +92,11 @@
|
|||
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
|
||||
|
||||
/*
|
||||
* A type large enough to hold any SID
|
||||
* Maximum SID size and a type large enough to hold it
|
||||
*/
|
||||
|
||||
typedef char BIGSID[40];
|
||||
#define MAX_SID_SIZE (8 + SID_MAX_SUB_AUTHORITIES*4)
|
||||
typedef char BIGSID[MAX_SID_SIZE];
|
||||
|
||||
/*
|
||||
* Struct to hold the input mapping file
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
#define ENODATA ENOENT
|
||||
#endif
|
||||
|
||||
#ifndef ELIBBAD
|
||||
#define ELIBBAD ENOEXEC
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
|
|
@ -109,6 +109,7 @@ extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
|
|||
void *dirent, ntfs_filldir_t filldir);
|
||||
|
||||
ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni);
|
||||
u32 ntfs_interix_types(ntfs_inode *ni);
|
||||
|
||||
int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
char *value, size_t size);
|
||||
|
|
|
@ -129,6 +129,7 @@ typedef struct {
|
|||
VCN parent_vcn[MAX_PARENT_VCN]; /* entry's parent nodes */
|
||||
int pindex; /* maximum it's the number of the parent nodes */
|
||||
BOOL ib_dirty;
|
||||
BOOL bad_index;
|
||||
u32 block_size;
|
||||
u8 vcn_size_bits;
|
||||
} ntfs_index_context;
|
||||
|
|
|
@ -171,6 +171,12 @@ typedef enum {
|
|||
#define ntfs_is_empty_recordp(p) ( ntfs_is_magicp(p, empty) )
|
||||
|
||||
|
||||
/*
|
||||
* The size of a logical sector in bytes, used as the sequence number stride for
|
||||
* multi-sector transfers. This is intended to be less than or equal to the
|
||||
* physical sector size, since if this were greater than the physical sector
|
||||
* size, then incomplete multi-sector transfers may not be detected.
|
||||
*/
|
||||
#define NTFS_BLOCK_SIZE 512
|
||||
#define NTFS_BLOCK_SIZE_BITS 9
|
||||
|
||||
|
@ -545,16 +551,15 @@ typedef enum {
|
|||
* enum COLLATION_RULES - The collation rules for sorting views/indexes/etc
|
||||
* (32-bit).
|
||||
*
|
||||
* COLLATION_UNICODE_STRING - Collate Unicode strings by comparing their binary
|
||||
* Unicode values, except that when a character can be uppercased, the
|
||||
* upper case value collates before the lower case one.
|
||||
* COLLATION_FILE_NAME - Collate file names as Unicode strings. The collation
|
||||
* is done very much like COLLATION_UNICODE_STRING. In fact I have no idea
|
||||
* what the difference is. Perhaps the difference is that file names
|
||||
* would treat some special characters in an odd way (see
|
||||
* unistr.c::ntfs_collate_names() and unistr.c::legal_ansi_char_array[]
|
||||
* for what I mean but COLLATION_UNICODE_STRING would not give any special
|
||||
* treatment to any characters at all, but this is speculation.
|
||||
* COLLATION_BINARY - Collate by binary compare where the first byte is most
|
||||
* significant.
|
||||
* COLLATION_FILE_NAME - Collate Unicode strings by comparing their 16-bit
|
||||
* coding units, primarily ignoring case using the volume's $UpCase table,
|
||||
* but falling back to a case-sensitive comparison if the names are equal
|
||||
* ignoring case.
|
||||
* COLLATION_UNICODE_STRING - TODO: this is not yet implemented and still needs
|
||||
* to be properly documented --- is it really the same as
|
||||
* COLLATION_FILE_NAME?
|
||||
* COLLATION_NTOFS_ULONG - Sorting is done according to ascending le32 key
|
||||
* values. E.g. used for $SII index in FILE_Secure, which sorts by
|
||||
* security_id (le32).
|
||||
|
@ -585,17 +590,9 @@ static const COLLATION_RULES
|
|||
#else
|
||||
typedef enum {
|
||||
#endif
|
||||
COLLATION_BINARY = const_cpu_to_le32(0), /* Collate by binary
|
||||
compare where the first byte is most
|
||||
significant. */
|
||||
COLLATION_FILE_NAME = const_cpu_to_le32(1), /* Collate file names
|
||||
as Unicode strings. */
|
||||
COLLATION_UNICODE_STRING = const_cpu_to_le32(2), /* Collate Unicode
|
||||
strings by comparing their binary
|
||||
Unicode values, except that when a
|
||||
character can be uppercased, the upper
|
||||
case value collates before the lower
|
||||
case one. */
|
||||
COLLATION_BINARY = const_cpu_to_le32(0),
|
||||
COLLATION_FILE_NAME = const_cpu_to_le32(1),
|
||||
COLLATION_UNICODE_STRING = const_cpu_to_le32(2),
|
||||
COLLATION_NTOFS_ULONG = const_cpu_to_le32(16),
|
||||
COLLATION_NTOFS_SID = const_cpu_to_le32(17),
|
||||
COLLATION_NTOFS_SECURITY_HASH = const_cpu_to_le32(18),
|
||||
|
@ -1141,12 +1138,17 @@ typedef enum {
|
|||
FILE_NAME_WIN32 = 0x01,
|
||||
/* The standard WinNT/2k NTFS long filenames. Case insensitive.
|
||||
All Unicode chars except: '\0', '"', '*', '/', ':', '<',
|
||||
'>', '?', '\' and '|'. Further, names cannot end with a '.'
|
||||
or a space. */
|
||||
'>', '?', '\' and '|'. Trailing dots and spaces are allowed,
|
||||
even though on Windows a filename with such a suffix can only
|
||||
be created and accessed using a WinNT-style path, i.e.
|
||||
\\?\-prefixed. (If a regular path is used, Windows will
|
||||
strip the trailing dots and spaces, which makes such
|
||||
filenames incompatible with most Windows software.) */
|
||||
FILE_NAME_DOS = 0x02,
|
||||
/* The standard DOS filenames (8.3 format). Uppercase only.
|
||||
All 8-bit characters greater space, except: '"', '*', '+',
|
||||
',', '/', ':', ';', '<', '=', '>', '?' and '\'. */
|
||||
',', '/', ':', ';', '<', '=', '>', '?' and '\'. Trailing
|
||||
dots and spaces are forbidden. */
|
||||
FILE_NAME_WIN32_AND_DOS = 0x03,
|
||||
/* 3 means that both the Win32 and the DOS filenames are
|
||||
identical and hence have been saved in this single filename
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* logfile.h - Exports for $LogFile handling. Originated from the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2000-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2016 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
|
||||
|
@ -93,7 +94,8 @@ typedef struct {
|
|||
version is 1. */
|
||||
/* 28*/ sle16 major_ver; /* Log file major version. We only support
|
||||
version 1.1. */
|
||||
/* sizeof() = 30 (0x1e) bytes */
|
||||
/* 30*/ le16 usn;
|
||||
/* sizeof() = 32 (0x20) bytes */
|
||||
} __attribute__((__packed__)) RESTART_PAGE_HEADER;
|
||||
|
||||
/*
|
||||
|
@ -101,8 +103,8 @@ typedef struct {
|
|||
* in this particular client array. Also inside the client records themselves,
|
||||
* this means that there are no client records preceding or following this one.
|
||||
*/
|
||||
#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff)
|
||||
#define LOGFILE_NO_CLIENT_CPU 0xffff
|
||||
#define LOGFILE_NO_CLIENT const_cpu_to_le16(LOGFILE_NO_CLIENT_CPU)
|
||||
|
||||
/*
|
||||
* These are the so far known RESTART_AREA_* flags (16-bit) which contain
|
||||
|
@ -329,18 +331,16 @@ typedef struct {
|
|||
le32 flags;
|
||||
le16 page_count;
|
||||
le16 page_position;
|
||||
union {
|
||||
struct {
|
||||
le16 next_record_offset;
|
||||
u8 reserved[6];
|
||||
leLSN last_end_lsn;
|
||||
} __attribute__((__packed__)) packed;
|
||||
} __attribute__((__packed__)) header;
|
||||
le16 next_record_offset;
|
||||
le16 reserved[3];
|
||||
leLSN last_end_lsn;
|
||||
} __attribute__((__packed__)) RECORD_PAGE_HEADER;
|
||||
|
||||
/**
|
||||
* enum LOG_RECORD_FLAGS - Possible 16-bit flags for log records.
|
||||
*
|
||||
* Some flags describe what kind of update is being logged.
|
||||
*
|
||||
* (Or is it log record pages?)
|
||||
*/
|
||||
#if ENABLE_STRICT_ENDIANNESS_CHECKING
|
||||
|
@ -351,6 +351,9 @@ static const LOG_RECORD_FLAGS
|
|||
typedef enum {
|
||||
#endif
|
||||
LOG_RECORD_MULTI_PAGE = const_cpu_to_le16(0x0001), /* ??? */
|
||||
/* The flags below were introduced in Windows 10 */
|
||||
LOG_RECORD_DELETING = const_cpu_to_le16(0x0002),
|
||||
LOG_RECORD_ADDING = const_cpu_to_le16(0x0004),
|
||||
#if !ENABLE_STRICT_ENDIANNESS_CHECKING
|
||||
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
|
||||
/* This has nothing to do with the log record. It is only so
|
||||
|
@ -368,6 +371,52 @@ typedef struct {
|
|||
le16 client_index;
|
||||
} __attribute__((__packed__)) LOG_CLIENT_ID;
|
||||
|
||||
/*
|
||||
* LOG_RECORD_TYPE : types of log records
|
||||
*/
|
||||
|
||||
#if ENABLE_STRICT_ENDIANNESS_CHECKING
|
||||
typedef le32 LOG_RECORD_TYPE;
|
||||
|
||||
static const LOG_RECORD_TYPE
|
||||
#else
|
||||
enum {
|
||||
#endif
|
||||
LOG_STANDARD = const_cpu_to_le32(1),
|
||||
LOG_CHECKPOINT = const_cpu_to_le32(2),
|
||||
#if !ENABLE_STRICT_ENDIANNESS_CHECKING
|
||||
LOG_RECORD_TYPE_PLACE_HOLDER = 0xffffffffU
|
||||
} ;
|
||||
typedef le32 LOG_RECORD_TYPE;
|
||||
#else
|
||||
__LOG_RECORD_TYPE_end;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ATTRIBUTE_FLAGS : flags describing the kind of NTFS record
|
||||
* is being updated.
|
||||
* These flags were introduced in Vista, only two flags are known?
|
||||
*/
|
||||
|
||||
#if ENABLE_STRICT_ENDIANNESS_CHECKING
|
||||
typedef le16 ATTRIBUTE_FLAGS;
|
||||
|
||||
static const ATTRIBUTE_FLAGS
|
||||
#else
|
||||
enum {
|
||||
#endif
|
||||
ACTS_ON_MFT = const_cpu_to_le16(2),
|
||||
ACTS_ON_INDX = const_cpu_to_le16(8),
|
||||
#if !ENABLE_STRICT_ENDIANNESS_CHECKING
|
||||
ATTRIBUTE_FLAGS_PLACE_HOLDER = 0xffff,
|
||||
} ;
|
||||
typedef le16 ATTRIBUTE_FLAGS;
|
||||
#else
|
||||
__ATTRIBUTE_FLAGS_end;
|
||||
#endif
|
||||
|
||||
#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */
|
||||
|
||||
/**
|
||||
* struct LOG_RECORD - Log record header.
|
||||
*
|
||||
|
@ -379,32 +428,79 @@ typedef struct {
|
|||
leLSN client_undo_next_lsn;
|
||||
le32 client_data_length;
|
||||
LOG_CLIENT_ID client_id;
|
||||
le32 record_type;
|
||||
LOG_RECORD_TYPE record_type;
|
||||
le32 transaction_id;
|
||||
le16 flags;
|
||||
LOG_RECORD_FLAGS log_record_flags;
|
||||
le16 reserved_or_alignment[3];
|
||||
/* Now are at ofs 0x30 into struct. */
|
||||
le16 redo_operation;
|
||||
le16 undo_operation;
|
||||
le16 redo_offset;
|
||||
le16 redo_length;
|
||||
le16 undo_offset;
|
||||
le16 undo_length;
|
||||
le16 target_attribute;
|
||||
le16 lcns_to_follow; /* Number of lcn_list entries
|
||||
union {
|
||||
struct {
|
||||
le16 undo_offset;
|
||||
le16 undo_length;
|
||||
le16 target_attribute;
|
||||
le16 lcns_to_follow; /* Number of lcn_list entries
|
||||
following this entry. */
|
||||
/* Now at ofs 0x40. */
|
||||
le16 record_offset;
|
||||
le16 attribute_offset;
|
||||
le32 alignment_or_reserved;
|
||||
leVCN target_vcn;
|
||||
le16 record_offset;
|
||||
le16 attribute_offset;
|
||||
le16 cluster_index;
|
||||
ATTRIBUTE_FLAGS attribute_flags;
|
||||
leVCN target_vcn;
|
||||
/* Now at ofs 0x50. */
|
||||
struct { /* Only present if lcns_to_follow
|
||||
is not 0. */
|
||||
leLCN lcn;
|
||||
} __attribute__((__packed__)) lcn_list[0];
|
||||
leLCN lcn_list[0]; /* Only present if lcns_to_follow
|
||||
is not 0. */
|
||||
} __attribute__((__packed__));
|
||||
struct {
|
||||
leLSN transaction_lsn;
|
||||
leLSN attributes_lsn;
|
||||
leLSN names_lsn;
|
||||
leLSN dirty_pages_lsn;
|
||||
le64 unknown_list[0];
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__)) LOG_RECORD;
|
||||
|
||||
/**
|
||||
* struct BITMAP_ACTION - Bitmap change being logged
|
||||
*/
|
||||
|
||||
struct BITMAP_ACTION {
|
||||
le32 firstbit;
|
||||
le32 count;
|
||||
} ;
|
||||
|
||||
/**
|
||||
* struct ATTR - Attribute record.
|
||||
*
|
||||
* The format of an attribute record has changed from Windows 10.
|
||||
* The old format was 44 bytes long, despite having 8 bytes fields,
|
||||
* and this leads to alignment problems in arrays.
|
||||
* This problem does not occur in the new format, which is shorter.
|
||||
* The format being used can generally be determined from size.
|
||||
*/
|
||||
typedef struct { /* Format up to Win10 (44 bytes) */
|
||||
le64 unknown1;
|
||||
le64 unknown2;
|
||||
le64 inode;
|
||||
leLSN lsn;
|
||||
le32 unknown3;
|
||||
le32 type;
|
||||
le32 unknown4;
|
||||
} __attribute__((__packed__)) ATTR_OLD;
|
||||
|
||||
typedef struct { /* Format since Win10 (40 bytes) */
|
||||
le64 unknown1;
|
||||
le64 unknown2;
|
||||
le32 type;
|
||||
le32 unknown3;
|
||||
le64 inode;
|
||||
leLSN lsn;
|
||||
} __attribute__((__packed__)) ATTR_NEW;
|
||||
|
||||
extern BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp);
|
||||
extern BOOL ntfs_is_logfile_clean(ntfs_attr *log_na, RESTART_PAGE_HEADER *rp);
|
||||
extern int ntfs_empty_logfile(ntfs_attr *na);
|
||||
|
|
|
@ -107,6 +107,11 @@ enum {
|
|||
* performances, but bad on security with internal fuse or external
|
||||
* fuse older than 2.8
|
||||
*
|
||||
* On Linux, cacheing is discouraged for the high level interface
|
||||
* in order to get proper support of hard links. As a consequence,
|
||||
* having access control in the file system leads to fewer requests
|
||||
* to the file system and fewer context switches.
|
||||
*
|
||||
* Possible values for high level :
|
||||
* 1 : no cache, kernel control (recommended)
|
||||
* 4 : no cache, file system control
|
||||
|
@ -115,12 +120,13 @@ enum {
|
|||
*
|
||||
* Possible values for low level :
|
||||
* 2 : no cache, kernel control
|
||||
* 3 : use kernel/fuse cache, kernel control (external fuse >= 2.8)
|
||||
* 5 : no cache, file system control (recommended on Linux)
|
||||
* 3 : use kernel/fuse cache, kernel control (recommended)
|
||||
* 5 : no cache, file system control
|
||||
* 6 : kernel/fuse cache, file system control (OpenIndiana only)
|
||||
* 8 : no cache, kernel control for ACLs
|
||||
* 9 : kernel/fuse cache, kernel control for ACLs (target)
|
||||
*
|
||||
* Use of options 7 and 8 requires a patch to fuse
|
||||
* Use of options 7, 8 and 9 requires a fuse module upgrade
|
||||
* When Posix ACLs are selected in the configure options, a value
|
||||
* of 6 is added in the mount report.
|
||||
*/
|
||||
|
@ -132,13 +138,14 @@ enum {
|
|||
*/
|
||||
#define HPERMSCONFIG 6
|
||||
#define LPERMSCONFIG 6
|
||||
#else
|
||||
#else /* defined(__sun) && defined(__SVR4) */
|
||||
/*
|
||||
* Cacheing by kernel is buggy on Linux when access control is done
|
||||
* by the file system, and also when using hard-linked files on
|
||||
* the fuse high level interface.
|
||||
*/
|
||||
#define HPERMSCONFIG 1
|
||||
#if defined(FUSE_INTERNAL) || !defined(FUSE_VERSION) || (FUSE_VERSION < 28)
|
||||
#define LPERMSCONFIG 5
|
||||
#else
|
||||
#define LPERMSCONFIG 3
|
||||
#endif
|
||||
#define LPERMSCONFIG 3 /* Use 9 when ACLs are supported by fuse kernel */
|
||||
#endif /* defined(__sun) && defined(__SVR4) */
|
||||
|
||||
#endif /* defined _NTFS_PARAM_H */
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* plugin.h : define interface for plugin development
|
||||
*
|
||||
* Copyright (c) 2015 Jean-Pierre Andre
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (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
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file defines the interface to ntfs-3g plugins which
|
||||
* add support for processing some type of reparse points.
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_PLUGIN_H
|
||||
#define _NTFS_PLUGIN_H
|
||||
|
||||
#include "inode.h"
|
||||
#include "layout.h"
|
||||
|
||||
struct fuse_file_info;
|
||||
struct stat;
|
||||
|
||||
/*
|
||||
* The plugin operations currently defined.
|
||||
* These functions should return a non-negative value when they
|
||||
* succeed, or a negative errno value when they fail.
|
||||
* They must not close or free their arguments.
|
||||
* The file system must be left in a consistent state after
|
||||
* each individual call.
|
||||
* If an operation is not defined, an EOPNOTSUPP error is
|
||||
* returned to caller.
|
||||
*/
|
||||
typedef struct plugin_operations {
|
||||
/*
|
||||
* Set the attributes st_size, st_blocks and st_mode
|
||||
* into a struct stat. The returned st_mode must at least
|
||||
* define the file type. Depending on the permissions options
|
||||
* used for mounting, the umask will be applied to the returned
|
||||
* permissions, or the permissions will be changed according
|
||||
* to the ACL set on the file.
|
||||
*/
|
||||
int (*getattr)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct stat *stbuf);
|
||||
|
||||
/*
|
||||
* Open a file for reading or writing
|
||||
* The field fi->flags indicates the kind of opening.
|
||||
* The field fi->fh may be used to store some information which
|
||||
* will be available to subsequent reads and writes. When used
|
||||
* this field must be non-null.
|
||||
* The returned value is zero for success and a negative errno
|
||||
* value for failure.
|
||||
*/
|
||||
int (*open)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Release an open file
|
||||
* This is only called if fi->fh has been set to a non-null
|
||||
* value while opening. It may be used to free some context
|
||||
* specific to the open file.
|
||||
* The returned value is zero for success or a negative errno
|
||||
* value for failure.
|
||||
*/
|
||||
int (*release)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Read from an open file
|
||||
* The returned value is the count of bytes which were read
|
||||
* or a negative errno value for failure.
|
||||
* If the returned value is positive, the access time stamp
|
||||
* will be updated after the call.
|
||||
*/
|
||||
int (*read)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
char *buf, size_t size,
|
||||
off_t offset, struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Write to an open file
|
||||
* The file system must be left consistent after each write call,
|
||||
* the file itself must be at least deletable if the application
|
||||
* writing to it is killed for some reason.
|
||||
* The returned value is the count of bytes which were written
|
||||
* or a negative errno value for failure.
|
||||
* If the returned value is positive, the modified time stamp
|
||||
* will be updated after the call.
|
||||
*/
|
||||
int (*write)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
const char *buf, size_t size,
|
||||
off_t offset, struct fuse_file_info *fi);
|
||||
|
||||
/*
|
||||
* Get a symbolic link
|
||||
* The symbolic link must be returned in an allocated buffer,
|
||||
* encoded in a zero terminated multibyte string compatible
|
||||
* which the locale mount option.
|
||||
* The returned value is zero for success or a negative errno
|
||||
* value for failure.
|
||||
*/
|
||||
int (*readlink)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
char **pbuf);
|
||||
|
||||
/*
|
||||
* Truncate a file (shorten or append zeroes)
|
||||
* The returned value is zero for success or a negative errno
|
||||
* value for failure.
|
||||
* If the returned value is zero, the modified time stamp
|
||||
* will be updated after the call.
|
||||
*/
|
||||
int (*truncate)(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
off_t size);
|
||||
} plugin_operations_t;
|
||||
|
||||
|
||||
/*
|
||||
* Plugin initialization routine
|
||||
* Returns the entry table if successful, otherwise returns NULL
|
||||
* and sets errno (e.g. to EINVAL if the tag is not supported by
|
||||
* the plugin.)
|
||||
*/
|
||||
typedef const struct plugin_operations *(*plugin_init_t)(le32 tag);
|
||||
const struct plugin_operations *init(le32 tag);
|
||||
|
||||
#endif /* _NTFS_PLUGIN_H */
|
|
@ -24,12 +24,14 @@
|
|||
#ifndef REPARSE_H
|
||||
#define REPARSE_H
|
||||
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
int *pattr_size);
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point);
|
||||
|
||||
BOOL ntfs_possible_symlink(ntfs_inode *ni);
|
||||
|
||||
int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size);
|
||||
|
||||
REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni);
|
||||
|
||||
int ntfs_set_ntfs_reparse_data(ntfs_inode *ni, const char *value,
|
||||
size_t size, int flags);
|
||||
int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni);
|
||||
|
|
|
@ -173,7 +173,7 @@ struct POSIX_SECURITY {
|
|||
int defcnt;
|
||||
int firstdef;
|
||||
u16 tagsset;
|
||||
s32 alignment[0];
|
||||
u16 filler;
|
||||
struct POSIX_ACL acl;
|
||||
} ;
|
||||
|
||||
|
@ -256,7 +256,9 @@ int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
|
|||
le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *dir_ni, BOOL fordir);
|
||||
int ntfs_open_secure(ntfs_volume *vol);
|
||||
void ntfs_close_secure(struct SECURITY_CONTEXT *scx);
|
||||
int ntfs_close_secure(ntfs_volume *vol);
|
||||
|
||||
void ntfs_destroy_security_context(struct SECURITY_CONTEXT *scx);
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
|
|
|
@ -68,9 +68,9 @@ extern ntfschar *ntfs_str2ucs(const char *s, int *len);
|
|||
|
||||
extern void ntfs_ucsfree(ntfschar *ucs);
|
||||
|
||||
extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len);
|
||||
extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len, BOOL strict);
|
||||
extern BOOL ntfs_forbidden_names(ntfs_volume *vol,
|
||||
const ntfschar *name, int len);
|
||||
const ntfschar *name, int len, BOOL strict);
|
||||
extern BOOL ntfs_collapsible_chars(ntfs_volume *vol,
|
||||
const ntfschar *shortname, int shortlen,
|
||||
const ntfschar *longname, int longlen);
|
||||
|
|
|
@ -60,6 +60,7 @@ typedef struct _ntfs_volume ntfs_volume;
|
|||
enum {
|
||||
NTFS_MNT_NONE = 0x00000000,
|
||||
NTFS_MNT_RDONLY = 0x00000001,
|
||||
NTFS_MNT_MAY_RDONLY = 0x02000000, /* Allow fallback to ro */
|
||||
NTFS_MNT_FORENSIC = 0x04000000, /* No modification during
|
||||
* mount. */
|
||||
NTFS_MNT_EXCLUSIVE = 0x08000000,
|
||||
|
|
|
@ -19,8 +19,27 @@
|
|||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _NTFS_XATTR_H_
|
||||
#define _NTFS_XATTR_H_
|
||||
#ifndef _NTFS_XATTRS_H_
|
||||
#define _NTFS_XATTRS_H_
|
||||
|
||||
/*
|
||||
* Flags that modify setxattr() semantics. These flags are also used by a
|
||||
* number of libntfs-3g functions, such as ntfs_set_ntfs_acl(), which were
|
||||
* originally tied to extended attributes support but now can be used by
|
||||
* applications even if the platform does not support extended attributes.
|
||||
*
|
||||
* Careful: applications including this header should define HAVE_SETXATTR or
|
||||
* HAVE_SYS_XATTR_H if the platform supports extended attributes. Otherwise the
|
||||
* defined flags values may be incorrect (they will be correct for Linux but not
|
||||
* necessarily for other platforms).
|
||||
*/
|
||||
#if defined(HAVE_SETXATTR) || defined(HAVE_SYS_XATTR_H)
|
||||
#include <sys/xattr.h>
|
||||
#else
|
||||
#include "compat.h" /* may be needed for ENODATA definition */
|
||||
#define XATTR_CREATE 1
|
||||
#define XATTR_REPLACE 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Identification of data mapped to the system name space
|
||||
|
@ -61,6 +80,8 @@ void ntfs_xattr_free_mapping(struct XATTRMAPPING*);
|
|||
enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name,
|
||||
ntfs_volume *vol);
|
||||
|
||||
struct SECURITY_CONTEXT;
|
||||
|
||||
int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
|
||||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||
|
@ -73,4 +94,4 @@ int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
|
|||
enum SYSTEMXATTRS attr,
|
||||
ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||
|
||||
#endif /* _NTFS_XATTR_H_ */
|
||||
#endif /* _NTFS_XATTRS_H_ */
|
||||
|
|
|
@ -1281,8 +1281,15 @@ static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
|
|||
{
|
||||
if (!err) {
|
||||
struct fuse *f = req_fuse(req);
|
||||
#ifdef __SOLARIS__
|
||||
/* Skip forget for negative result */
|
||||
if ((fuse_reply_entry(req, e) == -ENOENT)
|
||||
&& (e->ino != 0))
|
||||
forget_node(f, e->ino, 1);
|
||||
#else /* __SOLARIS__ */
|
||||
if (fuse_reply_entry(req, e) == -ENOENT)
|
||||
forget_node(f, e->ino, 1);
|
||||
#endif
|
||||
} else
|
||||
reply_err(req, err);
|
||||
}
|
||||
|
@ -2081,9 +2088,7 @@ static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
|
|||
}
|
||||
} else {
|
||||
reply_err(req, err);
|
||||
#ifndef __SOLARIS__
|
||||
pthread_mutex_destroy(&dh->lock);
|
||||
#endif /* ! __SOLARIS__ */
|
||||
free(dh);
|
||||
}
|
||||
free(path);
|
||||
|
@ -2901,7 +2906,7 @@ static void fuse_lib_help(void)
|
|||
" -o direct_io use direct I/O\n"
|
||||
" -o kernel_cache cache files in kernel\n"
|
||||
#ifdef __SOLARIS__
|
||||
" -o [no]auto_cache enable caching based on modification times\n"
|
||||
" -o [no]auto_cache enable caching based on modification times (off)\n"
|
||||
#endif /* __SOLARIS__ */
|
||||
" -o umask=M set file permissions (octal)\n"
|
||||
" -o uid=N set file owner\n"
|
||||
|
|
|
@ -22,6 +22,16 @@
|
|||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#define PARAM(inarg) (((const char *)(inarg)) + sizeof(*(inarg)))
|
||||
#define OFFSET_MAX 0x7fffffffffffffffLL
|
||||
|
||||
|
@ -561,10 +571,13 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
|
||||
if (req->f->op.mknod) {
|
||||
#if defined(__SOLARIS__) && defined(_LP64)
|
||||
/* Must unpack the device, as arg->rdev is limited to 32 bits */
|
||||
/*
|
||||
* Must unpack the device, as arg->rdev is limited to 32 bits,
|
||||
* and must have the same format in 32-bit and 64-bit builds.
|
||||
*/
|
||||
req->f->op.mknod(req, nodeid, name, arg->mode,
|
||||
makedev((arg->rdev >> 18) & 0x3ffff,
|
||||
arg->rdev & 0x3fff));
|
||||
makedev((arg->rdev >> 18) & 0x3fff,
|
||||
arg->rdev & 0x3ffff));
|
||||
#else
|
||||
req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
|
||||
#endif
|
||||
|
@ -1090,6 +1103,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
#ifdef POSIXACLS
|
||||
if (arg->flags & FUSE_DONT_MASK)
|
||||
f->conn.capable |= FUSE_CAP_DONT_MASK;
|
||||
if (arg->flags & FUSE_POSIX_ACL)
|
||||
f->conn.capable |= FUSE_CAP_POSIX_ACL;
|
||||
#endif
|
||||
if (arg->flags & FUSE_BIG_WRITES)
|
||||
f->conn.capable |= FUSE_CAP_BIG_WRITES;
|
||||
|
@ -1130,6 +1145,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
#ifdef POSIXACLS
|
||||
if (f->conn.want & FUSE_CAP_DONT_MASK)
|
||||
outarg.flags |= FUSE_DONT_MASK;
|
||||
if (f->conn.want & FUSE_CAP_POSIX_ACL)
|
||||
outarg.flags |= FUSE_POSIX_ACL;
|
||||
#endif
|
||||
} else {
|
||||
/* Never use a version more recent than supported by the kernel */
|
||||
|
@ -1144,6 +1161,8 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
#ifdef POSIXACLS
|
||||
if (f->conn.want & FUSE_CAP_DONT_MASK)
|
||||
outarg.flags |= FUSE_DONT_MASK;
|
||||
if (f->conn.want & FUSE_CAP_POSIX_ACL)
|
||||
outarg.flags |= FUSE_POSIX_ACL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#include <paths.h>
|
||||
|
||||
#ifdef __SOLARIS__
|
||||
#include <sys/mnttab.h>
|
||||
|
|
|
@ -350,7 +350,7 @@ static int receive_fd(int fd)
|
|||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (!cmsg->cmsg_type == SCM_RIGHTS) {
|
||||
if (cmsg->cmsg_type != SCM_RIGHTS) {
|
||||
fprintf(stderr, "got control message of unknown type %d\n",
|
||||
cmsg->cmsg_type);
|
||||
return -1;
|
||||
|
@ -380,10 +380,13 @@ void fuse_kern_unmount(const char *mountpoint, int fd)
|
|||
then the filesystem is already unmounted */
|
||||
if (res == 1 && (pfd.revents & POLLERR))
|
||||
return;
|
||||
/*
|
||||
* Need to close file descriptor, otherwise synchronous umount
|
||||
* would recurse into filesystem, and deadlock.
|
||||
*/
|
||||
close(fd);
|
||||
}
|
||||
#ifndef __SOLARIS__
|
||||
close(fd);
|
||||
|
||||
fusermount(1, 0, 1, "", mountpoint);
|
||||
#else /* __SOLARIS__ */
|
||||
if (geteuid() == 0) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef __SOLARIS__
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* This module is part of ntfs-3g library, but may also be
|
||||
* integrated in tools running over Linux or Windows
|
||||
*
|
||||
* Copyright (c) 2007-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2016 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
|
||||
|
@ -22,10 +22,6 @@
|
|||
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
/*
|
||||
* integration into ntfs-3g
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
|
@ -58,55 +54,6 @@
|
|||
#include "security.h"
|
||||
#include "acls.h"
|
||||
#include "misc.h"
|
||||
#else
|
||||
|
||||
/*
|
||||
* integration into secaudit, check whether Win32,
|
||||
* may have to be adapted to compiler or something else
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
#if defined(__WIN32) | defined(__WIN32__) | defined(WNSC)
|
||||
#define WIN32 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* integration into secaudit/Win32
|
||||
*/
|
||||
#ifdef WIN32
|
||||
#include <fcntl.h>
|
||||
#include <windows.h>
|
||||
#define __LITTLE_ENDIAN 1234
|
||||
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||
#else
|
||||
/*
|
||||
* integration into secaudit/STSC
|
||||
*/
|
||||
#ifdef STSC
|
||||
#include <stat.h>
|
||||
#undef __BYTE_ORDER
|
||||
#define __BYTE_ORDER __BIG_ENDIAN
|
||||
#else
|
||||
/*
|
||||
* integration into secaudit/Linux
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#include <endian.h>
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#endif /* STSC */
|
||||
#endif /* WIN32 */
|
||||
#include "secaudit.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
/*
|
||||
* A few useful constants
|
||||
|
@ -599,6 +546,7 @@ static BOOL valid_acl(const ACL *pacl, unsigned int end)
|
|||
unsigned int acecnt;
|
||||
unsigned int acesz;
|
||||
unsigned int nace;
|
||||
unsigned int wantsz;
|
||||
BOOL ok;
|
||||
|
||||
ok = TRUE;
|
||||
|
@ -613,9 +561,16 @@ static BOOL valid_acl(const ACL *pacl, unsigned int end)
|
|||
&((const char*)pacl)[offace];
|
||||
acesz = le16_to_cpu(pace->size);
|
||||
if (((offace + acesz) > end)
|
||||
|| !ntfs_valid_sid(&pace->sid)
|
||||
|| ((ntfs_sid_size(&pace->sid) + 8) != (int)acesz))
|
||||
|| !ntfs_valid_sid(&pace->sid))
|
||||
ok = FALSE;
|
||||
else {
|
||||
/* Win10 may insert garbage in the last ACE */
|
||||
wantsz = ntfs_sid_size(&pace->sid) + 8;
|
||||
if (((nace < (acecnt - 1))
|
||||
&& (wantsz != acesz))
|
||||
|| (wantsz > acesz))
|
||||
ok = FALSE;
|
||||
}
|
||||
offace += acesz;
|
||||
}
|
||||
}
|
||||
|
@ -1638,7 +1593,7 @@ static BOOL build_user_denials(ACL *pacl,
|
|||
grants = OWNER_RIGHTS;
|
||||
} else {
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_USID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_usid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
grants = WORLD_RIGHTS;
|
||||
} else {
|
||||
|
@ -1794,7 +1749,7 @@ static BOOL build_user_grants(ACL *pacl,
|
|||
grants = OWNER_RIGHTS;
|
||||
} else {
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_USID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_usid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
if (sid)
|
||||
sidsz = ntfs_sid_size(sid);
|
||||
|
@ -1880,7 +1835,7 @@ static BOOL build_group_denials_grant(ACL *pacl,
|
|||
sid = gsid;
|
||||
else
|
||||
if (pxace->id)
|
||||
sid = NTFS_FIND_GSID(mapping[MAPGROUPS],
|
||||
sid = ntfs_find_gsid(mapping[MAPGROUPS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
else {
|
||||
sid = adminsid;
|
||||
|
@ -2185,7 +2140,7 @@ static int buildacls_posix(struct MAPPING* const mapping[],
|
|||
case POSIX_ACL_USER :
|
||||
pset->designates++;
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_USID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_usid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
if (sid && ntfs_same_sid(sid,usid))
|
||||
pset->selfuserperms |= pxace->perms;
|
||||
|
@ -2196,7 +2151,7 @@ static int buildacls_posix(struct MAPPING* const mapping[],
|
|||
case POSIX_ACL_GROUP :
|
||||
pset->designates++;
|
||||
if (pxace->id) {
|
||||
sid = NTFS_FIND_GSID(mapping[MAPUSERS],
|
||||
sid = ntfs_find_gsid(mapping[MAPUSERS],
|
||||
pxace->id, (SID*)&defsid);
|
||||
if (sid && ntfs_same_sid(sid,gsid))
|
||||
pset->selfgrpperms |= pxace->perms;
|
||||
|
@ -2790,10 +2745,10 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
|||
for (k=0; k<pxdesc->acccnt; k++) {
|
||||
if ((pxdesc->acl.ace[k].tag == POSIX_ACL_USER)
|
||||
|| (pxdesc->acl.ace[k].tag == POSIX_ACL_GROUP))
|
||||
newattrsz += 3*40; /* fixme : maximum size */
|
||||
newattrsz += 3*MAX_SID_SIZE;
|
||||
}
|
||||
/* account for default ACE's */
|
||||
newattrsz += 2*40*pxdesc->defcnt; /* fixme : maximum size */
|
||||
newattrsz += 2*MAX_SID_SIZE*pxdesc->defcnt;
|
||||
newattr = (char*)ntfs_malloc(newattrsz);
|
||||
if (newattr) {
|
||||
/* build the main header part */
|
||||
|
@ -3647,7 +3602,7 @@ static uid_t find_tenant(struct MAPPING *const mapping[],
|
|||
pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace];
|
||||
if ((pace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
&& (pace->mask & DIR_WRITE)) {
|
||||
xid = NTFS_FIND_USER(mapping[MAPUSERS], &pace->sid);
|
||||
xid = ntfs_find_user(mapping[MAPUSERS], &pace->sid);
|
||||
if (xid) tid = xid;
|
||||
}
|
||||
offace += le16_to_cpu(pace->size);
|
||||
|
@ -3782,13 +3737,13 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
|||
} else {
|
||||
if (ntfs_same_sid(&pace->sid,usid))
|
||||
groupowns = TRUE;
|
||||
gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid);
|
||||
gid = ntfs_find_group(mapping[MAPGROUPS],&pace->sid);
|
||||
if (gid) {
|
||||
pxace->tag = POSIX_ACL_GROUP;
|
||||
pxace->id = gid;
|
||||
pctx->prevgid = gid;
|
||||
} else {
|
||||
uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid);
|
||||
uid = ntfs_find_user(mapping[MAPUSERS],&pace->sid);
|
||||
if (uid) {
|
||||
pxace->tag = POSIX_ACL_USER;
|
||||
pxace->id = uid;
|
||||
|
@ -3811,7 +3766,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
|||
if (pace->type == ACCESS_ALLOWED_ACE_TYPE)
|
||||
pctx->gotowner = TRUE;
|
||||
if (pctx->gotownermask && !pctx->gotowner) {
|
||||
uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid);
|
||||
uid = ntfs_find_user(mapping[MAPUSERS],&pace->sid);
|
||||
pxace->id = uid;
|
||||
pxace->tag = POSIX_ACL_USER;
|
||||
} else
|
||||
|
@ -3843,7 +3798,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
|||
pctx->groupmasks++;
|
||||
} else {
|
||||
if (pctx->gotgroup || (pctx->groupmasks > 1)) {
|
||||
gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid);
|
||||
gid = ntfs_find_group(mapping[MAPGROUPS],&pace->sid);
|
||||
if (gid) {
|
||||
pxace->id = gid;
|
||||
pxace->tag = POSIX_ACL_GROUP;
|
||||
|
@ -3877,7 +3832,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
|||
pxace->id = -1;
|
||||
pxace->tag = POSIX_ACL_SPECIAL;
|
||||
} else {
|
||||
uid = NTFS_FIND_USER(mapping[MAPUSERS],&pace->sid);
|
||||
uid = ntfs_find_user(mapping[MAPUSERS],&pace->sid);
|
||||
if (uid) {
|
||||
if ((pace->type == ACCESS_DENIED_ACE_TYPE)
|
||||
&& (pace->mask & WRITE_OWNER)
|
||||
|
@ -3890,7 +3845,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
|||
}
|
||||
pctx->prevuid = uid;
|
||||
} else {
|
||||
gid = NTFS_FIND_GROUP(mapping[MAPGROUPS],&pace->sid);
|
||||
gid = ntfs_find_group(mapping[MAPGROUPS],&pace->sid);
|
||||
if (gid) {
|
||||
if ((pace->type == ACCESS_DENIED_ACE_TYPE)
|
||||
&& (pace->mask & WRITE_OWNER)
|
||||
|
|
|
@ -2215,7 +2215,7 @@ retry:
|
|||
} else
|
||||
written = ntfs_pwrite(vol->dev, wpos,
|
||||
to_write, b);
|
||||
}
|
||||
}
|
||||
} else
|
||||
written = to_write;
|
||||
/* If everything ok, update progress counters and continue. */
|
||||
|
@ -5142,6 +5142,10 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
|
|||
*/
|
||||
if (le32_eq(na->type, AT_STANDARD_INFORMATION) || le32_eq(na->type, AT_ATTRIBUTE_LIST)) {
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if (!NInoAttrList(na->ni) && ntfs_inode_add_attrlist(na->ni)) {
|
||||
ntfs_log_perror("Could not add attribute list");
|
||||
return -1;
|
||||
}
|
||||
if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD,
|
||||
non_resident_end) + 8)) {
|
||||
ntfs_log_perror("Could not free space in MFT record");
|
||||
|
|
|
@ -40,7 +40,13 @@
|
|||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
|
@ -61,10 +67,7 @@
|
|||
#include "security.h"
|
||||
#include "reparse.h"
|
||||
#include "object_id.h"
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* The little endian Unicode strings "$I30", "$SII", "$SDH", "$O"
|
||||
|
@ -875,7 +878,7 @@ typedef enum {
|
|||
* and most metadata files have such similar patters.
|
||||
*/
|
||||
|
||||
static u32 ntfs_interix_types(ntfs_inode *ni)
|
||||
u32 ntfs_interix_types(ntfs_inode *ni)
|
||||
{
|
||||
ntfs_attr *na;
|
||||
u32 dt_type;
|
||||
|
@ -884,8 +887,14 @@ static u32 ntfs_interix_types(ntfs_inode *ni)
|
|||
dt_type = NTFS_DT_UNKNOWN;
|
||||
na = ntfs_attr_open(ni, AT_DATA, NULL, 0);
|
||||
if (na) {
|
||||
/* Unrecognized patterns (eg HID + SYST) are plain files */
|
||||
dt_type = NTFS_DT_REG;
|
||||
/*
|
||||
* Unrecognized patterns (eg HID + SYST for metadata)
|
||||
* are plain files or directories
|
||||
*/
|
||||
if (!le16_andz(ni->mrec->flags, MFT_RECORD_IS_DIRECTORY))
|
||||
dt_type = NTFS_DT_DIR;
|
||||
else
|
||||
dt_type = NTFS_DT_REG;
|
||||
if (na->data_size <= 1) {
|
||||
if (le32_andz(ni->flags, FILE_ATTR_HIDDEN))
|
||||
dt_type = (na->data_size ?
|
||||
|
@ -1892,20 +1901,23 @@ int ntfs_delete(ntfs_volume *vol, const char *pathname,
|
|||
if (!actx)
|
||||
goto err_out;
|
||||
search:
|
||||
while (!ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, CASE_SENSITIVE,
|
||||
0, NULL, 0, actx)) {
|
||||
while (!(err = ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0,
|
||||
CASE_SENSITIVE, 0, NULL, 0, actx))) {
|
||||
#ifdef DEBUG
|
||||
char *s;
|
||||
#endif
|
||||
IGNORE_CASE_BOOL case_sensitive = IGNORE_CASE;
|
||||
|
||||
errno = 0;
|
||||
fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
|
||||
le16_to_cpu(actx->attr->value_offset));
|
||||
#ifdef DEBUG
|
||||
s = ntfs_attr_name_get(fn->file_name, fn->file_name_length);
|
||||
ntfs_log_trace("name: '%s' type: %d dos: %d win32: %d "
|
||||
"case: %d\n", s, fn->file_name_type,
|
||||
looking_for_dos_name, looking_for_win32_name,
|
||||
case_sensitive_match);
|
||||
ntfs_attr_name_free(&s);
|
||||
#endif
|
||||
if (looking_for_dos_name) {
|
||||
if (fn->file_name_type == FILE_NAME_DOS)
|
||||
break;
|
||||
|
@ -1946,7 +1958,7 @@ search:
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (errno) {
|
||||
if (err) {
|
||||
/*
|
||||
* If case sensitive search failed, then try once again
|
||||
* ignoring case.
|
||||
|
@ -2268,8 +2280,6 @@ ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni)
|
|||
return (dir_ni);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
|
||||
#define MAX_DOS_NAME_LENGTH 12
|
||||
|
||||
/*
|
||||
|
@ -2418,11 +2428,11 @@ int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
|||
*/
|
||||
ntfs_name_upcase(dosname, doslen,
|
||||
ni->vol->upcase, ni->vol->upcase_len);
|
||||
if (ntfs_ucstombs(dosname, doslen, &outname, size) < 0) {
|
||||
outsize = ntfs_ucstombs(dosname, doslen, &outname, 0);
|
||||
if (outsize < 0) {
|
||||
ntfs_log_error("Cannot represent dosname in current locale.\n");
|
||||
outsize = -errno;
|
||||
} else {
|
||||
outsize = strlen(outname);
|
||||
if (value && (outsize <= (int)size))
|
||||
memcpy(value, outname, outsize);
|
||||
else
|
||||
|
@ -2644,9 +2654,12 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
|||
shortlen = ntfs_mbstoucs(newname, &shortname);
|
||||
if (shortlen > MAX_DOS_NAME_LENGTH)
|
||||
shortlen = MAX_DOS_NAME_LENGTH;
|
||||
/* make sure the short name has valid chars */
|
||||
|
||||
/* Make sure the short name has valid chars.
|
||||
* Note: the short name cannot end with dot or space, but the
|
||||
* corresponding long name can. */
|
||||
if ((shortlen < 0)
|
||||
|| ntfs_forbidden_names(ni->vol,shortname,shortlen)) {
|
||||
|| ntfs_forbidden_names(ni->vol,shortname,shortlen,TRUE)) {
|
||||
ntfs_inode_close_in_dir(ni,dir_ni);
|
||||
ntfs_inode_close(dir_ni);
|
||||
res = -errno;
|
||||
|
@ -2657,7 +2670,8 @@ int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
|||
if (longlen > 0) {
|
||||
oldlen = get_dos_name(ni, dnum, oldname);
|
||||
if ((oldlen >= 0)
|
||||
&& !ntfs_forbidden_names(ni->vol, longname, longlen)) {
|
||||
&& !ntfs_forbidden_names(ni->vol, longname, longlen,
|
||||
FALSE)) {
|
||||
if (oldlen > 0) {
|
||||
if (flags & XATTR_CREATE) {
|
||||
res = -1;
|
||||
|
@ -2778,5 +2792,3 @@ int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes support required */
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
@ -46,10 +44,6 @@
|
|||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#include "types.h"
|
||||
#include "param.h"
|
||||
#include "layout.h"
|
||||
|
@ -59,6 +53,7 @@
|
|||
#include "ea.h"
|
||||
#include "misc.h"
|
||||
#include "logging.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* Create a needed attribute (EA or EA_INFORMATION)
|
||||
|
@ -398,5 +393,3 @@ int ntfs_remove_ntfs_ea(ntfs_inode *ni)
|
|||
}
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
|
|
@ -39,10 +39,6 @@
|
|||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
@ -57,8 +53,7 @@
|
|||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "efs.h"
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#include "xattrs.h"
|
||||
|
||||
static ntfschar logged_utility_stream_name[] = {
|
||||
const_cpu_to_le16('$'),
|
||||
|
@ -433,5 +428,3 @@ err_out:
|
|||
ntfs_attr_put_search_ctx(ctx);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
|
|
@ -143,7 +143,7 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
|
|||
{
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
if (!icx->entry)
|
||||
if (!icx->bad_index && !icx->entry)
|
||||
return;
|
||||
|
||||
if (icx->actx)
|
||||
|
@ -719,7 +719,7 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
|
|||
ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
|
||||
if (ret == STATUS_ERROR) {
|
||||
err = errno;
|
||||
goto err_out;
|
||||
goto err_lookup;
|
||||
}
|
||||
|
||||
icx->ir = ir;
|
||||
|
@ -780,6 +780,8 @@ descend_into_child_node:
|
|||
|
||||
goto descend_into_child_node;
|
||||
err_out:
|
||||
icx->bad_index = TRUE; /* Force icx->* to be freed */
|
||||
err_lookup:
|
||||
free(ib);
|
||||
if (!err)
|
||||
err = EIO;
|
||||
|
|
|
@ -36,9 +36,6 @@
|
|||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#include "param.h"
|
||||
#include "compat.h"
|
||||
|
@ -57,6 +54,7 @@
|
|||
#include "ntfstime.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
ntfs_inode *ntfs_inode_base(ntfs_inode *ni)
|
||||
{
|
||||
|
@ -1446,8 +1444,6 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get high precision NTFS times
|
||||
*
|
||||
|
@ -1604,5 +1600,3 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
|
|||
errno = EEXIST;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
|
|
@ -49,14 +49,15 @@
|
|||
#include <limits.h>
|
||||
#endif
|
||||
#include <syslog.h>
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
|
|
|
@ -119,7 +119,7 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
|
|||
/* Verify the position of the update sequence array. */
|
||||
usa_ofs = le16_to_cpu(rp->usa_ofs);
|
||||
usa_end = usa_ofs + usa_count * sizeof(u16);
|
||||
if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
|
||||
if (usa_ofs < offsetof(RESTART_PAGE_HEADER, usn) ||
|
||||
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent update sequence array offset.\n");
|
||||
|
@ -134,7 +134,7 @@ skip_usa_checks:
|
|||
*/
|
||||
ra_ofs = le16_to_cpu(rp->restart_area_offset);
|
||||
if (ra_ofs & 7 || (have_usa ? ra_ofs < usa_end :
|
||||
ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
|
||||
ra_ofs < offsetof(RESTART_PAGE_HEADER, usn)) ||
|
||||
ra_ofs > logfile_system_page_size) {
|
||||
ntfs_log_error("$LogFile restart page specifies "
|
||||
"inconsistent restart area offset.\n");
|
||||
|
|
|
@ -1629,6 +1629,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
|
|||
int err;
|
||||
u32 usa_ofs;
|
||||
le16 seq_no, usn;
|
||||
BOOL oldwarn;
|
||||
|
||||
if (base_ni)
|
||||
ntfs_log_enter("Entering (allocating an extent mft record for "
|
||||
|
@ -1742,10 +1743,22 @@ found_free_rec:
|
|||
if (!m)
|
||||
goto undo_mftbmp_alloc;
|
||||
|
||||
/*
|
||||
* As this is allocating a new record, do not expect it to have
|
||||
* been initialized previously, so do not warn over bad fixups
|
||||
* (hence avoid warn flooding when an NTFS partition has been wiped).
|
||||
*/
|
||||
oldwarn = !NVolNoFixupWarn(vol);
|
||||
NVolSetNoFixupWarn(vol);
|
||||
if (ntfs_mft_record_read(vol, bit, m)) {
|
||||
if (oldwarn)
|
||||
NVolClearNoFixupWarn(vol);
|
||||
free(m);
|
||||
goto undo_mftbmp_alloc;
|
||||
}
|
||||
if (oldwarn)
|
||||
NVolClearNoFixupWarn(vol);
|
||||
|
||||
/* Sanity check that the mft record is really not in use. */
|
||||
if (ntfs_is_file_record(m->magic) && !le16_andz(m->flags, MFT_RECORD_IN_USE)) {
|
||||
ntfs_log_error("Inode %lld is used but it wasn't marked in "
|
||||
|
|
|
@ -31,6 +31,21 @@
|
|||
#include "mst.h"
|
||||
#include "logging.h"
|
||||
|
||||
/*
|
||||
* Basic validation of a NTFS multi-sector record. The record size must be a
|
||||
* multiple of the logical sector size; and the update sequence array must be
|
||||
* properly aligned, of the expected length, and must end before the last le16
|
||||
* in the first logical sector.
|
||||
*/
|
||||
static BOOL
|
||||
is_valid_record(u32 size, u16 usa_ofs, u16 usa_count)
|
||||
{
|
||||
return size % NTFS_BLOCK_SIZE == 0 &&
|
||||
usa_ofs % 2 == 0 &&
|
||||
usa_count == 1 + (size / NTFS_BLOCK_SIZE) &&
|
||||
usa_ofs + ((u32)usa_count * 2) <= NTFS_BLOCK_SIZE - 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data
|
||||
* @b: pointer to the data to deprotect
|
||||
|
@ -57,12 +72,9 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
|||
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
usa_count = le16_to_cpu(b->usa_count);
|
||||
|
||||
if (!is_valid_record(size, usa_ofs, usa_count)) {
|
||||
errno = EINVAL;
|
||||
if (warn) {
|
||||
ntfs_log_perror("%s: magic: 0x%08lx size: %ld "
|
||||
|
@ -91,7 +103,7 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
|||
/*
|
||||
* Check for incomplete multi sector transfer(s).
|
||||
*/
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
if (*data_pos != usn) {
|
||||
/*
|
||||
* Incomplete multi sector transfer detected! )-:
|
||||
|
@ -109,10 +121,10 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
|||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||
}
|
||||
/* Re-setup the variables. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
usa_count = le16_to_cpu(b->usa_count);
|
||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
|
@ -171,12 +183,9 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
|||
}
|
||||
/* Setup the variables. */
|
||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
/* Decrement usa_count to get number of fixups. */
|
||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
/* Size and alignment checks. */
|
||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
||||
usa_count = le16_to_cpu(b->usa_count);
|
||||
|
||||
if (!is_valid_record(size, usa_ofs, usa_count)) {
|
||||
errno = EINVAL;
|
||||
ntfs_log_perror("%s", __FUNCTION__);
|
||||
return -1;
|
||||
|
@ -195,7 +204,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
|||
/* Position in data of first le16 that needs fixing up. */
|
||||
data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1;
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
/*
|
||||
* Increment the position in the usa and save the
|
||||
* original data from the data buffer into the usa.
|
||||
|
@ -223,7 +232,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
|||
u16 *usa_pos, *data_pos;
|
||||
|
||||
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
|
||||
u16 usa_count = le16_to_cpu(b->usa_count);
|
||||
|
||||
ntfs_log_trace("Entering\n");
|
||||
|
||||
|
@ -234,7 +243,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
|||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||
|
||||
/* Fixup all sectors. */
|
||||
while (usa_count--) {
|
||||
while (--usa_count) {
|
||||
/*
|
||||
* Increment position in usa and restore original data from
|
||||
* the usa into the data buffer.
|
||||
|
|
|
@ -37,11 +37,6 @@
|
|||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
@ -59,6 +54,7 @@
|
|||
#include "object_id.h"
|
||||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* Endianness considerations
|
||||
|
@ -130,7 +126,6 @@ struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */
|
|||
|
||||
static ntfschar objid_index_name[] = { const_cpu_to_le16('$'),
|
||||
const_cpu_to_le16('O') };
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Set the index for a new object id
|
||||
|
@ -176,8 +171,6 @@ static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo,
|
|||
return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx));
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Open the $Extend/$ObjId file and its index
|
||||
*
|
||||
|
@ -213,7 +206,6 @@ static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
|
|||
return (xo);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Merge object_id data stored in the index into
|
||||
|
@ -263,7 +255,6 @@ static int merge_index_data(ntfs_inode *ni,
|
|||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Remove an object id index entry if attribute present
|
||||
|
@ -311,7 +302,6 @@ static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
|
|||
return (ret);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Update the object id and index
|
||||
|
@ -417,7 +407,6 @@ static int add_object_id(ntfs_inode *ni, int flags)
|
|||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Delete an object_id index entry
|
||||
|
@ -456,7 +445,6 @@ int ntfs_delete_object_id_index(ntfs_inode *ni)
|
|||
return (res);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs object id into an extended attribute
|
||||
|
@ -636,5 +624,3 @@ int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
|
|||
}
|
||||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* This module is part of ntfs-3g library
|
||||
*
|
||||
* Copyright (c) 2008-2014 Jean-Pierre Andre
|
||||
* Copyright (c) 2008-2016 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
|
||||
|
@ -37,11 +37,6 @@
|
|||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
@ -60,6 +55,7 @@
|
|||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
#include "reparse.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
struct MOUNT_POINT_REPARSE_DATA { /* reparse data for junctions */
|
||||
le16 subst_name_offset;
|
||||
|
@ -448,8 +444,13 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
|
|||
+ (!le32_andz(reparse_attr->reparse_tag,
|
||||
IO_REPARSE_TAG_IS_MICROSOFT) ? 0 : sizeof(GUID))) == size);
|
||||
if (ok) {
|
||||
/* switch (reparse_attr->reparse_tag) { */
|
||||
do {
|
||||
if (le32_eq(reparse_attr->reparse_tag, IO_REPARSE_TAG_MOUNT_POINT)) {
|
||||
if (size < sizeof(REPARSE_POINT) +
|
||||
sizeof(struct MOUNT_POINT_REPARSE_DATA)) {
|
||||
ok = FALSE;
|
||||
break;
|
||||
}
|
||||
mount_point_data = (const struct MOUNT_POINT_REPARSE_DATA*)
|
||||
reparse_attr->reparse_data;
|
||||
offs = le16_to_cpu(mount_point_data->subst_name_offset);
|
||||
|
@ -460,8 +461,13 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
|
|||
+ sizeof(struct MOUNT_POINT_REPARSE_DATA)
|
||||
+ offs + lth)) > size))
|
||||
ok = FALSE;
|
||||
}
|
||||
else if (le32_eq(reparse_attr->reparse_tag, IO_REPARSE_TAG_SYMLINK)) {
|
||||
break;
|
||||
} else if (le32_eq(reparse_attr->reparse_tag, IO_REPARSE_TAG_SYMLINK)) {
|
||||
if (size < sizeof(REPARSE_POINT) +
|
||||
sizeof(struct SYMLINK_REPARSE_DATA)) {
|
||||
ok = FALSE;
|
||||
break;
|
||||
}
|
||||
symlink_data = (const struct SYMLINK_REPARSE_DATA*)
|
||||
reparse_attr->reparse_data;
|
||||
offs = le16_to_cpu(symlink_data->subst_name_offset);
|
||||
|
@ -470,10 +476,10 @@ static BOOL valid_reparse_data(ntfs_inode *ni,
|
|||
+ sizeof(struct SYMLINK_REPARSE_DATA)
|
||||
+ offs + lth)) > size)
|
||||
ok = FALSE;
|
||||
}
|
||||
else {
|
||||
/* break; */
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
} } while(0);
|
||||
}
|
||||
if (!ok)
|
||||
errno = EINVAL;
|
||||
|
@ -718,8 +724,7 @@ static char *ntfs_get_rellink(ntfs_inode *ni, ntfschar *junction, int count)
|
|||
* symbolic link or directory junction
|
||||
*/
|
||||
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
||||
int *pattr_size)
|
||||
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point)
|
||||
{
|
||||
s64 attr_size = 0;
|
||||
char *target;
|
||||
|
@ -814,7 +819,6 @@ char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point,
|
|||
}
|
||||
free(reparse_attr);
|
||||
}
|
||||
*pattr_size = attr_size;
|
||||
if (bad)
|
||||
errno = EOPNOTSUPP;
|
||||
return (target);
|
||||
|
@ -849,7 +853,6 @@ BOOL ntfs_possible_symlink(ntfs_inode *ni)
|
|||
return (possible);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Set the index for new reparse data
|
||||
|
@ -888,7 +891,6 @@ static int set_reparse_index(ntfs_inode *ni, ntfs_index_context *xr,
|
|||
return (ntfs_ie_add(xr,(INDEX_ENTRY*)&indx));
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Remove a reparse data index entry if attribute present
|
||||
|
@ -965,7 +967,6 @@ static ntfs_index_context *open_reparse_index(ntfs_volume *vol)
|
|||
return (xr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Update the reparse data and index
|
||||
|
@ -1031,7 +1032,6 @@ static int update_reparse_data(ntfs_inode *ni, ntfs_index_context *xr,
|
|||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Delete a reparse index entry
|
||||
|
@ -1070,7 +1070,6 @@ int ntfs_delete_reparse_index(ntfs_inode *ni)
|
|||
return (res);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs reparse data into an extended attribute
|
||||
|
@ -1255,4 +1254,31 @@ int ntfs_remove_ntfs_reparse_data(ntfs_inode *ni)
|
|||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Get the reparse data into a buffer
|
||||
*
|
||||
* Returns the buffer if the reparse data exists and is valid
|
||||
* NULL otherwise (with errno set according to the cause).
|
||||
* When a buffer is returned, it has to be freed by caller.
|
||||
*/
|
||||
|
||||
REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni)
|
||||
{
|
||||
s64 attr_size = 0;
|
||||
REPARSE_POINT *reparse_attr;
|
||||
|
||||
reparse_attr = (REPARSE_POINT*)NULL;
|
||||
if (ni) {
|
||||
reparse_attr = (REPARSE_POINT*)ntfs_attr_readall(ni,
|
||||
AT_REPARSE_POINT,(ntfschar*)NULL, 0, &attr_size);
|
||||
if (reparse_attr
|
||||
&& !valid_reparse_data(ni, reparse_attr, attr_size)) {
|
||||
free(reparse_attr);
|
||||
reparse_attr = (REPARSE_POINT*)NULL;
|
||||
errno = ENOENT;
|
||||
}
|
||||
} else
|
||||
errno = EINVAL;
|
||||
return (reparse_attr);
|
||||
}
|
||||
|
|
|
@ -41,9 +41,6 @@
|
|||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETXATTR
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
@ -64,6 +61,7 @@
|
|||
#include "acls.h"
|
||||
#include "cache.h"
|
||||
#include "misc.h"
|
||||
#include "xattrs.h"
|
||||
|
||||
/*
|
||||
* JPA NTFS constants or structs
|
||||
|
@ -525,8 +523,7 @@ static int entersecurity_data(ntfs_volume *vol,
|
|||
*/
|
||||
res = ntfs_attr_shrink_size(vol->secure_ni,STREAM_SDS,
|
||||
4, offs - gap + ALIGN_SDS_BLOCK + fullsz);
|
||||
}
|
||||
else
|
||||
} else
|
||||
errno = ENOSPC;
|
||||
free(fullattr);
|
||||
} else
|
||||
|
@ -3063,7 +3060,6 @@ BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni)
|
|||
return (allowed);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
#if POSIXACLS
|
||||
|
||||
|
@ -3242,7 +3238,6 @@ int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
|
|||
return (res ? -1 : 0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
/*
|
||||
* Set new permissions to a file
|
||||
|
@ -4383,7 +4378,6 @@ int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
|
|||
return (!scx->mapping[MAPUSERS] || link_group_members(scx));
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
|
||||
/*
|
||||
* Get the ntfs attribute into an extended attribute
|
||||
|
@ -4469,58 +4463,83 @@ int ntfs_set_ntfs_attrib(ntfs_inode *ni,
|
|||
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)
|
||||
* Open the volume's security descriptor index ($Secure)
|
||||
*
|
||||
* returns 0 if it succeeds
|
||||
* -1 with errno set if it fails and the volume is NTFS v3.0+
|
||||
*/
|
||||
|
||||
|
||||
int ntfs_open_secure(ntfs_volume *vol)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
int res;
|
||||
ntfs_index_context *sii;
|
||||
ntfs_index_context *sdh;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (vol->secure_ni) /* Already open? */
|
||||
return 0;
|
||||
|
||||
ni = ntfs_pathname_to_inode(vol, NULL, "$Secure");
|
||||
if (!ni)
|
||||
goto err;
|
||||
|
||||
if (ni->mft_no != FILE_Secure) {
|
||||
ntfs_log_error("$Secure does not have expected inode number!");
|
||||
errno = EINVAL;
|
||||
goto err_close_ni;
|
||||
}
|
||||
return (res);
|
||||
|
||||
/* Allocate the needed index contexts. */
|
||||
sii = ntfs_index_ctx_get(ni, sii_stream, 4);
|
||||
if (!sii)
|
||||
goto err_close_ni;
|
||||
|
||||
sdh = ntfs_index_ctx_get(ni, sdh_stream, 4);
|
||||
if (!sdh)
|
||||
goto err_close_sii;
|
||||
|
||||
vol->secure_xsdh = sdh;
|
||||
vol->secure_xsii = sii;
|
||||
vol->secure_ni = ni;
|
||||
return 0;
|
||||
|
||||
err_close_sii:
|
||||
ntfs_index_ctx_put(sii);
|
||||
err_close_ni:
|
||||
ntfs_inode_close(ni);
|
||||
err:
|
||||
/* Failing on NTFS pre-v3.0 is expected. */
|
||||
if (vol->major_ver < 3)
|
||||
return 0;
|
||||
ntfs_log_perror("Failed to open $Secure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Final cleaning
|
||||
* Close the volume's security descriptor index ($Secure)
|
||||
*
|
||||
* returns 0 if it succeeds
|
||||
* -1 with errno set if it fails
|
||||
*/
|
||||
int ntfs_close_secure(ntfs_volume *vol)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
if (vol->secure_ni) {
|
||||
ntfs_index_ctx_put(vol->secure_xsdh);
|
||||
ntfs_index_ctx_put(vol->secure_xsii);
|
||||
res = ntfs_inode_close(vol->secure_ni);
|
||||
vol->secure_ni = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a security context
|
||||
* Allocated memory is freed to facilitate the detection of memory leaks
|
||||
*/
|
||||
|
||||
void ntfs_close_secure(struct SECURITY_CONTEXT *scx)
|
||||
void ntfs_destroy_security_context(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);
|
||||
}
|
||||
|
@ -5339,7 +5358,6 @@ struct SECURITY_API *ntfs_initialize_file_security(const char *device,
|
|||
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);
|
||||
|
@ -5371,7 +5389,7 @@ BOOL ntfs_leave_file_security(struct SECURITY_API *scapi)
|
|||
ok = FALSE;
|
||||
if (scapi && (scapi->magic == MAGIC_API) && scapi->security.vol) {
|
||||
vol = scapi->security.vol;
|
||||
ntfs_close_secure(&scapi->security);
|
||||
ntfs_destroy_security_context(&scapi->security);
|
||||
free(scapi);
|
||||
if (!ntfs_umount(vol, 0))
|
||||
ok = TRUE;
|
||||
|
|
|
@ -59,7 +59,11 @@
|
|||
#include "logging.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define NOREVBOM 0 /* JPA rejecting U+FFFE and U+FFFF, open to debate */
|
||||
#ifndef ALLOW_BROKEN_UNICODE
|
||||
/* Erik allowing broken UTF-16 surrogate pairs and U+FFFE and U+FFFF by default,
|
||||
* open to debate. */
|
||||
#define ALLOW_BROKEN_UNICODE 1
|
||||
#endif /* !defined(ALLOW_BROKEN_UNICODE) */
|
||||
|
||||
/*
|
||||
* IMPORTANT
|
||||
|
@ -139,14 +143,24 @@ BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
|
|||
* @name1_len: length of first Unicode name to compare
|
||||
* @name2: second Unicode name to compare
|
||||
* @name2_len: length of second Unicode name to compare
|
||||
* @ic: either CASE_SENSITIVE or IGNORE_CASE
|
||||
* @upcase: upcase table (ignored if @ic is CASE_SENSITIVE)
|
||||
* @upcase_len: upcase table size (ignored if @ic is CASE_SENSITIVE)
|
||||
* @ic: either CASE_SENSITIVE or IGNORE_CASE (see below)
|
||||
* @upcase: upcase table
|
||||
* @upcase_len: upcase table size
|
||||
*
|
||||
* If @ic is CASE_SENSITIVE, then the names are compared primarily ignoring
|
||||
* case, but if the names are equal ignoring case, then they are compared
|
||||
* case-sensitively. As an example, "abc" would collate before "BCD" (since
|
||||
* "abc" and "BCD" differ ignoring case and 'A' < 'B') but after "ABC" (since
|
||||
* "ABC" and "abc" are equal ignoring case and 'A' < 'a'). This matches the
|
||||
* collation order of filenames as indexed in NTFS directories.
|
||||
*
|
||||
* If @ic is IGNORE_CASE, then the names are only compared case-insensitively
|
||||
* and are considered to match if and only if they are equal ignoring case.
|
||||
*
|
||||
* Returns:
|
||||
* -1 if the first name collates before the second one,
|
||||
* 0 if the names match,
|
||||
* 1 if the second name collates before the first one, or
|
||||
*
|
||||
* 0 if the names match, or
|
||||
* 1 if the second name collates before the first one
|
||||
*/
|
||||
int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
||||
const ntfschar *name2, const u32 name2_len,
|
||||
|
@ -158,7 +172,7 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||
u16 u1, u2;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!name1 || !name2 || (ic && (!upcase || !upcase_len))) {
|
||||
if (!name1 || !name2 || !upcase || !upcase_len) {
|
||||
ntfs_log_debug("ntfs_names_collate received NULL pointer!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -201,9 +215,9 @@ int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
|
|||
return 1;
|
||||
} else {
|
||||
do {
|
||||
u1 = c1 = le16_to_cpu(*name1);
|
||||
u1 = le16_to_cpu(*name1);
|
||||
name1++;
|
||||
u2 = c2 = le16_to_cpu(*name2);
|
||||
u2 = le16_to_cpu(*name2);
|
||||
name2++;
|
||||
if (u1 < upcase_len)
|
||||
u1 = le16_to_cpu(upcase[u1]);
|
||||
|
@ -444,10 +458,15 @@ void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
|
|||
*/
|
||||
|
||||
/*
|
||||
* Return the amount of 8-bit elements in UTF-8 needed (without the terminating
|
||||
* null) to store a given UTF-16LE string.
|
||||
* Return the number of bytes in UTF-8 needed (without the terminating null) to
|
||||
* store the given UTF-16LE string.
|
||||
*
|
||||
* Return -1 with errno set if string has invalid byte sequence or too long.
|
||||
* On error, -1 is returned, and errno is set to the error code. The following
|
||||
* error codes can be expected:
|
||||
* EILSEQ The input string is not valid UTF-16LE (only possible
|
||||
* if compiled without ALLOW_BROKEN_UNICODE).
|
||||
* ENAMETOOLONG The length of the UTF-8 string in bytes (without the
|
||||
* terminating null) would exceed @outs_len.
|
||||
*/
|
||||
static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_len)
|
||||
{
|
||||
|
@ -456,14 +475,28 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
|
|||
BOOL surrog;
|
||||
|
||||
surrog = FALSE;
|
||||
for (i = 0; i < ins_len && !le16_cmpz(ins[i]); i++) {
|
||||
for (i = 0; i < ins_len && !le16_cmpz(ins[i]) && count <= outs_len; i++) {
|
||||
unsigned short c = le16_to_cpu(ins[i]);
|
||||
if (surrog) {
|
||||
if ((c >= 0xdc00) && (c < 0xe000)) {
|
||||
surrog = FALSE;
|
||||
count += 4;
|
||||
} else
|
||||
} else {
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
/* The first UTF-16 unit of a surrogate pair has
|
||||
* a value between 0xd800 and 0xdc00. It can be
|
||||
* encoded as an individual UTF-8 sequence if we
|
||||
* cannot combine it with the next UTF-16 unit
|
||||
* unit as a surrogate pair. */
|
||||
surrog = FALSE;
|
||||
count += 3;
|
||||
|
||||
--i;
|
||||
continue;
|
||||
#else
|
||||
goto fail;
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
} else
|
||||
if (c < 0x80)
|
||||
count++;
|
||||
|
@ -473,21 +506,30 @@ static int utf16_to_utf8_size(const ntfschar *ins, const int ins_len, int outs_l
|
|||
count += 3;
|
||||
else if (c < 0xdc00)
|
||||
surrog = TRUE;
|
||||
#if NOREVBOM
|
||||
else if ((c >= 0xe000) && (c < 0xfffe))
|
||||
#else
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
else if (c < 0xe000)
|
||||
count += 3;
|
||||
else if (c >= 0xe000)
|
||||
#endif
|
||||
#else
|
||||
else if ((c >= 0xe000) && (c < 0xfffe))
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
count += 3;
|
||||
else
|
||||
goto fail;
|
||||
if (count > outs_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (surrog)
|
||||
|
||||
if (surrog && count <= outs_len) {
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
count += 3; /* ending with a single surrogate */
|
||||
#else
|
||||
goto fail;
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
|
||||
if (count > outs_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = count;
|
||||
out:
|
||||
|
@ -502,7 +544,7 @@ fail:
|
|||
* @ins: input utf16 string buffer
|
||||
* @ins_len: length of input string in utf16 characters
|
||||
* @outs: on return contains the (allocated) output multibyte string
|
||||
* @outs_len: length of output buffer in bytes
|
||||
* @outs_len: length of output buffer in bytes (ignored if *@outs is NULL)
|
||||
*
|
||||
* Return -1 with errno set if string has invalid byte sequence or too long.
|
||||
*/
|
||||
|
@ -521,10 +563,16 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||
int halfpair;
|
||||
|
||||
halfpair = 0;
|
||||
if (!*outs)
|
||||
if (!*outs) {
|
||||
/* If no output buffer was provided, we will allocate one and
|
||||
* limit its length to PATH_MAX. Note: we follow the standard
|
||||
* convention of PATH_MAX including the terminating null. */
|
||||
outs_len = PATH_MAX;
|
||||
}
|
||||
|
||||
size = utf16_to_utf8_size(ins, ins_len, outs_len);
|
||||
/* The size *with* the terminating null is limited to @outs_len,
|
||||
* so the size *without* the terminating null is limited to one less. */
|
||||
size = utf16_to_utf8_size(ins, ins_len, outs_len - 1);
|
||||
|
||||
if (size < 0)
|
||||
goto out;
|
||||
|
@ -548,8 +596,24 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||
*t++ = 0x80 + ((c >> 6) & 15) + ((halfpair & 3) << 4);
|
||||
*t++ = 0x80 + (c & 63);
|
||||
halfpair = 0;
|
||||
} else
|
||||
} else {
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
/* The first UTF-16 unit of a surrogate pair has
|
||||
* a value between 0xd800 and 0xdc00. It can be
|
||||
* encoded as an individual UTF-8 sequence if we
|
||||
* cannot combine it with the next UTF-16 unit
|
||||
* unit as a surrogate pair. */
|
||||
*t++ = 0xe0 | (halfpair >> 12);
|
||||
*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
|
||||
*t++ = 0x80 | (halfpair & 0x3f);
|
||||
halfpair = 0;
|
||||
|
||||
--i;
|
||||
continue;
|
||||
#else
|
||||
goto fail;
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
} else if (c < 0x80) {
|
||||
*t++ = c;
|
||||
} else {
|
||||
|
@ -562,6 +626,13 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||
*t++ = 0x80 | (c & 0x3f);
|
||||
} else if (c < 0xdc00)
|
||||
halfpair = c;
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
else if (c < 0xe000) {
|
||||
*t++ = 0xe0 | (c >> 12);
|
||||
*t++ = 0x80 | ((c >> 6) & 0x3f);
|
||||
*t++ = 0x80 | (c & 0x3f);
|
||||
}
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
else if (c >= 0xe000) {
|
||||
*t++ = 0xe0 | (c >> 12);
|
||||
*t++ = 0x80 | ((c >> 6) & 0x3f);
|
||||
|
@ -570,6 +641,13 @@ static int ntfs_utf16_to_utf8(const ntfschar *ins, const int ins_len,
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
if (halfpair) { /* ending with a single surrogate */
|
||||
*t++ = 0xe0 | (halfpair >> 12);
|
||||
*t++ = 0x80 | ((halfpair >> 6) & 0x3f);
|
||||
*t++ = 0x80 | (halfpair & 0x3f);
|
||||
}
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
*t = '\0';
|
||||
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
|
@ -691,15 +769,16 @@ static int utf8_to_unicode(u32 *wc, const char *s)
|
|||
| ((u32)(s[1] & 0x3F) << 6)
|
||||
| ((u32)(s[2] & 0x3F));
|
||||
/* Check valid ranges */
|
||||
#if NOREVBOM
|
||||
#if ALLOW_BROKEN_UNICODE
|
||||
if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFD)))
|
||||
|| ((*wc >= 0xD800) && (*wc <= 0xDFFF))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFF)))
|
||||
return 3;
|
||||
#else
|
||||
if (((*wc >= 0x800) && (*wc <= 0xD7FF))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFF)))
|
||||
|| ((*wc >= 0xe000) && (*wc <= 0xFFFD)))
|
||||
return 3;
|
||||
#endif
|
||||
#endif /* ALLOW_BROKEN_UNICODE */
|
||||
}
|
||||
goto fail;
|
||||
/* four-byte */
|
||||
|
@ -804,7 +883,7 @@ fail:
|
|||
* @ins: input Unicode string buffer
|
||||
* @ins_len: length of input string in Unicode characters
|
||||
* @outs: on return contains the (allocated) output multibyte string
|
||||
* @outs_len: length of output buffer in bytes
|
||||
* @outs_len: length of output buffer in bytes (ignored if *@outs is NULL)
|
||||
*
|
||||
* Convert the input little endian, 2-byte Unicode string @ins, of length
|
||||
* @ins_len into the multibyte string format dictated by the current locale.
|
||||
|
@ -1236,7 +1315,8 @@ void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len)
|
|||
{ 0x3c2, 0x3c2, 0x0, 2, 6, 1 },
|
||||
{ 0x3d7, 0x3d7, -0x8, 2, 6, 1 },
|
||||
{ 0x515, 0x523, -0x1, 2, 6, 1 },
|
||||
{ 0x1d79, 0x1d79, 0x8a04, 2, 6, 1 },
|
||||
/* below, -0x75fc stands for 0x8a04 and truncation */
|
||||
{ 0x1d79, 0x1d79, -0x75fc, 2, 6, 1 },
|
||||
{ 0x1efb, 0x1eff, -0x1, 2, 6, 1 },
|
||||
{ 0x1fc3, 0x1ff3, 0x9, 48, 6, 1 },
|
||||
{ 0x1fcc, 0x1ffc, 0x0, 48, 6, 1 },
|
||||
|
@ -1397,10 +1477,14 @@ void ntfs_ucsfree(ntfschar *ucs)
|
|||
* Check whether a name contains no chars forbidden
|
||||
* for DOS or Win32 use
|
||||
*
|
||||
* If @strict is TRUE, then trailing dots and spaces are forbidden.
|
||||
* These names are technically allowed in the Win32 namespace, but
|
||||
* they can be problematic. See comment for FILE_NAME_WIN32.
|
||||
*
|
||||
* If there is a bad char, errno is set to EINVAL
|
||||
*/
|
||||
|
||||
BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
||||
BOOL ntfs_forbidden_chars(const ntfschar *name, int len, BOOL strict)
|
||||
{
|
||||
BOOL forbidden;
|
||||
int ch;
|
||||
|
@ -1413,9 +1497,9 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
|||
| (1L << ('>' - 0x20))
|
||||
| (1L << ('?' - 0x20));
|
||||
|
||||
forbidden = (len == 0)
|
||||
|| le16_eq(name[len-1], const_cpu_to_le16(' '))
|
||||
|| le16_eq(name[len-1], const_cpu_to_le16('.'));
|
||||
forbidden = (len == 0) ||
|
||||
(strict && (le16_eq(name[len-1], const_cpu_to_le16(' ')) ||
|
||||
le16_eq(name[len-1], const_cpu_to_le16('.'))));
|
||||
for (i=0; i<len; i++) {
|
||||
ch = le16_to_cpu(name[i]);
|
||||
if ((ch < 0x20)
|
||||
|
@ -1437,10 +1521,15 @@ BOOL ntfs_forbidden_chars(const ntfschar *name, int len)
|
|||
* The reserved names are CON, PRN, AUX, NUL, COM1..COM9, LPT1..LPT9
|
||||
* with no suffix or any suffix.
|
||||
*
|
||||
* If @strict is TRUE, then trailing dots and spaces are forbidden.
|
||||
* These names are technically allowed in the Win32 namespace, but
|
||||
* they can be problematic. See comment for FILE_NAME_WIN32.
|
||||
*
|
||||
* If the name is forbidden, errno is set to EINVAL
|
||||
*/
|
||||
|
||||
BOOL ntfs_forbidden_names(ntfs_volume *vol, const ntfschar *name, int len)
|
||||
BOOL ntfs_forbidden_names(ntfs_volume *vol, const ntfschar *name, int len,
|
||||
BOOL strict)
|
||||
{
|
||||
BOOL forbidden;
|
||||
int h;
|
||||
|
@ -1458,7 +1547,7 @@ BOOL ntfs_forbidden_names(ntfs_volume *vol, const ntfschar *name, int len)
|
|||
static const ntfschar lpt[] = { const_cpu_to_le16('l'),
|
||||
const_cpu_to_le16('p'), const_cpu_to_le16('t') };
|
||||
|
||||
forbidden = ntfs_forbidden_chars(name, len);
|
||||
forbidden = ntfs_forbidden_chars(name, len, strict);
|
||||
if (!forbidden && (len >= 3)) {
|
||||
/*
|
||||
* Rough hash check to tell whether the first couple of chars
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#include "cache.h"
|
||||
#include "realpath.h"
|
||||
#include "misc.h"
|
||||
#include "security.h"
|
||||
|
||||
const char *ntfs_home =
|
||||
"News, support and information: http://tuxera.com\n";
|
||||
|
@ -97,6 +98,11 @@ static const char *hibernated_volume_msg =
|
|||
"Windows fully (no hibernation or fast restarting), or mount the volume\n"
|
||||
"read-only with the 'ro' mount option.\n";
|
||||
|
||||
static const char *fallback_readonly_msg =
|
||||
"Falling back to read-only mount because the NTFS partition is in an\n"
|
||||
"unsafe state. Please resume and shutdown Windows fully (no hibernation\n"
|
||||
"or fast restarting.)\n";
|
||||
|
||||
static const char *unclean_journal_msg =
|
||||
"Write access is denied because the disk wasn't safely powered\n"
|
||||
"off and the 'norecover' mount option was specified.\n";
|
||||
|
@ -167,6 +173,9 @@ static int __ntfs_volume_release(ntfs_volume *v)
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
if (ntfs_close_secure(v))
|
||||
ntfs_error_set(&err);
|
||||
|
||||
if (ntfs_inode_free(&v->vol_ni))
|
||||
ntfs_error_set(&err);
|
||||
/*
|
||||
|
@ -914,7 +923,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
|||
int i, j, eo;
|
||||
unsigned int k;
|
||||
u32 u;
|
||||
BOOL need_fallback_ro;
|
||||
|
||||
need_fallback_ro = FALSE;
|
||||
vol = ntfs_volume_startup(dev, flags);
|
||||
if (!vol)
|
||||
return NULL;
|
||||
|
@ -1227,26 +1238,46 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
|
|||
ntfs_log_perror("Failed to close $AttrDef");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
/* Open $Secure. */
|
||||
if (ntfs_open_secure(vol))
|
||||
goto error_exit;
|
||||
|
||||
/*
|
||||
* Check for dirty logfile and hibernated Windows.
|
||||
* We care only about read-write mounts.
|
||||
*/
|
||||
if (!(flags & (NTFS_MNT_RDONLY | NTFS_MNT_FORENSIC))) {
|
||||
if (!(flags & NTFS_MNT_IGNORE_HIBERFILE) &&
|
||||
ntfs_volume_check_hiberfile(vol, 1) < 0)
|
||||
goto error_exit;
|
||||
ntfs_volume_check_hiberfile(vol, 1) < 0) {
|
||||
if (flags & NTFS_MNT_MAY_RDONLY)
|
||||
need_fallback_ro = TRUE;
|
||||
else
|
||||
goto error_exit;
|
||||
}
|
||||
if (ntfs_volume_check_logfile(vol) < 0) {
|
||||
/* Always reject cached metadata for now */
|
||||
if (!(flags & NTFS_MNT_RECOVER) || (errno == EPERM))
|
||||
goto error_exit;
|
||||
ntfs_log_info("The file system wasn't safely "
|
||||
"closed on Windows. Fixing.\n");
|
||||
if (ntfs_logfile_reset(vol))
|
||||
goto error_exit;
|
||||
if (!(flags & NTFS_MNT_RECOVER) || (errno == EPERM)) {
|
||||
if (flags & NTFS_MNT_MAY_RDONLY)
|
||||
need_fallback_ro = TRUE;
|
||||
else
|
||||
goto error_exit;
|
||||
} else {
|
||||
ntfs_log_info("The file system wasn't safely "
|
||||
"closed on Windows. Fixing.\n");
|
||||
if (ntfs_logfile_reset(vol))
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
/* make $TXF_DATA resident if present on the root directory */
|
||||
if (fix_txf_data(vol))
|
||||
goto error_exit;
|
||||
if (!(flags & NTFS_MNT_RDONLY) && !need_fallback_ro) {
|
||||
if (fix_txf_data(vol))
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
if (need_fallback_ro) {
|
||||
NVolSetReadOnly(vol);
|
||||
ntfs_log_error("%s", fallback_readonly_msg);
|
||||
}
|
||||
|
||||
return vol;
|
||||
|
|
|
@ -150,6 +150,7 @@ enum { /* see http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx *
|
|||
STATUS_FILE_NOT_FOUND = 0xC0000028,
|
||||
STATUS_OBJECT_NAME_INVALID = 0xC0000033,
|
||||
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
|
||||
STATUS_SHARING_VIOLATION = 0xC0000043,
|
||||
STATUS_INVALID_PARAMETER_1 = 0xC00000EF,
|
||||
STATUS_IO_DEVICE_ERROR = 0xC0000185,
|
||||
STATUS_GUARD_PAGE_VIOLATION = 0x80000001
|
||||
|
@ -354,6 +355,8 @@ static int ntfs_ntstatus_to_errno(NTSTATUS status)
|
|||
case STATUS_IO_DEVICE_ERROR :
|
||||
case STATUS_END_OF_FILE :
|
||||
return (EIO);
|
||||
case STATUS_SHARING_VIOLATION :
|
||||
return (EBUSY);
|
||||
default:
|
||||
/* generic message */
|
||||
return ENOMSG;
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SETXATTR /* extended attributes support required */
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
@ -83,10 +81,6 @@ struct LE_POSIX_ACL {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
static const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
static const char nf_ns_user_prefix[] = "user.";
|
||||
static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
|
||||
|
||||
static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
|
||||
static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
|
||||
static const char nf_ns_xattr_attrib_be[] = "system.ntfs_attrib_be";
|
||||
|
@ -798,5 +792,3 @@ int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
|
|||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
|
|
@ -17,7 +17,8 @@ if ENABLE_NTFSPROGS
|
|||
bin_PROGRAMS = ntfsfix ntfsinfo ntfscluster ntfsls ntfscat ntfscmp
|
||||
sbin_PROGRAMS = mkntfs ntfslabel ntfsundelete ntfsresize ntfsclone \
|
||||
ntfscp
|
||||
EXTRA_PROGRAM_NAMES = ntfswipe ntfstruncate ntfsrecover
|
||||
EXTRA_PROGRAM_NAMES = ntfswipe ntfstruncate ntfsrecover \
|
||||
ntfsusermap ntfssecaudit
|
||||
|
||||
QUARANTINED_PROGRAM_NAMES = ntfsdump_logfile ntfsmftalloc ntfsmove ntfsck \
|
||||
ntfsfallocate
|
||||
|
@ -26,7 +27,8 @@ man_MANS = mkntfs.8 ntfsfix.8 ntfslabel.8 ntfsinfo.8 \
|
|||
ntfsundelete.8 ntfsresize.8 ntfsprogs.8 ntfsls.8 \
|
||||
ntfsclone.8 ntfscluster.8 ntfscat.8 ntfscp.8 \
|
||||
ntfscmp.8 ntfswipe.8 ntfstruncate.8 \
|
||||
ntfsdecrypt.8 ntfsfallocate.8 ntfsrecover.8
|
||||
ntfsdecrypt.8 ntfsfallocate.8 ntfsrecover.8 \
|
||||
ntfsusermap.8 ntfssecaudit.8
|
||||
EXTRA_MANS =
|
||||
|
||||
CLEANFILES = $(EXTRA_PROGRAMS)
|
||||
|
@ -106,6 +108,14 @@ ntfsrecover_SOURCES = playlog.c ntfsrecover.c utils.c utils.h ntfsrecover.h
|
|||
ntfsrecover_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS)
|
||||
ntfsrecover_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfsusermap_SOURCES = ntfsusermap.c utils.c utils.h
|
||||
ntfsusermap_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS)
|
||||
ntfsusermap_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
ntfssecaudit_SOURCES = ntfssecaudit.c utils.c utils.h
|
||||
ntfssecaudit_LDADD = $(AM_LIBS) $(NTFSRECOVER_LIBS)
|
||||
ntfssecaudit_LDFLAGS = $(AM_LFLAGS)
|
||||
|
||||
# We don't distribute these
|
||||
|
||||
ntfstruncate_SOURCES = attrdef.c ntfstruncate.c utils.c utils.h
|
||||
|
|
|
@ -185,12 +185,14 @@ Clone NTFS to the non\-existent
|
|||
If
|
||||
.I FILE
|
||||
is '\-' then clone to the
|
||||
standard output.
|
||||
standard output. This option cannot be used for creating a partition,
|
||||
use \fB\-\-overwrite\fR for an existing partition.
|
||||
.TP
|
||||
\fB\-O\fR, \fB\-\-overwrite\fR FILE
|
||||
Clone NTFS to
|
||||
.IR FILE ,
|
||||
overwriting if exists.
|
||||
which can be an existing partition or a regular file which will be
|
||||
overwritten if it exists.
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-save\-image\fR
|
||||
Save to the special image format. This is the most efficient way space and
|
||||
|
@ -235,8 +237,11 @@ inconsistency are saved too.
|
|||
Do not wipe the timestamps, to be used only with the
|
||||
.B \-\-metadata
|
||||
option.
|
||||
|
||||
|
||||
.TP
|
||||
\fB\-\-full\-logfile\fR
|
||||
Include the Windows log file in the copy. This is only useful for
|
||||
extracting metadata, saving or cloning a file system which was not
|
||||
properly unmounted from Windows.
|
||||
.TP
|
||||
\fB\-\-new\-serial\fR, or
|
||||
.TP
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2003-2006 Szabolcs Szakacsits
|
||||
* Copyright (c) 2004-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2010-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2010-2016 Jean-Pierre Andre
|
||||
* Special image format support copyright (c) 2004 Per Olofsson
|
||||
*
|
||||
* Clone NTFS data and/or metadata to a sparse file, image, device or stdout.
|
||||
|
@ -160,6 +160,7 @@ static struct {
|
|||
int new_serial;
|
||||
int metadata_image;
|
||||
int preserve_timestamps;
|
||||
int full_logfile;
|
||||
int restore_image;
|
||||
char *output;
|
||||
char *volume;
|
||||
|
@ -368,11 +369,12 @@ static void usage(int ret)
|
|||
" -t, --preserve-timestamps Do not clear the timestamps\n"
|
||||
" -q, --quiet Do not display any progress bars\n"
|
||||
" -f, --force Force to progress (DANGEROUS)\n"
|
||||
" --full-logfile Include the full logfile in metadata output\n"
|
||||
" -h, --help Display this help\n"
|
||||
#ifdef DEBUG
|
||||
" -d, --debug Show debug information\n"
|
||||
#endif
|
||||
" -V, --version Display version information\n"
|
||||
" -V, --version Display version information\n"
|
||||
"\n"
|
||||
" If FILE is '-' then send the image to the standard output. If SOURCE is '-'\n"
|
||||
" and --restore-image is used then read the image from the standard input.\n"
|
||||
|
@ -391,7 +393,7 @@ static void version(void)
|
|||
"Efficiently clone, image, restore or rescue an NTFS Volume.\n\n"
|
||||
"Copyright (c) 2003-2006 Szabolcs Szakacsits\n"
|
||||
"Copyright (c) 2004-2006 Anton Altaparmakov\n"
|
||||
"Copyright (c) 2010-2015 Jean-Pierre Andre\n\n");
|
||||
"Copyright (c) 2010-2016 Jean-Pierre Andre\n\n");
|
||||
fprintf(stderr, "%s\n%s%s", ntfs_gpl, ntfs_bugs, ntfs_home);
|
||||
exit(0);
|
||||
}
|
||||
|
@ -415,6 +417,7 @@ static void parse_options(int argc, char **argv)
|
|||
{ "rescue", no_argument, NULL, 'R' },
|
||||
{ "new-serial", no_argument, NULL, 'I' },
|
||||
{ "new-half-serial", no_argument, NULL, 'i' },
|
||||
{ "full-logfile", no_argument, NULL, 'l' },
|
||||
{ "save-image", no_argument, NULL, 's' },
|
||||
{ "preserve-timestamps", no_argument, NULL, 't' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
|
@ -451,6 +454,9 @@ static void parse_options(int argc, char **argv)
|
|||
case 'I': /* not proposed as a short option */
|
||||
opt.new_serial |= 2;
|
||||
break;
|
||||
case 'l':
|
||||
opt.full_logfile++;
|
||||
break;
|
||||
case 'm':
|
||||
opt.metadata++;
|
||||
break;
|
||||
|
@ -633,7 +639,7 @@ static s64 is_critical_metadata(ntfs_walk_clusters_ctx *image, runlist *rl)
|
|||
if (inode == FILE_BadClus && le32_eq(image->ctx->attr->type, AT_DATA))
|
||||
return 0;
|
||||
|
||||
if (inode != FILE_LogFile)
|
||||
if ((inode != FILE_LogFile) || opt.full_logfile)
|
||||
return rl->length;
|
||||
|
||||
if (le32_eq(image->ctx->attr->type, AT_DATA)) {
|
||||
|
@ -2150,11 +2156,20 @@ static void mount_volume(unsigned long new_mntflag)
|
|||
* Normally avoided in order to get the original log file
|
||||
* data, but needed when remounting the metadata of a
|
||||
* volume improperly unmounted from Windows.
|
||||
* If the full log file was requested, it must be kept
|
||||
* as is, so we just remount read-only.
|
||||
*/
|
||||
if (!(new_mntflag & (NTFS_MNT_RDONLY | NTFS_MNT_RECOVER))) {
|
||||
Printf("Trying to recover...\n");
|
||||
vol = ntfs_mount(opt.volume,
|
||||
if (opt.full_logfile) {
|
||||
Printf("Retrying read-only to ignore"
|
||||
" the log file...\n");
|
||||
vol = ntfs_mount(opt.volume,
|
||||
new_mntflag | NTFS_MNT_RDONLY);
|
||||
} else {
|
||||
Printf("Trying to recover...\n");
|
||||
vol = ntfs_mount(opt.volume,
|
||||
new_mntflag | NTFS_MNT_RECOVER);
|
||||
}
|
||||
Printf("... %s\n",(vol ? "Successful" : "Failed"));
|
||||
}
|
||||
if (!vol)
|
||||
|
|
|
@ -486,6 +486,9 @@ int main(int argc, char *argv[])
|
|||
struct match m;
|
||||
int res;
|
||||
int result = 1;
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
char *unix_name;
|
||||
#endif
|
||||
|
||||
ntfs_log_set_handler(ntfs_log_handler_outerr);
|
||||
|
||||
|
@ -521,7 +524,17 @@ int main(int argc, char *argv[])
|
|||
result = cluster_find(vol, opts.range_begin, opts.range_end, (cluster_cb*)&print_match, NULL);
|
||||
break;
|
||||
case act_file:
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
unix_name = ntfs_utils_unix_path(opts.filename);
|
||||
ino = 0;
|
||||
if (unix_name) {
|
||||
ino = ntfs_pathname_to_inode(vol, NULL,
|
||||
unix_name);
|
||||
free(unix_name);
|
||||
}
|
||||
#else
|
||||
ino = ntfs_pathname_to_inode(vol, NULL, opts.filename);
|
||||
#endif
|
||||
if (ino)
|
||||
result = dump_file(vol, ino);
|
||||
break;
|
||||
|
|
|
@ -547,7 +547,7 @@ static void cmp_index_allocation(ntfs_attr *na1, ntfs_attr *na2)
|
|||
/*
|
||||
* FIXME: ia can be the same even if the bitmap sizes are different.
|
||||
*/
|
||||
if (cia1.bm_size != cia1.bm_size)
|
||||
if (cia1.bm_size != cia2.bm_size)
|
||||
goto out;
|
||||
|
||||
if (cmp_buffer(cia1.bitmap, cia2.bitmap, cia1.bm_size, na1))
|
||||
|
|
|
@ -319,7 +319,7 @@ static void restart_header_sanity(RESTART_PAGE_HEADER *rstr, u8 *buf)
|
|||
log_err_exit(buf, "Restart page header in $LogFile is "
|
||||
"corrupt: Update sequence array size is "
|
||||
"wrong. Cannot handle this yet.\n");
|
||||
if (le16_to_cpu(rstr->usa_ofs) < sizeof(RESTART_PAGE_HEADER))
|
||||
if (le16_to_cpu(rstr->usa_ofs) < offsetof(RESTART_PAGE_HEADER, usn))
|
||||
log_err_exit(buf, "Restart page header in $LogFile is "
|
||||
"corrupt: Update sequence array overlaps "
|
||||
"restart page header. Cannot handle this "
|
||||
|
@ -557,17 +557,17 @@ static void dump_log_record(LOG_RECORD *lr)
|
|||
(unsigned int)le32_to_cpu(lr->record_type));
|
||||
ntfs_log_info("transaction_id = 0x%x\n",
|
||||
(unsigned int)le32_to_cpu(lr->transaction_id));
|
||||
ntfs_log_info("flags = 0x%x:", le16_to_cpu(lr->flags));
|
||||
if (le16_cmpz(lr->flags))
|
||||
ntfs_log_info("flags = 0x%x:", le16_to_cpu(lr->log_record_flags));
|
||||
if (le16_cmpz(lr->log_record_flags))
|
||||
ntfs_log_info(" NONE\n");
|
||||
else {
|
||||
int _b = 0;
|
||||
|
||||
if (!le16_andz(lr->flags, LOG_RECORD_MULTI_PAGE)) {
|
||||
if (!le16_andz(lr->log_record_flags, LOG_RECORD_MULTI_PAGE)) {
|
||||
ntfs_log_info(" LOG_RECORD_MULTI_PAGE");
|
||||
_b = 1;
|
||||
}
|
||||
if (!le16_andz(lr->flags, le16_not(LOG_RECORD_MULTI_PAGE))) {
|
||||
if (!le16_andz(lr->log_record_flags, le16_not(LOG_RECORD_MULTI_PAGE))) {
|
||||
if (_b)
|
||||
ntfs_log_info(" |");
|
||||
ntfs_log_info(" Unknown flags");
|
||||
|
@ -589,8 +589,8 @@ static void dump_log_record(LOG_RECORD *lr)
|
|||
if (le16_to_cpu(lr->lcns_to_follow) > 0)
|
||||
ntfs_log_info("Array of lcns:\n");
|
||||
for (i = 0; i < le16_to_cpu(lr->lcns_to_follow); i++)
|
||||
ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i, (unsigned long long)
|
||||
sle64_to_cpu(lr->lcn_list[i].lcn));
|
||||
ntfs_log_info("lcn_list[%u].lcn = 0x%llx\n", i,
|
||||
(unsigned long long)sle64_to_cpu(lr->lcn_list[i]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -633,9 +633,9 @@ rcrd_pass_loc:
|
|||
ntfs_log_info("page count = %i\n", le16_to_cpu(rcrd->page_count));
|
||||
ntfs_log_info("page position = %i\n", le16_to_cpu(rcrd->page_position));
|
||||
ntfs_log_info("header.next_record_offset = 0x%llx\n", (unsigned long long)
|
||||
le16_to_cpu(rcrd->header.packed.next_record_offset));
|
||||
le16_to_cpu(rcrd->next_record_offset));
|
||||
ntfs_log_info("header.last_end_lsn = 0x%llx\n", (unsigned long long)
|
||||
sle64_to_cpu(rcrd->header.packed.last_end_lsn));
|
||||
sle64_to_cpu(rcrd->last_end_lsn));
|
||||
/*
|
||||
* Where does the 0x40 come from? Is it just usa_offset +
|
||||
* usa_client * 2 + 7 & ~7 or is it derived from somewhere?
|
||||
|
@ -648,7 +648,7 @@ rcrd_pass_loc:
|
|||
client++;
|
||||
lr = (LOG_RECORD*)((u8*)lr + 0x70);
|
||||
} while (((u8*)lr + 0x70 <= (u8*)rcrd +
|
||||
le16_to_cpu(rcrd->header.packed.next_record_offset)));
|
||||
le16_to_cpu(rcrd->next_record_offset)));
|
||||
|
||||
pass++;
|
||||
goto rcrd_pass_loc;
|
||||
|
|
|
@ -341,6 +341,39 @@ static int empty_journal(ntfs_volume *vol)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the sparse flag of an attribute
|
||||
*/
|
||||
|
||||
static int clear_sparse(ntfs_attr *na, const char *name)
|
||||
{
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
|
||||
if (ctx) {
|
||||
if (!ntfs_attr_lookup(na->type, na->name, na->name_len,
|
||||
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
|
||||
na->data_flags = le16_and(na->data_flags, le16_not(ATTR_IS_SPARSE));
|
||||
ctx->attr->data_size = cpu_to_sle64(na->data_size);
|
||||
ctx->attr->initialized_size
|
||||
= cpu_to_sle64(na->initialized_size);
|
||||
ctx->attr->flags = cpu_to_le16(na->data_flags);
|
||||
ctx->attr->compression_unit = 0;
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
res = 0;
|
||||
} else
|
||||
ntfs_log_perror("Could not locate attribute for %s",
|
||||
name);
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
} else
|
||||
ntfs_log_perror("Could not get a search context for %s",
|
||||
name);
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the bad cluster marks (option)
|
||||
*/
|
||||
|
@ -372,15 +405,14 @@ static int clear_badclus(ntfs_volume *vol)
|
|||
* (which requires setting the data size according
|
||||
* to allocation), then reallocate a sparse stream
|
||||
* to full size of volume and reset the data size.
|
||||
* Note : the sparse flags should not be set.
|
||||
*/
|
||||
na->data_size = na->allocated_size;
|
||||
na->initialized_size = na->allocated_size;
|
||||
if (!ntfs_attr_truncate(na,0)
|
||||
&& !ntfs_attr_truncate(na,vol->nr_clusters
|
||||
<< vol->cluster_size_bits)) {
|
||||
na->data_size = 0;
|
||||
na->initialized_size = 0;
|
||||
ni->flags = le32_or(ni->flags, FILE_ATTR_SPARSE_FILE);
|
||||
NInoFileNameSetDirty(ni);
|
||||
ok = TRUE;
|
||||
} else {
|
||||
|
@ -390,6 +422,14 @@ static int clear_badclus(ntfs_volume *vol)
|
|||
ntfs_log_info("No bad clusters...");
|
||||
ok = TRUE;
|
||||
}
|
||||
/*
|
||||
* The sparse flags are not set after an initial
|
||||
* formatting, so do the same.
|
||||
*/
|
||||
if (ok) {
|
||||
ni->flags = le32_and(ni->flags, le32_not(FILE_ATTR_SPARSE_FILE));
|
||||
ok = !clear_sparse(na, "$BadClus::$Bad");
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else {
|
||||
ntfs_log_perror("Failed to open $BadClus::$Bad");
|
||||
|
|
|
@ -412,16 +412,23 @@ static const char *reparse_type_name(le32 tag)
|
|||
{
|
||||
const char *name;
|
||||
|
||||
if (le32_eq(tag, IO_REPARSE_TAG_MOUNT_POINT))
|
||||
do {
|
||||
if (le32_eq(tag, IO_REPARSE_TAG_MOUNT_POINT)) {
|
||||
name = " (mount point)";
|
||||
else
|
||||
if (le32_eq(tag, IO_REPARSE_TAG_SYMLINK))
|
||||
name = " (symlink)";
|
||||
else
|
||||
if (le32_eq(tag, IO_REPARSE_TAG_WOF))
|
||||
name = " (Wof compressed)";
|
||||
else
|
||||
name = "";
|
||||
break;
|
||||
} else if (le32_eq(tag, IO_REPARSE_TAG_SYMLINK)) {
|
||||
name = " (symlink)";
|
||||
break;
|
||||
} else if (le32_eq(tag, IO_REPARSE_TAG_WOF)) {
|
||||
name = " (Wof compressed)";
|
||||
break;
|
||||
} else if (le32_eq(tag, IO_REPARSE_TAG_DEDUP)) {
|
||||
name = " (deduplicated)";
|
||||
break;
|
||||
} else {
|
||||
name = "";
|
||||
break;
|
||||
} } while(0);
|
||||
return (name);
|
||||
}
|
||||
|
||||
|
|
|
@ -299,8 +299,9 @@ static int set_new_serial(ntfs_volume *vol)
|
|||
serial_number = cpu_to_le64(sn);
|
||||
}
|
||||
if (!change_serial(vol, 0, serial_number, bs, oldbs)) {
|
||||
number_of_sectors = sle64_to_cpu(bs->number_of_sectors);
|
||||
if (!change_serial(vol, number_of_sectors,
|
||||
number_of_sectors = ntfs_device_size_get(vol->dev,
|
||||
vol->sector_size);
|
||||
if (!change_serial(vol, number_of_sectors - 1,
|
||||
serial_number, bs, oldbs)) {
|
||||
ntfs_log_info("New serial number : %016llx\n",
|
||||
(long long)le64_to_cpu(
|
||||
|
|
|
@ -86,6 +86,13 @@ generated during several sessions.
|
|||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Show some help information.
|
||||
.TP
|
||||
\fB\-k\fR, \fB\-\-kill\-fast\-restart\fR
|
||||
When Windows has been interrupted with fast restart mode activated,
|
||||
part of pending changes are kept in the Windows cache and only the same
|
||||
Windows version can recover them. This option can be used to apply the
|
||||
changes recorded in the log file and drop the ones in the Windows cache.
|
||||
This is dangerous and may cause loss of data.
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no-action\fR
|
||||
Do not apply any modification, useful when using the options -p, -s or -u.
|
||||
.TP
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
|||
* Declarations for processing log data
|
||||
*
|
||||
* Copyright (c) 2000-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2014-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2014-2016 Jean-Pierre Andre
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -22,16 +22,6 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO
|
||||
* This file partially duplicates logfile.h (with modifications).
|
||||
* The generic declarations are to be moved to logfile.h, thus
|
||||
* implying adapting (at least) libntfs-3g/logfile.c and
|
||||
* ntfsprogs/ntfsdump_logfile.c, and the declarations specific to
|
||||
* ntfsrecover should be kept in this file.
|
||||
* (removing ntfsdump_logfile.c might also be considered).
|
||||
*/
|
||||
|
||||
#define getle16(p,x) le16_to_cpu(*(const le16*)((const char*)(p) + (x)))
|
||||
#define getle32(p,x) le32_to_cpu(*(const le32*)((const char*)(p) + (x)))
|
||||
#define getle64(p,x) le64_to_cpu(*(const le64*)((const char*)(p) + (x)))
|
||||
|
@ -40,17 +30,6 @@
|
|||
#define feedle32(p,x) (*(const le32*)((const char*)(p) + (x)))
|
||||
#define feedle64(p,x) (*(const le64*)((const char*)(p) + (x)))
|
||||
|
||||
enum LOG_RECORD_TYPE {
|
||||
LOG_STANDARD = 1,
|
||||
LOG_CHECKPOINT = 2
|
||||
} ;
|
||||
|
||||
/* These flags were introduced in Vista in field attribute_flags */
|
||||
enum ATTRIBUTE_FLAGS {
|
||||
ACTS_ON_MFT = 2,
|
||||
ACTS_ON_INDX = 8
|
||||
} ;
|
||||
|
||||
enum ACTIONS {
|
||||
Noop, /* 0 */
|
||||
CompensationlogRecord, /* 1 */
|
||||
|
@ -93,153 +72,14 @@ enum ACTIONS {
|
|||
LastAction /* 38 */
|
||||
} ;
|
||||
|
||||
/* Flags for field log_record_flags, their meaning is unclear */
|
||||
enum RECORD_FLAGS {
|
||||
RECORD_UNKNOWN = 1,
|
||||
/* The flags below were introduced in Windows 10 */
|
||||
RECORD_DELETING = 2,
|
||||
RECORD_ADDING = 4
|
||||
} ;
|
||||
typedef le16 LOG_RECORD_FLAGS;
|
||||
|
||||
#define LOGFILE_NO_CLIENT const_cpu_to_le16(0xffff)
|
||||
#define RESTART_VOLUME_IS_CLEAN const_cpu_to_le16(0x0002)
|
||||
|
||||
/* ntfsdoc p 39 (47), not in layout.h */
|
||||
|
||||
typedef struct RESTART_PAGE_HEADER { /* size 32 */
|
||||
NTFS_RECORD head;
|
||||
leLSN chkdsk_lsn;
|
||||
le32 system_page_size;
|
||||
le32 log_page_size;
|
||||
le16 restart_offset;
|
||||
le16 minor_ver;
|
||||
le16 major_ver;
|
||||
le16 usn;
|
||||
} __attribute__((__packed__)) RESTART_PAGE_HEADER;
|
||||
|
||||
/* ntfsdoc p 40 (48), not in layout.h */
|
||||
|
||||
struct RESTART_AREA { /* size 44 */
|
||||
leLSN current_lsn;
|
||||
le16 log_clients;
|
||||
le16 client_free_list;
|
||||
le16 client_in_use_list;
|
||||
le16 flags;
|
||||
le32 seq_number_bits;
|
||||
le16 restart_area_length;
|
||||
le16 client_array_offset;
|
||||
le64 file_size;
|
||||
le32 last_lsn_data_length;
|
||||
le16 record_length;
|
||||
le16 log_page_data_offset;
|
||||
le32 restart_log_open_count;
|
||||
} __attribute__((__packed__)) ;
|
||||
|
||||
typedef struct RESTART_CLIENT { /* size 160 */
|
||||
/*Ofs*/
|
||||
/* 0*/ leLSN oldest_lsn; /* Oldest LSN needed by this client. On create
|
||||
set to 0. */
|
||||
/* 8*/ leLSN client_restart_lsn;/* LSN at which this client needs to restart
|
||||
the volume, i.e. the current position within
|
||||
the log file. At present, if clean this
|
||||
should = current_lsn in restart area but it
|
||||
probably also = current_lsn when dirty most
|
||||
of the time. At create set to 0. */
|
||||
/* 16*/ le16 prev_client; /* The offset to the previous log client record
|
||||
in the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there is no previous
|
||||
client record, i.e. this is the first one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 18*/ le16 next_client; /* The offset to the next log client record in
|
||||
the array of log client records.
|
||||
LOGFILE_NO_CLIENT means there are no next
|
||||
client records, i.e. this is the last one.
|
||||
This is always LOGFILE_NO_CLIENT. */
|
||||
/* 20*/ le16 seq_number; /* On Win2k and presumably earlier, this is set
|
||||
to zero every time the logfile is restarted
|
||||
and it is incremented when the logfile is
|
||||
closed at dismount time. Thus it is 0 when
|
||||
dirty and 1 when clean. On WinXP and
|
||||
presumably later, this is always 0. */
|
||||
/* 22*/ u8 reserved[6]; /* Reserved/alignment. */
|
||||
/* 28*/ le32 client_name_length;/* Length of client name in bytes. Should
|
||||
always be 8. */
|
||||
/* 32*/ le16 client_name[64]; /* Name of the client in Unicode. Should
|
||||
always be "NTFS" with the remaining bytes
|
||||
set to 0. */
|
||||
/* sizeof() = 160 (0xa0) bytes */
|
||||
} __attribute__((__packed__)) LOG_CLIENT_RECORD;
|
||||
|
||||
/* ntfsdoc p 41 (49), not in layout.h */
|
||||
|
||||
struct RECORD_PAGE_HEADER { /* size 40 */
|
||||
NTFS_RECORD head; /* the magic is "RCRD" */
|
||||
union {
|
||||
leLSN last_lsn;
|
||||
le32 file_offset;
|
||||
} __attribute__((__packed__)) copy;
|
||||
le32 flags;
|
||||
le16 page_count;
|
||||
le16 page_position;
|
||||
le16 next_record_offset;
|
||||
le16 reserved4[3];
|
||||
leLSN last_end_lsn;
|
||||
} __attribute__((__packed__)) ;
|
||||
|
||||
/* ntfsdoc p 42 (50), not in layout.h */
|
||||
|
||||
#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */
|
||||
|
||||
typedef struct LOG_RECORD { /* size 80 */
|
||||
leLSN this_lsn;
|
||||
leLSN client_previous_lsn;
|
||||
leLSN client_undo_next_lsn;
|
||||
le32 client_data_length;
|
||||
struct {
|
||||
le16 seq_number;
|
||||
le16 client_index;
|
||||
} __attribute__((__packed__)) client_id;
|
||||
le32 record_type;
|
||||
le32 transaction_id;
|
||||
LOG_RECORD_FLAGS log_record_flags;
|
||||
le16 reserved1[3];
|
||||
le16 redo_operation;
|
||||
le16 undo_operation;
|
||||
le16 redo_offset;
|
||||
le16 redo_length;
|
||||
union {
|
||||
struct {
|
||||
le16 undo_offset;
|
||||
le16 undo_length;
|
||||
le16 target_attribute;
|
||||
le16 lcns_to_follow;
|
||||
le16 record_offset;
|
||||
le16 attribute_offset;
|
||||
le16 cluster_index;
|
||||
le16 attribute_flags;
|
||||
le32 target_vcn;
|
||||
le32 reserved3;
|
||||
le64 lcn_list[0];
|
||||
} __attribute__((__packed__));
|
||||
struct {
|
||||
leLSN transaction_lsn;
|
||||
leLSN attributes_lsn;
|
||||
leLSN names_lsn;
|
||||
leLSN dirty_pages_lsn;
|
||||
le64 unknown_list[0];
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__)) LOG_RECORD;
|
||||
|
||||
struct BUFFER {
|
||||
unsigned int num;
|
||||
unsigned int size;
|
||||
unsigned int headsz;
|
||||
BOOL safe;
|
||||
union {
|
||||
struct RESTART_PAGE_HEADER restart;
|
||||
struct RECORD_PAGE_HEADER record;
|
||||
RESTART_PAGE_HEADER restart;
|
||||
RECORD_PAGE_HEADER record;
|
||||
char data[1];
|
||||
} block; /* variable length, keep at the end */
|
||||
} ;
|
||||
|
@ -249,7 +89,7 @@ struct ACTION_RECORD {
|
|||
struct ACTION_RECORD *prev;
|
||||
int num;
|
||||
unsigned int flags;
|
||||
struct LOG_RECORD record; /* variable length, keep at the end */
|
||||
LOG_RECORD record; /* variable length, keep at the end */
|
||||
} ;
|
||||
|
||||
enum { /* Flag values for ACTION_RECORD */
|
||||
|
@ -265,31 +105,6 @@ struct ATTR {
|
|||
le16 name[1];
|
||||
} ;
|
||||
|
||||
struct BITMAP_ACTION {
|
||||
le32 firstbit;
|
||||
le32 count;
|
||||
} ;
|
||||
|
||||
/* Danger in arrays : contains le64's though size is not a multiple of 8 */
|
||||
typedef struct ATTR_OLD { /* Format up to Win10 (44 bytes) */
|
||||
le64 unknown1;
|
||||
le64 unknown2;
|
||||
le64 inode;
|
||||
leLSN lsn;
|
||||
le32 unknown3;
|
||||
le32 type;
|
||||
le32 unknown4;
|
||||
} __attribute__((__packed__)) ATTR_OLD;
|
||||
|
||||
typedef struct ATTR_NEW { /* Format since Win10 (40 bytes) */
|
||||
le64 unknown1;
|
||||
le64 unknown2;
|
||||
le32 type;
|
||||
le32 unknown3;
|
||||
le64 inode;
|
||||
leLSN lsn;
|
||||
} __attribute__((__packed__)) ATTR_NEW;
|
||||
|
||||
extern u32 clustersz;
|
||||
extern int clusterbits;
|
||||
extern u32 blocksz;
|
||||
|
@ -315,23 +130,22 @@ extern u64 synced_lsn;
|
|||
extern u64 latest_lsn;
|
||||
extern u64 restart_lsn;
|
||||
|
||||
extern struct RESTART_AREA restart;
|
||||
extern struct RESTART_CLIENT client;
|
||||
extern RESTART_AREA restart;
|
||||
extern LOG_CLIENT_RECORD client;
|
||||
|
||||
const char *actionname(int op);
|
||||
const char *mftattrname(ATTR_TYPES attr);
|
||||
void showname(const char *prefix, const char *name, int cnt);
|
||||
int fixnamelen(const char *name, int len);
|
||||
BOOL within_lcn_range(const struct LOG_RECORD *logr);
|
||||
BOOL within_lcn_range(const LOG_RECORD *logr);
|
||||
struct ATTR *getattrentry(unsigned int key, unsigned int lth);
|
||||
void copy_attribute(struct ATTR *pa, const char *buf, int length);
|
||||
u32 get_undo_offset(const struct LOG_RECORD *logr);
|
||||
u32 get_redo_offset(const struct LOG_RECORD *logr);
|
||||
u32 get_extra_offset(const struct LOG_RECORD *logr);
|
||||
u32 get_undo_offset(const LOG_RECORD *logr);
|
||||
u32 get_redo_offset(const LOG_RECORD *logr);
|
||||
u32 get_extra_offset(const LOG_RECORD *logr);
|
||||
BOOL exception(int num);
|
||||
|
||||
struct STORE;
|
||||
BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp);
|
||||
extern int play_undos(ntfs_volume *vol, const struct ACTION_RECORD *firstundo);
|
||||
extern int play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstredo);
|
||||
extern void show_redos(void);
|
||||
|
|
|
@ -88,7 +88,7 @@ To enlarge an NTFS filesystem, first you must enlarge the size of the
|
|||
underlying partition. This can be done using
|
||||
.BR fdisk (8)
|
||||
by deleting the partition and recreating it with a larger size.
|
||||
Make sure it will not overlap with an other existing partition.
|
||||
Make sure it will not overlap with another existing partition.
|
||||
You may enlarge upwards (first sector unchanged) or downwards (last
|
||||
sector unchanged), but you may not enlarge at both ends in a single step.
|
||||
If you merge two NTFS partitions, only one of them can be expanded to the
|
||||
|
|
|
@ -2377,6 +2377,7 @@ static void truncate_badclust_bad_attr(ntfs_resize_t *resize)
|
|||
{
|
||||
ntfs_inode *base_ni;
|
||||
ntfs_attr *na;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
s64 nr_clusters = resize->new_volume_size;
|
||||
ntfs_volume *vol = resize->vol;
|
||||
|
||||
|
@ -2390,7 +2391,17 @@ static void truncate_badclust_bad_attr(ntfs_resize_t *resize)
|
|||
err_printf("Could not adjust the bad sector list\n");
|
||||
exit(1);
|
||||
}
|
||||
na->ni->flags = le32_or(na->ni->flags, FILE_ATTR_SPARSE_FILE);
|
||||
/* Clear the sparse flags, even if there are bad clusters */
|
||||
na->ni->flags =
|
||||
le32_and(na->ni->flags, le32_not(FILE_ATTR_SPARSE_FILE));
|
||||
na->data_flags = le16_and(na->data_flags, le16_not(ATTR_IS_SPARSE));
|
||||
ctx = resize->ctx;
|
||||
ctx->attr->data_size = cpu_to_sle64(na->data_size);
|
||||
ctx->attr->initialized_size = cpu_to_sle64(na->initialized_size);
|
||||
ctx->attr->flags = cpu_to_le16(na->data_flags);
|
||||
ctx->attr->compression_unit = 0;
|
||||
ntfs_inode_mark_dirty(ctx->ntfs_ino);
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
NInoFileNameSetDirty(na->ni);
|
||||
|
||||
ntfs_attr_close(na);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
.\" Copyright (c) 2007-2009 Jean-Pierre André.
|
||||
.\" Copyright (c) 2007-2016 Jean-Pierre André.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFS-3G.SECAUDIT 8 "February 2010" "ntfs-3g.secaudit 1.4.1"
|
||||
.TH NTFSSECAUDIT 8 "February 2010" "ntfssecaudit 1.5.0"
|
||||
.SH NAME
|
||||
ntfs-3g.secaudit \- NTFS Security Data Auditing
|
||||
ntfssecaudit \- NTFS Security Data Auditing
|
||||
.SH SYNOPSIS
|
||||
.B ntfs-3g.secaudit
|
||||
.B ntfssecaudit
|
||||
\fB[\fIoptions\fP\fB]\fR
|
||||
.I args
|
||||
.PP
|
||||
|
@ -39,7 +39,7 @@ and args define the parameters and the set of files acted upon.
|
|||
.PP
|
||||
Typing secaudit with no args will display a summary of available options.
|
||||
.SH DESCRIPTION
|
||||
\fBntfs-3g.secaudit\fR
|
||||
\fBntfssecaudit\fR
|
||||
displays the ownership and permissions of a set of files on an NTFS
|
||||
file system, and checks their consistency. It can be started in terminal
|
||||
mode only (no graphical user interface is available.)
|
||||
|
@ -53,7 +53,7 @@ of information. It is therefore advisable to redirect the output to
|
|||
a file or pipe it to a text editor for examination.
|
||||
.SH OPTIONS
|
||||
Below are the valid combinations of options and arguments that
|
||||
\fBntfs-3g.secaudit\fR accepts. All the indicated arguments are
|
||||
\fBntfssecaudit\fR accepts. All the indicated arguments are
|
||||
mandatory and must be unique (if wildcards are used, they must
|
||||
resolve to a single name.)
|
||||
.TP
|
||||
|
@ -135,25 +135,25 @@ Example : "\fBu::7,g::5,o:0,u:510:rwx,g:500:5,d:u:510:7\fP"
|
|||
Audit the global security data on /dev/sda1
|
||||
.RS
|
||||
.sp
|
||||
.B ntfs-3g.secaudit -ar /dev/sda1
|
||||
.B ntfssecaudit -ar /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
Display the ownership and permissions parameters for files in directory
|
||||
/audio/music on device /dev/sda5, excluding sub-directories :
|
||||
.RS
|
||||
.sp
|
||||
.B ntfs-3g.secaudit /dev/sda5 /audio/music
|
||||
.B ntfssecaudit /dev/sda5 /audio/music
|
||||
.sp
|
||||
.RE
|
||||
Set all files in directory /audio/music on device /dev/sda5 as writeable
|
||||
by owner and read-only for everybody :
|
||||
.RS
|
||||
.sp
|
||||
.B ntfs-3g.secaudit -r /dev/sda5 644 /audio/music
|
||||
.B ntfssecaudit -r /dev/sda5 644 /audio/music
|
||||
.sp
|
||||
.RE
|
||||
.SH EXIT CODES
|
||||
.B ntfs-3g.secaudit
|
||||
.B ntfssecaudit
|
||||
exits with a value of 0 when no error was detected, and with a value
|
||||
of 1 when an error was detected.
|
||||
.SH KNOWN ISSUES
|
||||
|
@ -170,7 +170,7 @@ in detail. You can contact the
|
|||
development team on the ntfs\-3g\-devel@lists.sf.net
|
||||
address.
|
||||
.SH AUTHORS
|
||||
.B ntfs-3g.secaudit
|
||||
.B ntfssecaudit
|
||||
has been developed by Jean-Pierre André.
|
||||
.SH THANKS
|
||||
Several people made heroic efforts, often over five or more
|
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,11 @@
|
|||
.\" Copyright (c) 2007-2009 Jean-Pierre André.
|
||||
.\" Copyright (c) 2007-2016 Jean-Pierre André.
|
||||
.\" This file may be copied under the terms of the GNU Public License.
|
||||
.\"
|
||||
.TH NTFS-3G.USERMAP 8 "February 2010" "ntfs-3g.usermap 1.1.2"
|
||||
.TH NTFSUSERMAP 8 "February 2016" "ntfsusermap 1.2.0"
|
||||
.SH NAME
|
||||
ntfs-3g.usermap \- NTFS Building a User Mapping File
|
||||
ntfsusermap \- NTFS Building a User Mapping File
|
||||
.SH SYNOPSIS
|
||||
.B ntfs-3g.usermap
|
||||
.B ntfsusermap
|
||||
\fIwindows-system-device\fP
|
||||
\fB[\fIother-ntfs-device\fP...\fB]\fR
|
||||
.PP
|
||||
|
@ -15,13 +15,13 @@ whose users are to be mapped to current Linux system.
|
|||
And \fIother-ntfs-device\fP is another device containing files which are
|
||||
to be accessed both by the Windows mentioned above and current Linux system.
|
||||
.PP
|
||||
the ntfs-3g.usermap command must be started as root, and the designated devices
|
||||
the ntfsusermap command must be started as root, and the designated devices
|
||||
must not be mounted.
|
||||
.PP
|
||||
Typing ntfs-3g.usermap with no args will display a summary of command
|
||||
Typing ntfsusermap with no args will display a summary of command
|
||||
arguments.
|
||||
.SH DESCRIPTION
|
||||
\fBntfs-3g.usermap\fR
|
||||
\fBntfsusermap\fR
|
||||
creates the file defining the mapping of Windows accounts to Linux logins for
|
||||
users who owns files which should be visible from both Windows and
|
||||
Linux.
|
||||
|
@ -44,7 +44,7 @@ The mappings for standard Windows users, such as "Administrator" or
|
|||
"All Users" are defined implicitly. As a consequence a user mapping should
|
||||
never be defined as Linux root.
|
||||
.PP
|
||||
When there are no more significant files, ntfs-3g.usermap create the
|
||||
When there are no more significant files, ntfsusermap create the
|
||||
mapping file into the file UserMapping in the current directory. This
|
||||
file has to be moved to the hidden directory .NTFS-3G in the root of
|
||||
all the NTFS file systems to be shared between Windows and Linux. This
|
||||
|
@ -53,19 +53,19 @@ be taken into account if not present at mount time, which means the
|
|||
file system has to be unmounted and mounted again for the new mapping
|
||||
file to be taken into account.
|
||||
.SH OPTIONS
|
||||
No option is defined for ntfs-3g.usermap.
|
||||
No option is defined for ntfsusermap.
|
||||
.SH EXAMPLES
|
||||
Map the users defined on the Windows system present on /dev/sda1 :
|
||||
.RS
|
||||
.sp
|
||||
.B ntfs-3g.usermap /dev/sda1
|
||||
.B ntfsusermap /dev/sda1
|
||||
.sp
|
||||
.RE
|
||||
.PP
|
||||
A detailed example, with screen displays is available on
|
||||
http://pagesperso-orange.fr/b.andre/usermap.html
|
||||
http://jp-andre.pagesperso-orange.fr/ntfsusermap.html
|
||||
.SH EXIT CODES
|
||||
.B ntfs-3g.usermap
|
||||
.B ntfsusermap
|
||||
exits with a value of 0 when no error was detected, and with a value
|
||||
of 1 when an error was detected.
|
||||
.SH KNOWN ISSUES
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Redo or undo a list of logged actions
|
||||
*
|
||||
* Copyright (c) 2014-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2014-2016 Jean-Pierre Andre
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -67,6 +67,7 @@
|
|||
#include "volume.h"
|
||||
#include "unistr.h"
|
||||
#include "mst.h"
|
||||
#include "logfile.h"
|
||||
#include "ntfsrecover.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
@ -117,11 +118,11 @@ static void locate(const char *s, int n, const char *p, int m)
|
|||
}
|
||||
*/
|
||||
|
||||
static u64 inode_number(const struct LOG_RECORD *logr)
|
||||
static u64 inode_number(const LOG_RECORD *logr)
|
||||
{
|
||||
u64 offset;
|
||||
|
||||
offset = ((u64)le32_to_cpu(logr->target_vcn)
|
||||
offset = ((u64)le64_to_cpu(logr->target_vcn)
|
||||
<< clusterbits)
|
||||
+ ((u32)le16_to_cpu(logr->cluster_index)
|
||||
<< NTFS_BLOCK_SIZE_BITS);
|
||||
|
@ -409,7 +410,7 @@ static int sanity_indx(ntfs_volume *vol, const char *buffer)
|
|||
* With option -n reading is first attempted from the memory store
|
||||
*/
|
||||
|
||||
static char *read_raw(ntfs_volume *vol, const struct LOG_RECORD *logr)
|
||||
static char *read_raw(ntfs_volume *vol, const LOG_RECORD *logr)
|
||||
{
|
||||
char *buffer;
|
||||
char *target;
|
||||
|
@ -477,7 +478,7 @@ static char *read_raw(ntfs_volume *vol, const struct LOG_RECORD *logr)
|
|||
* With option -n a copy of the buffer is kept in memory for later use.
|
||||
*/
|
||||
|
||||
static int write_raw(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
||||
static int write_raw(ntfs_volume *vol, const LOG_RECORD *logr,
|
||||
char *buffer)
|
||||
{
|
||||
int err;
|
||||
|
@ -532,7 +533,7 @@ static int write_raw(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
|||
* Write a full set of raw clusters to mft_mirr
|
||||
*/
|
||||
|
||||
static int write_mirr(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
||||
static int write_mirr(ntfs_volume *vol, const LOG_RECORD *logr,
|
||||
char *buffer)
|
||||
{
|
||||
int err;
|
||||
|
@ -548,7 +549,7 @@ static int write_mirr(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
|||
if (!optn) {
|
||||
for (i=0; (i<count) && !err; i++) {
|
||||
lcn = ntfs_attr_vcn_to_lcn(vol->mftmirr_na,
|
||||
le32_to_cpu(logr->target_vcn) + i);
|
||||
le64_to_cpu(logr->target_vcn) + i);
|
||||
source = buffer + clustersz*i;
|
||||
if ((lcn < 0)
|
||||
|| (ntfs_pwrite(vol->dev, lcn << clusterbits,
|
||||
|
@ -566,7 +567,7 @@ static int write_mirr(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
|||
* Allocate a buffer and read a single protected record
|
||||
*/
|
||||
|
||||
static char *read_protected(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
||||
static char *read_protected(ntfs_volume *vol, const LOG_RECORD *logr,
|
||||
u32 size, BOOL warn)
|
||||
{
|
||||
char *buffer;
|
||||
|
@ -614,7 +615,7 @@ static char *read_protected(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
|||
* than a cluster, have to read, merge and write.
|
||||
*/
|
||||
|
||||
static int write_protected(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
||||
static int write_protected(ntfs_volume *vol, const LOG_RECORD *logr,
|
||||
char *buffer, u32 size)
|
||||
{
|
||||
MFT_RECORD *record;
|
||||
|
@ -640,15 +641,15 @@ static int write_protected(ntfs_volume *vol, const struct LOG_RECORD *logr,
|
|||
"older" : "newer"),
|
||||
(long long)sle64_to_cpu(logr->this_lsn));
|
||||
if (optv > 1)
|
||||
printf("mft vcn %ld index %d\n",
|
||||
(long)le32_to_cpu(logr->target_vcn),
|
||||
printf("mft vcn %lld index %d\n",
|
||||
(long long)le64_to_cpu(logr->target_vcn),
|
||||
(int)le16_to_cpu(logr->cluster_index));
|
||||
err = sanity_mft(buffer);
|
||||
/* Should set to some previous lsn for undos */
|
||||
if (opts)
|
||||
record->lsn = logr->this_lsn;
|
||||
/* Duplicate on mftmirr if not overflowing its size */
|
||||
mftmirr = (((u64)le32_to_cpu(logr->target_vcn)
|
||||
mftmirr = (((u64)le64_to_cpu(logr->target_vcn)
|
||||
+ le16_to_cpu(logr->lcns_to_follow))
|
||||
<< clusterbits)
|
||||
<= (((u64)vol->mftmirr_size) << mftrecbits);
|
||||
|
@ -1786,7 +1787,7 @@ static int create_indx(ntfs_volume *vol, const struct ACTION_RECORD *action,
|
|||
indx->usa_ofs = const_cpu_to_le16(0x28);
|
||||
indx->usa_count = const_cpu_to_le16(9);
|
||||
indx->lsn = action->record.this_lsn;
|
||||
vcn = le32_to_cpu(action->record.target_vcn);
|
||||
vcn = le64_to_cpu(action->record.target_vcn);
|
||||
/* beware of size change on big-endian cpus */
|
||||
indx->index_block_vcn = cpu_to_sle64(vcn);
|
||||
/* INDEX_HEADER */
|
||||
|
@ -2309,8 +2310,8 @@ static int redo_open_attribute(ntfs_volume *vol __attribute__((unused)),
|
|||
{
|
||||
const char *data;
|
||||
struct ATTR *pa;
|
||||
const struct ATTR_OLD *attr_old;
|
||||
const struct ATTR_NEW *attr_new;
|
||||
const ATTR_OLD *attr_old;
|
||||
const ATTR_NEW *attr_new;
|
||||
const char *name;
|
||||
le64 inode;
|
||||
u32 namelen;
|
||||
|
@ -2349,15 +2350,15 @@ static int redo_open_attribute(ntfs_volume *vol __attribute__((unused)),
|
|||
* whether it matches what we have in store.
|
||||
*/
|
||||
switch (length) {
|
||||
case sizeof(struct ATTR_OLD) :
|
||||
attr_old = (const struct ATTR_OLD*)data;
|
||||
case sizeof(ATTR_OLD) :
|
||||
attr_old = (const ATTR_OLD*)data;
|
||||
/* Badly aligned */
|
||||
memcpy(&inode, &attr_old->inode, 8);
|
||||
err = (MREF(le64_to_cpu(inode)) != pa->inode)
|
||||
|| !le32_eq(attr_old->type, pa->type);
|
||||
break;
|
||||
case sizeof(struct ATTR_NEW) :
|
||||
attr_new = (const struct ATTR_NEW*)data;
|
||||
case sizeof(ATTR_NEW) :
|
||||
attr_new = (const ATTR_NEW*)data;
|
||||
err = (MREF(le64_to_cpu(attr_new->inode))
|
||||
!= pa->inode)
|
||||
|| !le32_eq(attr_new->type, pa->type);
|
||||
|
@ -3379,8 +3380,8 @@ static int undo_open_attribute(ntfs_volume *vol __attribute__((unused)),
|
|||
{
|
||||
const char *data;
|
||||
struct ATTR *pa;
|
||||
const struct ATTR_OLD *attr_old;
|
||||
const struct ATTR_NEW *attr_new;
|
||||
const ATTR_OLD *attr_old;
|
||||
const ATTR_NEW *attr_new;
|
||||
const char *name;
|
||||
le64 inode;
|
||||
u32 namelen;
|
||||
|
@ -3415,15 +3416,15 @@ static int undo_open_attribute(ntfs_volume *vol __attribute__((unused)),
|
|||
if (pa) {
|
||||
/* check whether the redo attr matches what we have in store */
|
||||
switch (length) {
|
||||
case sizeof(struct ATTR_OLD) :
|
||||
attr_old = (const struct ATTR_OLD*)data;
|
||||
case sizeof(ATTR_OLD) :
|
||||
attr_old = (const ATTR_OLD*)data;
|
||||
/* Badly aligned */
|
||||
memcpy(&inode, &attr_old->inode, 8);
|
||||
err = (MREF(le64_to_cpu(inode)) != pa->inode)
|
||||
|| !le32_eq(attr_old->type, pa->type);
|
||||
break;
|
||||
case sizeof(struct ATTR_NEW) :
|
||||
attr_new = (const struct ATTR_NEW*)data;
|
||||
case sizeof(ATTR_NEW) :
|
||||
attr_new = (const ATTR_NEW*)data;
|
||||
err = (MREF(le64_to_cpu(attr_new->inode))!= pa->inode)
|
||||
|| !le32_eq(attr_new->type, pa->type);
|
||||
break;
|
||||
|
@ -3991,13 +3992,12 @@ static enum ACTION_KIND get_action_kind(const struct ACTION_RECORD *action)
|
|||
* the action was defined by Win10 (or subsequent).
|
||||
*/
|
||||
if (!le16_andz(action->record.log_record_flags,
|
||||
const_cpu_to_le16(RECORD_DELETING | RECORD_ADDING))) {
|
||||
if (!le16_andz(action->record.attribute_flags,
|
||||
const_cpu_to_le16(ACTS_ON_INDX)))
|
||||
le16_or(LOG_RECORD_DELETING, LOG_RECORD_ADDING))) {
|
||||
if (!le16_andz(action->record.attribute_flags, ACTS_ON_INDX))
|
||||
kind = ON_INDX;
|
||||
else
|
||||
if (!le16_andz(action->record.attribute_flags,
|
||||
const_cpu_to_le16(ACTS_ON_MFT)))
|
||||
ACTS_ON_MFT))
|
||||
kind = ON_MFT;
|
||||
else
|
||||
kind = ON_RAW;
|
||||
|
@ -4325,7 +4325,7 @@ static int play_one_redo(ntfs_volume *vol, const struct ACTION_RECORD *action)
|
|||
case ON_MFT :
|
||||
/*
|
||||
the check below cannot be used on WinXP
|
||||
if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_MFT)))
|
||||
if (!(action->record.attribute_flags & ACTS_ON_MFT))
|
||||
printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num);
|
||||
*/
|
||||
/* Check whether data is to be discarded */
|
||||
|
@ -4366,7 +4366,7 @@ printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num)
|
|||
case ON_INDX :
|
||||
/*
|
||||
the check below cannot be used on WinXP
|
||||
if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_INDX)))
|
||||
if (!(action->record.attribute_flags & ACTS_ON_INDX))
|
||||
printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num);
|
||||
*/
|
||||
xsize = vol->indx_record_size;
|
||||
|
@ -4407,7 +4407,7 @@ printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num
|
|||
break;
|
||||
case ON_RAW :
|
||||
if (!le16_andz(action->record.attribute_flags,
|
||||
(const_cpu_to_le16(ACTS_ON_INDX | ACTS_ON_MFT)))) {
|
||||
le16_or(ACTS_ON_INDX, ACTS_ON_MFT))) {
|
||||
printf("** Error : action %s on MFT"
|
||||
" or INDX\n",
|
||||
actionname(rop));
|
||||
|
@ -4707,7 +4707,7 @@ static int play_one_undo(ntfs_volume *vol, const struct ACTION_RECORD *action)
|
|||
case ON_MFT :
|
||||
/*
|
||||
the check below cannot be used on WinXP
|
||||
if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_MFT)))
|
||||
if (!(action->record.attribute_flags & ACTS_ON_MFT))
|
||||
printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num);
|
||||
*/
|
||||
buffer = read_protected(vol, &action->record, mftrecsz, TRUE);
|
||||
|
@ -4731,16 +4731,22 @@ printf("record lsn 0x%llx is %s than action %d lsn 0x%llx\n",
|
|||
err = 1;
|
||||
}
|
||||
} else {
|
||||
/* Undoing a record create which was not done ? */
|
||||
// TODO make sure this is about a newly allocated record (with bad fixup)
|
||||
// TODO check this is inputting a full record (record lth == data lth)
|
||||
buffer = (char*)calloc(1, mftrecsz);
|
||||
/*
|
||||
* Could not read the MFT record :
|
||||
* if this is undoing a record create (from scratch)
|
||||
* which did not take place, there is nothing to redo,
|
||||
* otherwise this is an error.
|
||||
*/
|
||||
if (check_full_mft(action,TRUE))
|
||||
executed = FALSE;
|
||||
else
|
||||
err = 1;
|
||||
}
|
||||
break;
|
||||
case ON_INDX :
|
||||
/*
|
||||
the check below cannot be used on WinXP
|
||||
if (!(action->record.attribute_flags & const_cpu_to_le16(ACTS_ON_INDX)))
|
||||
if (!(action->record.attribute_flags & ACTS_ON_INDX))
|
||||
printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num);
|
||||
*/
|
||||
xsize = vol->indx_record_size;
|
||||
|
@ -4765,18 +4771,33 @@ printf("index lsn 0x%llx is %s than action %d lsn 0x%llx\n",
|
|||
err = 1;
|
||||
}
|
||||
} else {
|
||||
/* Undoing a record create which was not done ? */
|
||||
// TODO make sure this is about a newly allocated record (with bad fixup)
|
||||
// TODO check this is inputting a full record (record lth == data lth)
|
||||
// recreate an INDX record if this is the first entry
|
||||
buffer = (char*)calloc(1, xsize);
|
||||
err = create_indx(vol, action, buffer);
|
||||
executed = TRUE;
|
||||
/*
|
||||
* Could not read the INDX record :
|
||||
* if this is undoing a record create (from scratch)
|
||||
* which did not take place, there is nothing to redo,
|
||||
* otherwise this must be an error.
|
||||
* However, after deleting the last index allocation
|
||||
* in a block, the block is apparently zeroed
|
||||
* and cannot be read. In this case we have to
|
||||
* create an initial index block and apply the undo.
|
||||
*/
|
||||
if (check_full_index(action,TRUE))
|
||||
executed = FALSE;
|
||||
else {
|
||||
err = 1;
|
||||
if (uop == AddIndexEntryAllocation) {
|
||||
executed = TRUE;
|
||||
buffer = (char*)calloc(1, xsize);
|
||||
if (buffer)
|
||||
err = create_indx(vol,
|
||||
action, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ON_RAW :
|
||||
if (!le16_andz(action->record.attribute_flags,
|
||||
(const_cpu_to_le16(ACTS_ON_INDX | ACTS_ON_MFT)))) {
|
||||
le16_or(ACTS_ON_INDX, ACTS_ON_MFT))) {
|
||||
printf("** Error : action %s on MFT or INDX\n",
|
||||
actionname(rop));
|
||||
err = 1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
EXTRA_DIST = secaudit.h ntfs-3g_common.h
|
||||
EXTRA_DIST = ntfs-3g_common.h
|
||||
|
||||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
|
@ -11,18 +11,19 @@ FUSE_CFLAGS = $(FUSE_MODULE_CFLAGS)
|
|||
FUSE_LIBS = $(FUSE_MODULE_LIBS)
|
||||
endif
|
||||
|
||||
if !DISABLE_PLUGINS
|
||||
plugindir = $(libdir)/ntfs-3g
|
||||
PLUGIN_CFLAGS = -DPLUGIN_DIR=\"$(plugindir)\"
|
||||
endif
|
||||
|
||||
if ENABLE_NTFS_3G
|
||||
|
||||
bin_PROGRAMS = ntfs-3g.probe \
|
||||
ntfs-3g.usermap \
|
||||
ntfs-3g.secaudit
|
||||
bin_PROGRAMS = ntfs-3g.probe
|
||||
rootbin_PROGRAMS = ntfs-3g lowntfs-3g
|
||||
rootsbin_DATA = #Create directory
|
||||
man_MANS = ntfs-3g.8 ntfs-3g.probe.8 \
|
||||
ntfs-3g.usermap.8 \
|
||||
ntfs-3g.secaudit.8
|
||||
man_MANS = ntfs-3g.8 ntfs-3g.probe.8
|
||||
|
||||
ntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
ntfs_3g_LDADD = $(LIBDL) $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
if REALLYSTATIC
|
||||
ntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static
|
||||
endif
|
||||
|
@ -30,10 +31,11 @@ ntfs_3g_CFLAGS = \
|
|||
$(AM_CFLAGS) \
|
||||
-DFUSE_USE_VERSION=26 \
|
||||
$(FUSE_CFLAGS) \
|
||||
-I$(top_srcdir)/include/ntfs-3g
|
||||
-I$(top_srcdir)/include/ntfs-3g \
|
||||
$(PLUGIN_CFLAGS)
|
||||
ntfs_3g_SOURCES = ntfs-3g.c ntfs-3g_common.c
|
||||
|
||||
lowntfs_3g_LDADD = $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
lowntfs_3g_LDADD = $(LIBDL) $(FUSE_LIBS) $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
if REALLYSTATIC
|
||||
lowntfs_3g_LDFLAGS = $(AM_LDFLAGS) -all-static
|
||||
endif
|
||||
|
@ -41,30 +43,26 @@ lowntfs_3g_CFLAGS = \
|
|||
$(AM_CFLAGS) \
|
||||
-DFUSE_USE_VERSION=26 \
|
||||
$(FUSE_CFLAGS) \
|
||||
-I$(top_srcdir)/include/ntfs-3g
|
||||
-I$(top_srcdir)/include/ntfs-3g \
|
||||
$(PLUGIN_CFLAGS)
|
||||
lowntfs_3g_SOURCES = lowntfs-3g.c ntfs-3g_common.c
|
||||
|
||||
ntfs_3g_probe_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
ntfs_3g_usermap_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
ntfs_3g_secaudit_LDADD = $(top_builddir)/libntfs-3g/libntfs-3g.la
|
||||
if REALLYSTATIC
|
||||
ntfs_3g_probe_LDFLAGS = $(AM_LDFLAGS) -all-static
|
||||
ntfs_3g_usermap_LDFLAGS = $(AM_LDFLAGS) -all-static
|
||||
ntfs_3g_secaudit_LDFLAGS = $(AM_LDFLAGS) -all-static
|
||||
endif
|
||||
ntfs_3g_probe_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g
|
||||
ntfs_3g_usermap_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g
|
||||
ntfs_3g_secaudit_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g
|
||||
ntfs_3g_probe_SOURCES = ntfs-3g.probe.c
|
||||
ntfs_3g_usermap_SOURCES = usermap.c
|
||||
ntfs_3g_secaudit_SOURCES = secaudit.c
|
||||
|
||||
drivers : $(FUSE_LIBS) ntfs-3g lowntfs-3g
|
||||
|
||||
if RUN_LDCONFIG
|
||||
install-exec-hook:
|
||||
if RUN_LDCONFIG
|
||||
$(LDCONFIG)
|
||||
endif
|
||||
if !DISABLE_PLUGINS
|
||||
$(MKDIR_P) $(DESTDIR)/$(plugindir)
|
||||
endif
|
||||
|
||||
if ENABLE_MOUNT_HELPER
|
||||
install-exec-local: install-rootbinPROGRAMS
|
||||
|
|
470
src/lowntfs-3g.c
470
src/lowntfs-3g.c
|
@ -4,7 +4,7 @@
|
|||
* Copyright (c) 2005-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2005 Yuval Fledel
|
||||
* Copyright (c) 2006-2009 Szabolcs Szakacsits
|
||||
* Copyright (c) 2007-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2017 Jean-Pierre Andre
|
||||
* Copyright (c) 2009 Erik Larsson
|
||||
*
|
||||
* This file is originated from the Linux-NTFS project.
|
||||
|
@ -73,9 +73,12 @@
|
|||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MKDEV_H
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#include <sys/dirent.h>
|
||||
|
@ -87,6 +90,10 @@
|
|||
#include <linux/fs.h>
|
||||
#endif
|
||||
|
||||
#ifndef FUSE_CAP_POSIX_ACL /* until defined in <fuse/fuse_common.h> */
|
||||
#define FUSE_CAP_POSIX_ACL (1 << 18)
|
||||
#endif /* FUSE_CAP_POSIX_ACL */
|
||||
|
||||
#include "compat.h"
|
||||
#include "bitmap.h"
|
||||
#include "attrib.h"
|
||||
|
@ -105,6 +112,7 @@
|
|||
#include "xattrs.h"
|
||||
#include "misc.h"
|
||||
#include "ioctl.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#include "ntfs-3g_common.h"
|
||||
|
||||
|
@ -136,13 +144,18 @@
|
|||
* FUSE cacheing is only usable with basic permissions
|
||||
* checked by the kernel with external fuse >= 2.8
|
||||
*/
|
||||
#if KERNELACLS | !KERNELPERMS
|
||||
#if !KERNELPERMS
|
||||
#warning "Fuse cacheing is only usable with basic permissions checked by kernel"
|
||||
#endif
|
||||
#define ATTR_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
|
||||
#define ENTRY_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
|
||||
#if KERNELACLS
|
||||
#define ATTR_TIMEOUT 10.0
|
||||
#define ENTRY_TIMEOUT 10.0
|
||||
#else /* KERNELACLS */
|
||||
#define ATTR_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 10.0 : 0.0)
|
||||
#define ENTRY_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 10.0 : 0.0)
|
||||
#endif /* KERNELACLS */
|
||||
#endif /* defined(__sun) && defined (__SVR4) */
|
||||
#endif
|
||||
#endif /* !CACHEING */
|
||||
#define GHOSTLTH 40 /* max length of a ghost file name - see ghostformat */
|
||||
|
||||
/* sometimes the kernel cannot check access */
|
||||
|
@ -157,6 +170,22 @@
|
|||
#define set_archive(ni) (ni)->flags = le32_or((ni)->flags, FILE_ATTR_ARCHIVE)
|
||||
#define INODE(ino) ((ino) == 1 ? (MFT_REF)FILE_root : (MFT_REF)(ino))
|
||||
|
||||
/*
|
||||
* Call a function from a reparse plugin (variable arguments)
|
||||
* Requires "reparse" and "ops" to have been defined
|
||||
*
|
||||
* Returns a non-negative value if successful,
|
||||
* and a negative error code if something fails.
|
||||
*/
|
||||
#define CALL_REPARSE_PLUGIN(ni, op_name, ...) \
|
||||
(reparse = (REPARSE_POINT*)NULL, \
|
||||
ops = select_reparse_plugin(ctx, ni, &reparse), \
|
||||
(!ops ? -errno \
|
||||
: (ops->op_name ? \
|
||||
ops->op_name(ni, reparse, __VA_ARGS__) \
|
||||
: -EOPNOTSUPP))), \
|
||||
free(reparse)
|
||||
|
||||
typedef enum {
|
||||
FSTYPE_NONE,
|
||||
FSTYPE_UNKNOWN,
|
||||
|
@ -187,13 +216,17 @@ struct open_file {
|
|||
fuse_ino_t ino;
|
||||
fuse_ino_t parent;
|
||||
int state;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
struct fuse_file_info fi;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
} ;
|
||||
|
||||
enum {
|
||||
CLOSE_GHOST = 1,
|
||||
CLOSE_COMPRESSED = 2,
|
||||
CLOSE_ENCRYPTED = 4,
|
||||
CLOSE_DMTIME = 8
|
||||
CLOSE_DMTIME = 8,
|
||||
CLOSE_REPARSE = 16
|
||||
};
|
||||
|
||||
enum RM_TYPES {
|
||||
|
@ -227,7 +260,7 @@ static const char *usage_msg =
|
|||
"\n"
|
||||
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
|
||||
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
|
||||
"Copyright (C) 2007-2016 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2007-2017 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2009 Erik Larsson\n"
|
||||
"\n"
|
||||
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
|
||||
|
@ -587,6 +620,10 @@ static void ntfs_init(void *userdata __attribute__((unused)),
|
|||
/* request umask not to be enforced by fuse */
|
||||
conn->want |= FUSE_CAP_DONT_MASK;
|
||||
#endif /* defined FUSE_CAP_DONT_MASK */
|
||||
#if POSIXACLS & KERNELACLS
|
||||
/* request ACLs to be checked by kernel */
|
||||
conn->want |= FUSE_CAP_POSIX_ACL;
|
||||
#endif /* POSIXACLS & KERNELACLS */
|
||||
#ifdef FUSE_CAP_BIG_WRITES
|
||||
if (ctx->big_writes
|
||||
&& ((ctx->vol->nr_clusters << ctx->vol->cluster_size_bits)
|
||||
|
@ -598,6 +635,65 @@ static void ntfs_init(void *userdata __attribute__((unused)),
|
|||
#endif /* defined(FUSE_CAP_IOCTL_DIR) */
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
/*
|
||||
* Define attributes for a junction or symlink
|
||||
* (internal plugin)
|
||||
*/
|
||||
|
||||
static int junction_getstat(ntfs_inode *ni,
|
||||
const REPARSE_POINT *reparse __attribute__((unused)),
|
||||
struct stat *stbuf)
|
||||
{
|
||||
char *target;
|
||||
int res;
|
||||
|
||||
errno = 0;
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
/*
|
||||
* If the reparse point is not a valid
|
||||
* directory junction, and there is no error
|
||||
* we still display as a symlink
|
||||
*/
|
||||
if (target || (errno == EOPNOTSUPP)) {
|
||||
if (target)
|
||||
stbuf->st_size = strlen(target);
|
||||
else
|
||||
stbuf->st_size = sizeof(ntfs_bad_reparse) - 1;
|
||||
stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_mode = S_IFLNK;
|
||||
free(target);
|
||||
res = 0;
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply permission masks to st_mode returned by reparse handler
|
||||
*/
|
||||
|
||||
static void apply_umask(struct stat *stbuf)
|
||||
{
|
||||
switch (stbuf->st_mode & S_IFMT) {
|
||||
case S_IFREG :
|
||||
stbuf->st_mode &= ~ctx->fmask;
|
||||
break;
|
||||
case S_IFDIR :
|
||||
stbuf->st_mode &= ~ctx->dmask;
|
||||
break;
|
||||
case S_IFLNK :
|
||||
stbuf->st_mode = (stbuf->st_mode & S_IFMT) | 0777;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
||||
ntfs_inode *ni, struct stat *stbuf)
|
||||
{
|
||||
|
@ -607,27 +703,42 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
|||
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL);
|
||||
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||
if (!le16_andz(ni->mrec->flags, MFT_RECORD_IS_DIRECTORY)
|
||||
|| !le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
res = CALL_REPARSE_PLUGIN(ni, getattr, stbuf);
|
||||
if (!res) {
|
||||
apply_umask(stbuf);
|
||||
} else {
|
||||
stbuf->st_size =
|
||||
sizeof(ntfs_bad_reparse) - 1;
|
||||
stbuf->st_blocks =
|
||||
(ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_mode = S_IFLNK;
|
||||
res = 0;
|
||||
}
|
||||
goto ok;
|
||||
#else /* DISABLE_PLUGINS */
|
||||
char *target;
|
||||
int attr_size;
|
||||
|
||||
errno = 0;
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point,
|
||||
&attr_size);
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
/*
|
||||
* If the reparse point is not a valid
|
||||
* directory junction, and there is no error
|
||||
* we still display as a symlink
|
||||
*/
|
||||
if (target || (errno == EOPNOTSUPP)) {
|
||||
/* returning attribute size */
|
||||
if (target)
|
||||
stbuf->st_size = attr_size;
|
||||
stbuf->st_size = strlen(target);
|
||||
else
|
||||
stbuf->st_size =
|
||||
sizeof(ntfs_bad_reparse);
|
||||
sizeof(ntfs_bad_reparse) - 1;
|
||||
stbuf->st_blocks =
|
||||
(ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_nlink =
|
||||
|
@ -638,6 +749,7 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
} else {
|
||||
/* Directory. */
|
||||
stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask);
|
||||
|
@ -676,7 +788,6 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
|||
* See more on the ntfs-3g-devel list.
|
||||
*/
|
||||
stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_SYSTEM)) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
|
@ -734,14 +845,38 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
|||
le64_to_cpu(
|
||||
intx_file->minor));
|
||||
}
|
||||
if (le64_eq(intx_file->magic, INTX_SYMBOLIC_LINK))
|
||||
if (le64_eq(intx_file->magic, INTX_SYMBOLIC_LINK)) {
|
||||
char *target = NULL;
|
||||
int len;
|
||||
|
||||
/* st_size should be set to length of
|
||||
* symlink target as multibyte string */
|
||||
len = ntfs_ucstombs(
|
||||
intx_file->target,
|
||||
(na->data_size -
|
||||
offsetof(INTX_FILE,
|
||||
target)) /
|
||||
sizeof(ntfschar),
|
||||
&target, 0);
|
||||
if (len < 0) {
|
||||
res = -errno;
|
||||
free(intx_file);
|
||||
ntfs_attr_close(na);
|
||||
goto exit;
|
||||
}
|
||||
free(target);
|
||||
stbuf->st_mode = S_IFLNK;
|
||||
stbuf->st_size = len;
|
||||
}
|
||||
free(intx_file);
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
stbuf->st_mode |= (0777 & ~ctx->fmask);
|
||||
}
|
||||
#ifndef DISABLE_PLUGINS
|
||||
ok:
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
if (withusermapping) {
|
||||
if (ntfs_get_owner_mode(scx,ni,stbuf) < 0)
|
||||
set_fuse_error(&res);
|
||||
|
@ -884,6 +1019,35 @@ static void ntfs_fuse_lookup(fuse_req_t req, fuse_ino_t parent,
|
|||
fuse_reply_entry(req, &entry);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
/*
|
||||
* Get the link defined by a junction or symlink
|
||||
* (internal plugin)
|
||||
*/
|
||||
|
||||
static int junction_readlink(ntfs_inode *ni,
|
||||
const REPARSE_POINT *reparse __attribute__((unused)),
|
||||
char **pbuf)
|
||||
{
|
||||
int res;
|
||||
|
||||
errno = 0;
|
||||
res = 0;
|
||||
*pbuf = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
if (!*pbuf) {
|
||||
if (errno == EOPNOTSUPP) {
|
||||
*pbuf = strdup(ntfs_bad_reparse);
|
||||
if (!*pbuf)
|
||||
res = -errno;
|
||||
} else
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino)
|
||||
{
|
||||
ntfs_inode *ni = NULL;
|
||||
|
@ -902,18 +1066,28 @@ static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino)
|
|||
* Reparse point : analyze as a junction point
|
||||
*/
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
int attr_size;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
res = CALL_REPARSE_PLUGIN(ni, readlink, &buf);
|
||||
if (res) {
|
||||
buf = strdup(ntfs_bad_reparse);
|
||||
if (!buf)
|
||||
res = -errno;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
errno = 0;
|
||||
res = 0;
|
||||
buf = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size);
|
||||
buf = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
if (!buf) {
|
||||
if (errno == EOPNOTSUPP)
|
||||
buf = strdup(ntfs_bad_reparse);
|
||||
if (!buf)
|
||||
res = -errno;
|
||||
}
|
||||
goto exit;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
/* Sanity checks. */
|
||||
if (le32_andz(ni->flags, FILE_ATTR_SYSTEM)) {
|
||||
|
@ -1266,10 +1440,9 @@ static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino,
|
|||
struct fuse_file_info *fi)
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
ntfs_attr *na;
|
||||
ntfs_attr *na = NULL;
|
||||
struct open_file *of;
|
||||
int state = 0;
|
||||
char *path = NULL;
|
||||
int res = 0;
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
int accesstype;
|
||||
|
@ -1278,56 +1451,77 @@ static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino,
|
|||
|
||||
ni = ntfs_inode_open(ctx->vol, INODE(ino));
|
||||
if (ni) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (na) {
|
||||
if (le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
goto close;
|
||||
}
|
||||
}
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
if (ntfs_fuse_fill_security_context(req, &security)) {
|
||||
if (fi->flags & O_WRONLY)
|
||||
accesstype = S_IWRITE;
|
||||
if (ntfs_fuse_fill_security_context(req, &security)) {
|
||||
if (fi->flags & O_WRONLY)
|
||||
accesstype = S_IWRITE;
|
||||
else
|
||||
if (fi->flags & O_RDWR)
|
||||
accesstype = S_IWRITE | S_IREAD;
|
||||
else
|
||||
if (fi->flags & O_RDWR)
|
||||
accesstype = S_IWRITE | S_IREAD;
|
||||
else
|
||||
accesstype = S_IREAD;
|
||||
/* check whether requested access is allowed */
|
||||
if (!ntfs_allowed_access(&security,
|
||||
ni,accesstype))
|
||||
res = -EACCES;
|
||||
}
|
||||
accesstype = S_IREAD;
|
||||
/* check whether requested access is allowed */
|
||||
if (!ntfs_allowed_access(&security,
|
||||
ni,accesstype))
|
||||
res = -EACCES;
|
||||
}
|
||||
#endif
|
||||
if ((res >= 0)
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR))) {
|
||||
/* mark a future need to compress the last chunk */
|
||||
if (!le16_andz(na->data_flags, ATTR_COMPRESSION_MASK))
|
||||
state |= CLOSE_COMPRESSED;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
/* mark a future need to fixup encrypted inode */
|
||||
if (ctx->efs_raw
|
||||
&& le16_andz(na->data_flags, ATTR_IS_ENCRYPTED)
|
||||
&& !le32_andz(ni->flags, FILE_ATTR_ENCRYPTED))
|
||||
state |= CLOSE_ENCRYPTED;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
/* mark a future need to update the mtime */
|
||||
if (ctx->dmtime)
|
||||
state |= CLOSE_DMTIME;
|
||||
/* deny opening metadata files for writing */
|
||||
if (ino < FILE_first_user)
|
||||
res = -EPERM;
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
fi->fh = 0;
|
||||
res = CALL_REPARSE_PLUGIN(ni, open, fi);
|
||||
if (!res && fi->fh) {
|
||||
state = CLOSE_REPARSE;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
res = -errno;
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto close;
|
||||
}
|
||||
if ((res >= 0)
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR))) {
|
||||
/* mark a future need to compress the last chunk */
|
||||
if (!le16_andz(na->data_flags, ATTR_COMPRESSION_MASK))
|
||||
state |= CLOSE_COMPRESSED;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
/* mark a future need to fixup encrypted inode */
|
||||
if (ctx->efs_raw
|
||||
&& le16_andz(na->data_flags, ATTR_IS_ENCRYPTED)
|
||||
&& !le32_andz(ni->flags, FILE_ATTR_ENCRYPTED))
|
||||
state |= CLOSE_ENCRYPTED;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
/* mark a future need to update the mtime */
|
||||
if (ctx->dmtime)
|
||||
state |= CLOSE_DMTIME;
|
||||
/* deny opening metadata files for writing */
|
||||
if (ino < FILE_first_user)
|
||||
res = -EPERM;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
close:
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
} else
|
||||
res = -errno;
|
||||
free(path);
|
||||
if (res >= 0) {
|
||||
of = (struct open_file*)malloc(sizeof(struct open_file));
|
||||
if (of) {
|
||||
of->parent = 0;
|
||||
of->ino = ino;
|
||||
of->state = state;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
memcpy(&of->fi, fi, sizeof(struct fuse_file_info));
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
of->next = ctx->open_files;
|
||||
of->previous = (struct open_file*)NULL;
|
||||
if (ctx->open_files)
|
||||
|
@ -1368,6 +1562,22 @@ static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
struct open_file *of;
|
||||
|
||||
of = (struct open_file*)(long)fi->fh;
|
||||
res = CALL_REPARSE_PLUGIN(ni, read, buf, size, offset, &of->fi);
|
||||
if (res >= 0) {
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
|
@ -1403,8 +1613,11 @@ static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
|
|||
total += ret;
|
||||
}
|
||||
ok:
|
||||
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME);
|
||||
res = total;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps :
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
@ -1430,6 +1643,23 @@ static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
struct open_file *of;
|
||||
|
||||
of = (struct open_file*)(long)fi->fh;
|
||||
res = CALL_REPARSE_PLUGIN(ni, write, buf, size, offset,
|
||||
&of->fi);
|
||||
if (res >= 0) {
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
|
@ -1446,15 +1676,18 @@ static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
|
|||
total += ret;
|
||||
}
|
||||
res = total;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps :
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
if ((res > 0)
|
||||
&& (!ctx->dmtime
|
||||
|| (sle64_to_cpu(ntfs_current_time())
|
||||
- sle64_to_cpu(ni->last_data_change_time)) > ctx->dmtime))
|
||||
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
|
||||
ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
if (total)
|
||||
if (res > 0)
|
||||
set_archive(ni);
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
|
@ -1607,9 +1840,11 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
|
|||
errno = EPERM;
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na)
|
||||
goto exit;
|
||||
if (le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na)
|
||||
goto exit;
|
||||
}
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
/*
|
||||
* deny truncation if cannot write to file
|
||||
|
@ -1622,6 +1857,21 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
|
|||
goto exit;
|
||||
}
|
||||
#endif
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
res = CALL_REPARSE_PLUGIN(ni, truncate, size);
|
||||
if (!res) {
|
||||
set_archive(ni);
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* for compressed files, upsizing is done by inserting a final
|
||||
* zero, which is optimized as creating a hole when possible.
|
||||
|
@ -1637,8 +1887,11 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
|
|||
goto exit;
|
||||
if (oldsize != size)
|
||||
set_archive(ni);
|
||||
|
||||
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps :
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME);
|
||||
res = ntfs_fuse_getstat(scx, ni, stbuf);
|
||||
errno = (res ? -res : 0);
|
||||
exit:
|
||||
|
@ -1916,10 +2169,15 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
|
|||
uname_len = ntfs_mbstoucs(name, &uname);
|
||||
if ((uname_len < 0)
|
||||
|| (ctx->windows_names
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len))) {
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
/* Deny creating into $Extend */
|
||||
if (parent == FILE_Extend) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
/* Open parent directory. */
|
||||
dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
|
||||
if (!dir_ni) {
|
||||
|
@ -2132,7 +2390,7 @@ static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)),
|
|||
uname_len = ntfs_mbstoucs(newname, &uname);
|
||||
if ((uname_len < 0)
|
||||
|| (ctx->windows_names
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len))) {
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -2211,6 +2469,11 @@ static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name,
|
|||
struct SECURITY_CONTEXT security;
|
||||
#endif
|
||||
|
||||
/* Deny removing from $Extend */
|
||||
if (parent == FILE_Extend) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
/* Open parent directory. */
|
||||
dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
|
||||
if (!dir_ni) {
|
||||
|
@ -2550,8 +2813,8 @@ static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino,
|
|||
of = (struct open_file*)(long)fi->fh;
|
||||
/* Only for marked descriptors there is something to do */
|
||||
if (!of
|
||||
|| !(of->state & (CLOSE_COMPRESSED
|
||||
| CLOSE_ENCRYPTED | CLOSE_DMTIME))) {
|
||||
|| !(of->state & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED
|
||||
| CLOSE_DMTIME | CLOSE_REPARSE))) {
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
|
@ -2560,20 +2823,38 @@ static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino,
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
res = CALL_REPARSE_PLUGIN(ni, release, &of->fi);
|
||||
if (!res) {
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
/* Assume release() was not needed */
|
||||
res = 0;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
res = 0;
|
||||
if (of->state & CLOSE_DMTIME)
|
||||
ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME);
|
||||
if (of->state & CLOSE_COMPRESSED)
|
||||
res = ntfs_attr_pclose(na);
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
if (of->state & CLOSE_ENCRYPTED)
|
||||
res = ntfs_efs_fixup_attribute(NULL, na);
|
||||
#endif /* HAVE_SETXATTR */
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps :
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
if (of->state & CLOSE_DMTIME)
|
||||
ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
@ -2923,7 +3204,7 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
|
|||
goto out;
|
||||
}
|
||||
/* Return with no result for symlinks, fifo, etc. */
|
||||
if (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT)))
|
||||
if (!user_xattrs_allowed(ctx, ni))
|
||||
goto exit;
|
||||
/* otherwise file must be readable */
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
|
@ -3072,7 +3353,7 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
|
|||
goto out;
|
||||
}
|
||||
/* Return with no result for symlinks, fifo, etc. */
|
||||
if (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT))) {
|
||||
if (!user_xattrs_allowed(ctx, ni)) {
|
||||
res = -ENODATA;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3269,7 +3550,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
|
|||
break;
|
||||
default :
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT))) {
|
||||
if (!user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3282,7 +3563,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
|
|||
#else
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if ((namespace == XATTRNS_USER)
|
||||
&& (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) {
|
||||
&& !user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3290,7 +3571,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
|
|||
lename_len = fix_xattr_prefix(name, namespace, &lename);
|
||||
if ((lename_len == -1)
|
||||
|| (ctx->windows_names
|
||||
&& ntfs_forbidden_chars(lename,lename_len))) {
|
||||
&& ntfs_forbidden_chars(lename,lename_len,TRUE))) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3514,7 +3795,7 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na
|
|||
break;
|
||||
default :
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT))) {
|
||||
if (!user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3527,7 +3808,7 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na
|
|||
#else
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if ((namespace == XATTRNS_USER)
|
||||
&& (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) {
|
||||
&& !user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3568,6 +3849,20 @@ out :
|
|||
#endif
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
static void register_internal_reparse_plugins(void)
|
||||
{
|
||||
static const plugin_operations_t ops = {
|
||||
.getattr = junction_getstat,
|
||||
.readlink = junction_readlink,
|
||||
} ;
|
||||
register_reparse_plugin(ctx, IO_REPARSE_TAG_MOUNT_POINT,
|
||||
&ops, (void*)NULL);
|
||||
register_reparse_plugin(ctx, IO_REPARSE_TAG_SYMLINK,
|
||||
&ops, (void*)NULL);
|
||||
}
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
static void ntfs_close(void)
|
||||
{
|
||||
struct SECURITY_CONTEXT security;
|
||||
|
@ -3593,7 +3888,7 @@ static void ntfs_close(void)
|
|||
/ ctx->seccache->head.p_reads % 10);
|
||||
}
|
||||
}
|
||||
ntfs_close_secure(&security);
|
||||
ntfs_destroy_security_context(&security);
|
||||
}
|
||||
|
||||
if (ntfs_umount(ctx->vol, FALSE))
|
||||
|
@ -3684,6 +3979,9 @@ static int ntfs_open(const char *device)
|
|||
flags |= NTFS_MNT_EXCLUSIVE;
|
||||
if (ctx->ro)
|
||||
flags |= NTFS_MNT_RDONLY;
|
||||
else
|
||||
if (!ctx->hiberfile)
|
||||
flags |= NTFS_MNT_MAY_RDONLY;
|
||||
if (ctx->recover)
|
||||
flags |= NTFS_MNT_RECOVER;
|
||||
if (ctx->hiberfile)
|
||||
|
@ -3827,13 +4125,14 @@ static fuse_fstype load_fuse_module(void)
|
|||
struct stat st;
|
||||
pid_t pid;
|
||||
const char *cmd = "/sbin/modprobe";
|
||||
char *env = (char*)NULL;
|
||||
struct timespec req = { 0, 100000000 }; /* 100 msec */
|
||||
fuse_fstype fstype;
|
||||
|
||||
if (!stat(cmd, &st) && !geteuid()) {
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
execl(cmd, cmd, "fuse", NULL);
|
||||
execle(cmd, cmd, "fuse", (char*)NULL, &env);
|
||||
_exit(1);
|
||||
} else if (pid != -1)
|
||||
waitpid(pid, NULL, 0);
|
||||
|
@ -4101,10 +4400,6 @@ int main(int argc, char *argv[])
|
|||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->vol->efs_raw = ctx->efs_raw;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
/* JPA open $Secure, (whatever NTFS version !) */
|
||||
/* to initialize security data */
|
||||
if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3))
|
||||
failed_secure = "Could not open file $Secure";
|
||||
if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path,
|
||||
(ctx->vol->secure_flags
|
||||
& ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))
|
||||
|
@ -4179,6 +4474,10 @@ int main(int argc, char *argv[])
|
|||
free(ctx->xattrmap_path);
|
||||
#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
register_internal_reparse_plugins();
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
se = mount_fuse(parsed_options);
|
||||
if (!se) {
|
||||
err = NTFS_VOLUME_FUSE_ERROR;
|
||||
|
@ -4214,6 +4513,9 @@ err_out:
|
|||
#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */
|
||||
err2:
|
||||
ntfs_close();
|
||||
#ifndef DISABLE_PLUGINS
|
||||
close_reparse_plugins(ctx);
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
free(ctx);
|
||||
free(parsed_options);
|
||||
free(opts.options);
|
||||
|
|
|
@ -185,8 +185,8 @@ etc. designate the same file). All files are displayed with lower case in
|
|||
directory listings.
|
||||
.TP
|
||||
.B remove_hiberfile
|
||||
Unlike in case of read-only mount, the read-write mount is denied if
|
||||
the NTFS volume is hibernated. One needs either to resume Windows and
|
||||
When the NTFS volume is hibernated, a read-write mount is denied and
|
||||
a read-only mount is forced. One needs either to resume Windows and
|
||||
shutdown it properly, or use this option which will remove the Windows
|
||||
hibernation file. Please note, this means that the saved Windows
|
||||
session will be completely lost. Use this option under your own
|
||||
|
@ -381,7 +381,7 @@ by Windows has to be collected. This will lead to a user mapping file like :
|
|||
.sp
|
||||
.RE
|
||||
.P
|
||||
The utility \fBntfs-3g.usermap\fP may be used to create such a user
|
||||
The utility \fBntfsusermap\fP may be used to create such a user
|
||||
mapping file.
|
||||
.SH EXAMPLES
|
||||
Mount /dev/sda1 to /mnt/windows:
|
||||
|
|
470
src/ntfs-3g.c
470
src/ntfs-3g.c
|
@ -4,7 +4,7 @@
|
|||
* Copyright (c) 2005-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2005 Yuval Fledel
|
||||
* Copyright (c) 2006-2009 Szabolcs Szakacsits
|
||||
* Copyright (c) 2007-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2007-2017 Jean-Pierre Andre
|
||||
* Copyright (c) 2009 Erik Larsson
|
||||
*
|
||||
* This file is originated from the Linux-NTFS project.
|
||||
|
@ -72,9 +72,12 @@
|
|||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MKDEV_H
|
||||
#ifdef MAJOR_IN_MKDEV
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef MAJOR_IN_SYSMACROS
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#include <sys/dirent.h>
|
||||
|
@ -82,6 +85,10 @@
|
|||
#include <sys/param.h>
|
||||
#endif /* defined(__APPLE__) || defined(__DARWIN__), ... */
|
||||
|
||||
#ifndef FUSE_CAP_POSIX_ACL /* until defined in <fuse/fuse_common.h> */
|
||||
#define FUSE_CAP_POSIX_ACL (1 << 18)
|
||||
#endif /* FUSE_CAP_POSIX_ACL */
|
||||
|
||||
#include "compat.h"
|
||||
#include "attrib.h"
|
||||
#include "inode.h"
|
||||
|
@ -99,6 +106,7 @@
|
|||
#include "xattrs.h"
|
||||
#include "misc.h"
|
||||
#include "ioctl.h"
|
||||
#include "plugin.h"
|
||||
|
||||
#include "ntfs-3g_common.h"
|
||||
|
||||
|
@ -129,6 +137,22 @@
|
|||
|
||||
#define set_archive(ni) (ni)->flags = le32_or((ni)->flags, FILE_ATTR_ARCHIVE)
|
||||
|
||||
/*
|
||||
* Call a function from a reparse plugin (variable arguments)
|
||||
* Requires "reparse" and "ops" to have been defined
|
||||
*
|
||||
* Returns a non-negative value if successful,
|
||||
* and a negative error code if something fails.
|
||||
*/
|
||||
#define CALL_REPARSE_PLUGIN(ni, op_name, ...) \
|
||||
(reparse = (REPARSE_POINT*)NULL, \
|
||||
ops = select_reparse_plugin(ctx, ni, &reparse), \
|
||||
(!ops ? -errno \
|
||||
: (ops->op_name ? \
|
||||
ops->op_name(ni, reparse, __VA_ARGS__) \
|
||||
: -EOPNOTSUPP))), \
|
||||
free(reparse)
|
||||
|
||||
typedef enum {
|
||||
FSTYPE_NONE,
|
||||
FSTYPE_UNKNOWN,
|
||||
|
@ -144,7 +168,8 @@ typedef struct {
|
|||
enum {
|
||||
CLOSE_COMPRESSED = 1,
|
||||
CLOSE_ENCRYPTED = 2,
|
||||
CLOSE_DMTIME = 4
|
||||
CLOSE_DMTIME = 4,
|
||||
CLOSE_REPARSE = 8
|
||||
};
|
||||
|
||||
static struct ntfs_options opts;
|
||||
|
@ -171,7 +196,7 @@ static const char *usage_msg =
|
|||
"\n"
|
||||
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
|
||||
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
|
||||
"Copyright (C) 2007-2016 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2007-2017 Jean-Pierre Andre\n"
|
||||
"Copyright (C) 2009 Erik Larsson\n"
|
||||
"\n"
|
||||
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
|
||||
|
@ -311,6 +336,7 @@ static int ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
|
|||
allowed = 1;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (dir_ni)
|
||||
allowed = ntfs_real_allowed_access(scx, dir_ni,
|
||||
accesstype);
|
||||
|
@ -353,6 +379,7 @@ static int ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
|
|||
ntfs_inode_close(ni2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (allowed);
|
||||
}
|
||||
|
||||
|
@ -651,6 +678,10 @@ static void *ntfs_init(struct fuse_conn_info *conn)
|
|||
/* request umask not to be enforced by fuse */
|
||||
conn->want |= FUSE_CAP_DONT_MASK;
|
||||
#endif /* defined FUSE_CAP_DONT_MASK */
|
||||
#if POSIXACLS & KERNELACLS
|
||||
/* request ACLs to be checked by kernel */
|
||||
conn->want |= FUSE_CAP_POSIX_ACL;
|
||||
#endif /* POSIXACLS & KERNELACLS */
|
||||
#ifdef FUSE_CAP_BIG_WRITES
|
||||
if (ctx->big_writes
|
||||
&& ((ctx->vol->nr_clusters << ctx->vol->cluster_size_bits)
|
||||
|
@ -663,6 +694,65 @@ static void *ntfs_init(struct fuse_conn_info *conn)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
/*
|
||||
* Define attributes for a junction or symlink
|
||||
* (internal plugin)
|
||||
*/
|
||||
|
||||
static int junction_getattr(ntfs_inode *ni,
|
||||
const REPARSE_POINT *reparse __attribute__((unused)),
|
||||
struct stat *stbuf)
|
||||
{
|
||||
char *target;
|
||||
int res;
|
||||
|
||||
errno = 0;
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
/*
|
||||
* If the reparse point is not a valid
|
||||
* directory junction, and there is no error
|
||||
* we still display as a symlink
|
||||
*/
|
||||
if (target || (errno == EOPNOTSUPP)) {
|
||||
if (target)
|
||||
stbuf->st_size = strlen(target);
|
||||
else
|
||||
stbuf->st_size = sizeof(ntfs_bad_reparse) - 1;
|
||||
stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_mode = S_IFLNK;
|
||||
free(target);
|
||||
res = 0;
|
||||
} else {
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply permission masks to st_mode returned by a reparse handler
|
||||
*/
|
||||
|
||||
static void apply_umask(struct stat *stbuf)
|
||||
{
|
||||
switch (stbuf->st_mode & S_IFMT) {
|
||||
case S_IFREG :
|
||||
stbuf->st_mode &= ~ctx->fmask;
|
||||
break;
|
||||
case S_IFDIR :
|
||||
stbuf->st_mode &= ~ctx->dmask;
|
||||
break;
|
||||
case S_IFLNK :
|
||||
stbuf->st_mode = (stbuf->st_mode & S_IFMT) | 0777;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
||||
{
|
||||
int res = 0;
|
||||
|
@ -696,26 +786,45 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|||
goto exit;
|
||||
}
|
||||
#endif
|
||||
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||
|
||||
if ((!le16_andz(ni->mrec->flags, MFT_RECORD_IS_DIRECTORY)
|
||||
|| !le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT))
|
||||
&& !stream_name_len) {
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
res = CALL_REPARSE_PLUGIN(ni, getattr, stbuf);
|
||||
if (!res) {
|
||||
apply_umask(stbuf);
|
||||
goto ok;
|
||||
} else {
|
||||
stbuf->st_size =
|
||||
sizeof(ntfs_bad_reparse) - 1;
|
||||
stbuf->st_blocks =
|
||||
(ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_mode = S_IFLNK;
|
||||
res = 0;
|
||||
goto ok;
|
||||
}
|
||||
goto exit;
|
||||
#else /* DISABLE_PLUGINS */
|
||||
char *target;
|
||||
int attr_size;
|
||||
|
||||
errno = 0;
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size);
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
/*
|
||||
* If the reparse point is not a valid
|
||||
* directory junction, and there is no error
|
||||
* we still display as a symlink
|
||||
*/
|
||||
if (target || (errno == EOPNOTSUPP)) {
|
||||
/* returning attribute size */
|
||||
if (target)
|
||||
stbuf->st_size = attr_size;
|
||||
stbuf->st_size = strlen(target);
|
||||
else
|
||||
stbuf->st_size = sizeof(ntfs_bad_reparse);
|
||||
stbuf->st_size = sizeof(ntfs_bad_reparse) - 1;
|
||||
stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||
stbuf->st_mode = S_IFLNK;
|
||||
|
@ -724,6 +833,7 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
} else {
|
||||
/* Directory. */
|
||||
stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask);
|
||||
|
@ -761,7 +871,6 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|||
* See more on the ntfs-3g-devel list.
|
||||
*/
|
||||
stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
|
||||
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_SYSTEM) || stream_name_len) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name,
|
||||
stream_name_len);
|
||||
|
@ -837,14 +946,38 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|||
le64_to_cpu(
|
||||
intx_file->minor));
|
||||
}
|
||||
if (le64_eq(intx_file->magic, INTX_SYMBOLIC_LINK))
|
||||
if (le64_eq(intx_file->magic, INTX_SYMBOLIC_LINK)) {
|
||||
char *target = NULL;
|
||||
int len;
|
||||
|
||||
/* st_size should be set to length of
|
||||
* symlink target as multibyte string */
|
||||
len = ntfs_ucstombs(
|
||||
intx_file->target,
|
||||
(na->data_size -
|
||||
offsetof(INTX_FILE,
|
||||
target)) /
|
||||
sizeof(ntfschar),
|
||||
&target, 0);
|
||||
if (len < 0) {
|
||||
res = -errno;
|
||||
free(intx_file);
|
||||
ntfs_attr_close(na);
|
||||
goto exit;
|
||||
}
|
||||
free(target);
|
||||
stbuf->st_mode = S_IFLNK;
|
||||
stbuf->st_size = len;
|
||||
}
|
||||
free(intx_file);
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
stbuf->st_mode |= (0777 & ~ctx->fmask);
|
||||
}
|
||||
#ifndef DISABLE_PLUGINS
|
||||
ok:
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
if (withusermapping) {
|
||||
if (ntfs_get_owner_mode(&security,ni,stbuf) < 0)
|
||||
set_fuse_error(&res);
|
||||
|
@ -900,6 +1033,35 @@ exit:
|
|||
return res;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
/*
|
||||
* Get the link defined by a junction or symlink
|
||||
* (internal plugin)
|
||||
*/
|
||||
|
||||
static int junction_readlink(ntfs_inode *ni,
|
||||
const REPARSE_POINT *reparse __attribute__((unused)),
|
||||
char **pbuf)
|
||||
{
|
||||
int res;
|
||||
|
||||
errno = 0;
|
||||
res = 0;
|
||||
*pbuf = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
if (!*pbuf) {
|
||||
if (errno == EOPNOTSUPP) {
|
||||
*pbuf = strdup(ntfs_bad_reparse);
|
||||
if (!*pbuf)
|
||||
res = -errno;
|
||||
} else
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size)
|
||||
{
|
||||
char *path = NULL;
|
||||
|
@ -926,12 +1088,26 @@ static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size)
|
|||
* Reparse point : analyze as a junction point
|
||||
*/
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
char *gotlink;
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
gotlink = (char*)NULL;
|
||||
res = CALL_REPARSE_PLUGIN(ni, readlink, &gotlink);
|
||||
if (gotlink) {
|
||||
strncpy(buf, gotlink, buf_size);
|
||||
free(gotlink);
|
||||
} else {
|
||||
strncpy(buf, ntfs_bad_reparse, buf_size);
|
||||
res = 0;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
char *target;
|
||||
int attr_size;
|
||||
|
||||
errno = 0;
|
||||
res = 0;
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size);
|
||||
target = ntfs_make_symlink(ni, ctx->abs_mnt_point);
|
||||
if (target) {
|
||||
strncpy(buf,target,buf_size);
|
||||
free(target);
|
||||
|
@ -940,6 +1116,7 @@ static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size)
|
|||
strcpy(buf,ntfs_bad_reparse);
|
||||
else
|
||||
res = -errno;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
/* Sanity checks. */
|
||||
|
@ -1163,7 +1340,7 @@ static int ntfs_fuse_open(const char *org_path,
|
|||
#endif
|
||||
{
|
||||
ntfs_inode *ni;
|
||||
ntfs_attr *na;
|
||||
ntfs_attr *na = NULL;
|
||||
int res = 0;
|
||||
char *path = NULL;
|
||||
ntfschar *stream_name;
|
||||
|
@ -1178,50 +1355,66 @@ static int ntfs_fuse_open(const char *org_path,
|
|||
return stream_name_len;
|
||||
ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
||||
if (ni) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
|
||||
if (na) {
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
if (ntfs_fuse_fill_security_context(&security)) {
|
||||
if (fi->flags & O_WRONLY)
|
||||
accesstype = S_IWRITE;
|
||||
else
|
||||
if (fi->flags & O_RDWR)
|
||||
accesstype = S_IWRITE | S_IREAD;
|
||||
else
|
||||
accesstype = S_IREAD;
|
||||
/*
|
||||
* directory must be searchable
|
||||
* and requested access allowed
|
||||
*/
|
||||
if (!ntfs_allowed_dir_access(&security,
|
||||
path,(ntfs_inode*)NULL,ni,S_IEXEC)
|
||||
|| !ntfs_allowed_access(&security,
|
||||
ni,accesstype))
|
||||
res = -EACCES;
|
||||
if (le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
goto close;
|
||||
}
|
||||
}
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
if (ntfs_fuse_fill_security_context(&security)) {
|
||||
if (fi->flags & O_WRONLY)
|
||||
accesstype = S_IWRITE;
|
||||
else
|
||||
if (fi->flags & O_RDWR)
|
||||
accesstype = S_IWRITE | S_IREAD;
|
||||
else
|
||||
accesstype = S_IREAD;
|
||||
/*
|
||||
* directory must be searchable
|
||||
* and requested access allowed
|
||||
*/
|
||||
if (!ntfs_allowed_dir_access(&security,
|
||||
path,(ntfs_inode*)NULL,ni,S_IEXEC)
|
||||
|| !ntfs_allowed_access(&security,
|
||||
ni,accesstype))
|
||||
res = -EACCES;
|
||||
}
|
||||
#endif
|
||||
if ((res >= 0)
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR))) {
|
||||
/* mark a future need to compress the last chunk */
|
||||
if (!le16_andz(na->data_flags, ATTR_COMPRESSION_MASK))
|
||||
fi->fh |= CLOSE_COMPRESSED;
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
fi->fh = 0;
|
||||
res = CALL_REPARSE_PLUGIN(ni, open, fi);
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto close;
|
||||
}
|
||||
if ((res >= 0)
|
||||
&& (fi->flags & (O_WRONLY | O_RDWR))) {
|
||||
/* mark a future need to compress the last chunk */
|
||||
if (!le16_andz(na->data_flags, ATTR_COMPRESSION_MASK))
|
||||
fi->fh |= CLOSE_COMPRESSED;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
/* mark a future need to fixup encrypted inode */
|
||||
if (ctx->efs_raw
|
||||
&& le16_andz(na->data_flags, ATTR_IS_ENCRYPTED)
|
||||
&& !le32_andz(ni->flags, FILE_ATTR_ENCRYPTED))
|
||||
fi->fh |= CLOSE_ENCRYPTED;
|
||||
if (ctx->efs_raw
|
||||
&& le16_andz(na->data_flags, ATTR_IS_ENCRYPTED)
|
||||
&& !le32_andz(ni->flags, FILE_ATTR_ENCRYPTED))
|
||||
fi->fh |= CLOSE_ENCRYPTED;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
/* mark a future need to update the mtime */
|
||||
if (ctx->dmtime)
|
||||
fi->fh |= CLOSE_DMTIME;
|
||||
/* deny opening metadata files for writing */
|
||||
if (ni->mft_no < FILE_first_user)
|
||||
res = -EPERM;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
} else
|
||||
res = -errno;
|
||||
/* mark a future need to update the mtime */
|
||||
if (ctx->dmtime)
|
||||
fi->fh |= CLOSE_DMTIME;
|
||||
/* deny opening metadata files for writing */
|
||||
if (ni->mft_no < FILE_first_user)
|
||||
res = -EPERM;
|
||||
}
|
||||
ntfs_attr_close(na);
|
||||
close:
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
} else
|
||||
|
@ -1254,6 +1447,24 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
if (stream_name_len || !fi) {
|
||||
res = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
res = CALL_REPARSE_PLUGIN(ni, read, buf, size, offset, fi);
|
||||
if (res >= 0) {
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
|
@ -1289,8 +1500,11 @@ static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
|
|||
total += ret;
|
||||
}
|
||||
ok:
|
||||
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME);
|
||||
res = total;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps:
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
@ -1321,6 +1535,24 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size,
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
if (stream_name_len || !fi) {
|
||||
res = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
res = CALL_REPARSE_PLUGIN(ni, write, buf, size, offset, fi);
|
||||
if (res >= 0) {
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
|
@ -1337,15 +1569,18 @@ static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size,
|
|||
total += ret;
|
||||
}
|
||||
res = total;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps:
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
if ((res > 0)
|
||||
&& (!ctx->dmtime
|
||||
|| (sle64_to_cpu(ntfs_current_time())
|
||||
- sle64_to_cpu(ni->last_data_change_time)) > ctx->dmtime))
|
||||
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
|
||||
ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
if (total)
|
||||
if (res > 0)
|
||||
set_archive(ni);
|
||||
if (ntfs_inode_close(ni))
|
||||
set_fuse_error(&res);
|
||||
|
@ -1365,8 +1600,14 @@ static int ntfs_fuse_release(const char *org_path,
|
|||
ntfschar *stream_name;
|
||||
int stream_name_len, res;
|
||||
|
||||
if (!fi) {
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only for marked descriptors there is something to do */
|
||||
if (!(fi->fh & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED | CLOSE_DMTIME))) {
|
||||
|
||||
if (!fi->fh) {
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1380,20 +1621,42 @@ static int ntfs_fuse_release(const char *org_path,
|
|||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
if (stream_name_len) {
|
||||
res = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
res = CALL_REPARSE_PLUGIN(ni, release, fi);
|
||||
if (!res) {
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
/* Assume release() was not needed */
|
||||
res = 0;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
|
||||
if (!na) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
res = 0;
|
||||
if (fi->fh & CLOSE_DMTIME)
|
||||
ntfs_inode_update_times(na->ni,NTFS_UPDATE_MCTIME);
|
||||
if (fi->fh & CLOSE_COMPRESSED)
|
||||
res = ntfs_attr_pclose(na);
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
if (fi->fh & CLOSE_ENCRYPTED)
|
||||
res = ntfs_efs_fixup_attribute(NULL, na);
|
||||
#endif /* HAVE_SETXATTR */
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps:
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
if (fi->fh & CLOSE_DMTIME)
|
||||
ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME);
|
||||
exit:
|
||||
if (na)
|
||||
ntfs_attr_close(na);
|
||||
|
@ -1440,6 +1703,25 @@ static int ntfs_fuse_trunc(const char *org_path, off_t size,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
const plugin_operations_t *ops;
|
||||
REPARSE_POINT *reparse;
|
||||
|
||||
if (stream_name_len) {
|
||||
res = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
res = CALL_REPARSE_PLUGIN(ni, truncate, size);
|
||||
if (!res) {
|
||||
set_archive(ni);
|
||||
goto stamps;
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = -EOPNOTSUPP;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
goto exit;
|
||||
}
|
||||
na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
|
||||
if (!na)
|
||||
goto exit;
|
||||
|
@ -1472,8 +1754,11 @@ static int ntfs_fuse_trunc(const char *org_path, off_t size,
|
|||
goto exit;
|
||||
if (oldsize != size)
|
||||
set_archive(ni);
|
||||
|
||||
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
stamps:
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
ntfs_fuse_update_times(ni, NTFS_UPDATE_MCTIME);
|
||||
errno = 0;
|
||||
exit:
|
||||
res = -errno;
|
||||
|
@ -1669,7 +1954,7 @@ static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev,
|
|||
uname_len = ntfs_mbstoucs(name, &uname);
|
||||
if ((uname_len < 0)
|
||||
|| (ctx->windows_names
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len))) {
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1683,9 +1968,12 @@ static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev,
|
|||
/* Open parent directory. */
|
||||
*--name = 0;
|
||||
dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, dir_path);
|
||||
if (!dir_ni) {
|
||||
/* Deny creating files in $Extend */
|
||||
if (!dir_ni || (dir_ni->mft_no == FILE_Extend)) {
|
||||
free(path);
|
||||
res = -errno;
|
||||
if (dir_ni->mft_no == FILE_Extend)
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
|
@ -1874,7 +2162,7 @@ static int ntfs_fuse_mknod_common(const char *org_path, mode_t mode, dev_t dev,
|
|||
&& (!S_ISREG(mode)
|
||||
|| (ctx->windows_names
|
||||
&& ntfs_forbidden_names(ctx->vol,stream_name,
|
||||
stream_name_len)))) {
|
||||
stream_name_len, TRUE)))) {
|
||||
res = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1943,7 +2231,7 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path)
|
|||
uname_len = ntfs_mbstoucs(name, &uname);
|
||||
if ((uname_len < 0)
|
||||
|| (ctx->windows_names
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len))) {
|
||||
&& ntfs_forbidden_names(ctx->vol,uname,uname_len,TRUE))) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -2028,8 +2316,11 @@ static int ntfs_fuse_rm(const char *org_path)
|
|||
/* Open parent directory. */
|
||||
*--name = 0;
|
||||
dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
|
||||
if (!dir_ni) {
|
||||
/* deny unlinking metadata files from $Extend */
|
||||
if (!dir_ni || (dir_ni->mft_no == FILE_Extend)) {
|
||||
res = -errno;
|
||||
if (dir_ni->mft_no == FILE_Extend)
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -2689,7 +2980,7 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
|
|||
if (!ni)
|
||||
return -errno;
|
||||
/* Return with no result for symlinks, fifo, etc. */
|
||||
if (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT)))
|
||||
if (!user_xattrs_allowed(ctx, ni))
|
||||
goto exit;
|
||||
/* otherwise file must be readable */
|
||||
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
|
||||
|
@ -2891,7 +3182,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name,
|
|||
if (!ni)
|
||||
return -errno;
|
||||
/* Return with no result for symlinks, fifo, etc. */
|
||||
if (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT))) {
|
||||
if (!user_xattrs_allowed(ctx, ni)) {
|
||||
res = -ENODATA;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3067,7 +3358,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
|||
break;
|
||||
default :
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) {
|
||||
if (!user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3080,7 +3371,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
|||
#else
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if ((namespace == XATTRNS_USER)
|
||||
&& (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT)))) {
|
||||
&& !user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3088,7 +3379,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name,
|
|||
lename_len = fix_xattr_prefix(name, namespace, &lename);
|
||||
if ((lename_len == -1)
|
||||
|| (ctx->windows_names
|
||||
&& ntfs_forbidden_chars(lename,lename_len))) {
|
||||
&& ntfs_forbidden_chars(lename,lename_len,TRUE))) {
|
||||
res = -errno;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3304,7 +3595,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
|
|||
break;
|
||||
default :
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) {
|
||||
if (!user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3317,7 +3608,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name)
|
|||
#else
|
||||
/* User xattr not allowed for symlinks, fifo, etc. */
|
||||
if ((namespace == XATTRNS_USER)
|
||||
&& (!le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT)))) {
|
||||
&& !user_xattrs_allowed(ctx, ni)) {
|
||||
res = -EPERM;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -3352,6 +3643,20 @@ exit:
|
|||
#endif
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
static void register_internal_reparse_plugins(void)
|
||||
{
|
||||
static const plugin_operations_t ops = {
|
||||
.getattr = junction_getattr,
|
||||
.readlink = junction_readlink,
|
||||
} ;
|
||||
register_reparse_plugin(ctx, IO_REPARSE_TAG_MOUNT_POINT,
|
||||
&ops, (void*)NULL);
|
||||
register_reparse_plugin(ctx, IO_REPARSE_TAG_SYMLINK,
|
||||
&ops, (void*)NULL);
|
||||
}
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
static void ntfs_close(void)
|
||||
{
|
||||
struct SECURITY_CONTEXT security;
|
||||
|
@ -3377,7 +3682,7 @@ static void ntfs_close(void)
|
|||
/ ctx->seccache->head.p_reads % 10);
|
||||
}
|
||||
}
|
||||
ntfs_close_secure(&security);
|
||||
ntfs_destroy_security_context(&security);
|
||||
}
|
||||
|
||||
if (ntfs_umount(ctx->vol, FALSE))
|
||||
|
@ -3473,6 +3778,9 @@ static int ntfs_open(const char *device)
|
|||
flags |= NTFS_MNT_EXCLUSIVE;
|
||||
if (ctx->ro)
|
||||
flags |= NTFS_MNT_RDONLY;
|
||||
else
|
||||
if (!ctx->hiberfile)
|
||||
flags |= NTFS_MNT_MAY_RDONLY;
|
||||
if (ctx->recover)
|
||||
flags |= NTFS_MNT_RECOVER;
|
||||
if (ctx->hiberfile)
|
||||
|
@ -3612,13 +3920,14 @@ static fuse_fstype load_fuse_module(void)
|
|||
struct stat st;
|
||||
pid_t pid;
|
||||
const char *cmd = "/sbin/modprobe";
|
||||
char *env = (char*)NULL;
|
||||
struct timespec req = { 0, 100000000 }; /* 100 msec */
|
||||
fuse_fstype fstype;
|
||||
|
||||
if (!stat(cmd, &st) && !geteuid()) {
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
execl(cmd, cmd, "fuse", NULL);
|
||||
execle(cmd, cmd, "fuse", (char*)NULL, &env);
|
||||
_exit(1);
|
||||
} else if (pid != -1)
|
||||
waitpid(pid, NULL, 0);
|
||||
|
@ -3891,10 +4200,6 @@ int main(int argc, char *argv[])
|
|||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->vol->efs_raw = ctx->efs_raw;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
/* JPA open $Secure, (whatever NTFS version !) */
|
||||
/* to initialize security data */
|
||||
if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3))
|
||||
failed_secure = "Could not open file $Secure";
|
||||
if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path,
|
||||
(ctx->vol->secure_flags
|
||||
& ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))
|
||||
|
@ -3968,6 +4273,10 @@ int main(int argc, char *argv[])
|
|||
free(ctx->xattrmap_path);
|
||||
#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
register_internal_reparse_plugins();
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
fh = mount_fuse(parsed_options);
|
||||
if (!fh) {
|
||||
err = NTFS_VOLUME_FUSE_ERROR;
|
||||
|
@ -4005,6 +4314,9 @@ err_out:
|
|||
#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */
|
||||
err2:
|
||||
ntfs_close();
|
||||
#ifndef DISABLE_PLUGINS
|
||||
close_reparse_plugins(ctx);
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
free(ctx);
|
||||
free(parsed_options);
|
||||
free(opts.options);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.
|
||||
*
|
||||
* Copyright (c) 2010-2015 Jean-Pierre Andre
|
||||
* Copyright (c) 2010-2016 Jean-Pierre Andre
|
||||
* Copyright (c) 2010 Erik Larsson
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
|
@ -28,6 +28,10 @@
|
|||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DLFCN_H
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
@ -43,9 +47,13 @@
|
|||
#include <getopt.h>
|
||||
#include <fuse.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "inode.h"
|
||||
#include "dir.h"
|
||||
#include "security.h"
|
||||
#include "xattrs.h"
|
||||
#include "reparse.h"
|
||||
#include "plugin.h"
|
||||
#include "ntfs-3g_common.h"
|
||||
#include "realpath.h"
|
||||
#include "misc.h"
|
||||
|
@ -750,3 +758,169 @@ exit :
|
|||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
|
||||
const plugin_operations_t *ops, void *handle)
|
||||
{
|
||||
plugin_list_t *plugin;
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
plugin = (plugin_list_t*)ntfs_malloc(sizeof(plugin_list_t));
|
||||
if (plugin) {
|
||||
plugin->tag = tag;
|
||||
plugin->ops = ops;
|
||||
plugin->handle = handle;
|
||||
plugin->next = ctx->plugins;
|
||||
ctx->plugins = plugin;
|
||||
res = 0;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the reparse operations associated to an inode
|
||||
*
|
||||
* The plugin able to process the reparse point is dynamically loaded
|
||||
*
|
||||
* When successful, returns the operations vector and the reparse
|
||||
* data if requested,
|
||||
* Otherwise returns NULL, with errno set.
|
||||
*/
|
||||
|
||||
const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx,
|
||||
ntfs_inode *ni, REPARSE_POINT **reparse_wanted)
|
||||
{
|
||||
const struct plugin_operations *ops;
|
||||
void *handle;
|
||||
REPARSE_POINT *reparse;
|
||||
le32 tag;
|
||||
plugin_list_t *plugin;
|
||||
plugin_init_t pinit;
|
||||
|
||||
ops = (struct plugin_operations*)NULL;
|
||||
reparse = ntfs_get_reparse_point(ni);
|
||||
if (reparse) {
|
||||
tag = reparse->reparse_tag;
|
||||
for (plugin=ctx->plugins; plugin && !le32_eq(plugin->tag, tag);
|
||||
plugin = plugin->next) { }
|
||||
if (plugin) {
|
||||
ops = plugin->ops;
|
||||
} else {
|
||||
#ifdef PLUGIN_DIR
|
||||
char name[sizeof(PLUGIN_DIR) + 64];
|
||||
|
||||
snprintf(name,sizeof(name), PLUGIN_DIR
|
||||
"/ntfs-plugin-%08lx.so",
|
||||
(long)le32_to_cpu(tag));
|
||||
#else
|
||||
char name[64];
|
||||
|
||||
snprintf(name,sizeof(name), "ntfs-plugin-%08lx.so",
|
||||
(long)le32_to_cpu(tag));
|
||||
#endif
|
||||
handle = dlopen(name, RTLD_LAZY);
|
||||
if (handle) {
|
||||
pinit = (plugin_init_t)dlsym(handle, "init");
|
||||
if (pinit) {
|
||||
/* pinit() should set errno if it fails */
|
||||
ops = (*pinit)(tag);
|
||||
if (ops && register_reparse_plugin(ctx,
|
||||
tag, ops, handle))
|
||||
ops = (struct plugin_operations*)NULL;
|
||||
} else
|
||||
errno = ELIBBAD;
|
||||
if (!ops)
|
||||
dlclose(handle);
|
||||
} else {
|
||||
if (!(ctx->errors_logged & ERR_PLUGIN)) {
|
||||
ntfs_log_perror(
|
||||
"Could not load plugin %s",
|
||||
name);
|
||||
ntfs_log_error("Hint %s\n",dlerror());
|
||||
}
|
||||
ctx->errors_logged |= ERR_PLUGIN;
|
||||
}
|
||||
}
|
||||
if (ops && reparse_wanted)
|
||||
*reparse_wanted = reparse;
|
||||
else
|
||||
free(reparse);
|
||||
}
|
||||
return (ops);
|
||||
}
|
||||
|
||||
void close_reparse_plugins(ntfs_fuse_context_t *ctx)
|
||||
{
|
||||
while (ctx->plugins) {
|
||||
plugin_list_t *next;
|
||||
|
||||
next = ctx->plugins->next;
|
||||
if (ctx->plugins->handle)
|
||||
dlclose(ctx->plugins->handle);
|
||||
free(ctx->plugins);
|
||||
ctx->plugins = next;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
|
||||
/*
|
||||
* Check whether a user xattr is allowed
|
||||
*
|
||||
* The inode must be a plain file or a directory. The only allowed
|
||||
* metadata file is the root directory (useful for MacOSX and hopefully
|
||||
* does not harm Windows).
|
||||
*/
|
||||
|
||||
BOOL user_xattrs_allowed(ntfs_fuse_context_t *ctx __attribute__((unused)),
|
||||
ntfs_inode *ni)
|
||||
{
|
||||
u32 dt_type;
|
||||
BOOL res;
|
||||
|
||||
/* Quick return for common cases and root */
|
||||
if (le32_andz(ni->flags, le32_or(FILE_ATTR_SYSTEM, FILE_ATTR_REPARSE_POINT))
|
||||
|| (ni->mft_no == FILE_root))
|
||||
res = TRUE;
|
||||
else {
|
||||
/* Reparse point depends on kind, see plugin */
|
||||
if (!le32_andz(ni->flags, FILE_ATTR_REPARSE_POINT)) {
|
||||
#ifndef DISABLE_PLUGINS
|
||||
struct stat stbuf;
|
||||
REPARSE_POINT *reparse;
|
||||
const plugin_operations_t *ops;
|
||||
|
||||
res = FALSE; /* default for error cases */
|
||||
ops = select_reparse_plugin(ctx, ni, &reparse);
|
||||
if (ops) {
|
||||
if (ops->getattr
|
||||
&& !ops->getattr(ni,reparse,&stbuf)) {
|
||||
res = S_ISREG(stbuf.st_mode)
|
||||
|| S_ISDIR(stbuf.st_mode);
|
||||
}
|
||||
free(reparse);
|
||||
}
|
||||
#else /* DISABLE_PLUGINS */
|
||||
res = FALSE; /* mountpoints, symlinks, ... */
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
} else {
|
||||
/* Metadata */
|
||||
if (ni->mft_no < FILE_first_user)
|
||||
res = FALSE;
|
||||
else {
|
||||
/* Interix types */
|
||||
dt_type = ntfs_interix_types(ni);
|
||||
res = (dt_type == NTFS_DT_REG)
|
||||
|| (dt_type == NTFS_DT_DIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif /* HAVE_SETXATTR */
|
||||
|
|
|
@ -110,6 +110,21 @@ typedef enum {
|
|||
ATIME_RELATIVE
|
||||
} ntfs_atime_t;
|
||||
|
||||
typedef enum {
|
||||
ERR_PLUGIN = 1
|
||||
} single_log_t;
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
typedef struct plugin_list {
|
||||
struct plugin_list *next;
|
||||
void *handle;
|
||||
const plugin_operations_t *ops;
|
||||
le32 tag;
|
||||
} plugin_list_t;
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
typedef struct {
|
||||
ntfs_volume *vol;
|
||||
unsigned int uid;
|
||||
|
@ -145,8 +160,12 @@ typedef struct {
|
|||
struct fuse_chan *fc;
|
||||
BOOL inherit;
|
||||
unsigned int secure_flags;
|
||||
single_log_t errors_logged;
|
||||
char *usermap_path;
|
||||
char *abs_mnt_point;
|
||||
#ifndef DISABLE_PLUGINS
|
||||
plugin_list_t *plugins;
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
struct PERMISSIONS_CACHE *seccache;
|
||||
struct SECURITY_CONTEXT security;
|
||||
struct open_file *open_files; /* only defined in lowntfs-3g */
|
||||
|
@ -181,5 +200,16 @@ int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void),
|
|||
|
||||
int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
|
||||
char *list, size_t size, BOOL prefixing);
|
||||
BOOL user_xattrs_allowed(ntfs_fuse_context_t *ctx, ntfs_inode *ni);
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
void close_reparse_plugins(ntfs_fuse_context_t *ctx);
|
||||
const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx,
|
||||
ntfs_inode *ni, REPARSE_POINT **reparse);
|
||||
int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
|
||||
const plugin_operations_t *ops, void *handle);
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
#endif /* _NTFS_3G_COMMON_H */
|
||||
|
|
742
src/secaudit.h
742
src/secaudit.h
|
@ -1,742 +0,0 @@
|
|||
/*
|
||||
* General declarations for secaudit
|
||||
*
|
||||
* These declarations are organized to enable code sharing with ntfs-3g
|
||||
* library, but should only be used to build tools runnable both
|
||||
* on Linux (dynamic linking) and Windows (static linking)
|
||||
*
|
||||
* Copyright (c) 2007-2009 Jean-Pierre Andre
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (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
|
||||
*/
|
||||
|
||||
/*
|
||||
* General parameters which may have to be adapted to needs
|
||||
*/
|
||||
|
||||
#define SELFTESTS 1 /* include code for self-testing */
|
||||
#define POSIXACLS 0 /* include code for processing Posix ACLs */
|
||||
#define NOREVBOM 0 /* temporary */
|
||||
|
||||
#define OWNERFROMACL 1 /* must match option in security.c */
|
||||
|
||||
#define MAXATTRSZ 65536 /* Max sec attr size (16448 met for WinXP) */
|
||||
#define MAXSECURID 262144
|
||||
#define SECBLKSZ 8
|
||||
#define MAXFILENAME 4096
|
||||
#define FORCEMASK 0 /* Special (dangerous) option -m to force a mask */
|
||||
#define MAXLINE 80 /* maximum processed size of a line */
|
||||
#define BUFSZ 1024 /* buffer size to read mapping file */
|
||||
#define LINESZ 120 /* maximum useful size of a mapping line */
|
||||
|
||||
/*
|
||||
* Definitions for Linux
|
||||
* Use explicit or implicit dynamic linking
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#undef POSIXACLS /* override default by configure option */
|
||||
#define USESTUBS 1 /* API stubs generated at link time */
|
||||
#else
|
||||
#define USESTUBS 0 /* direct calls to API, based on following definitions */
|
||||
#define ENVNTFS3G "NTFS3G"
|
||||
#if defined(__SVR4)
|
||||
#define LIBFILE64 "/usr/lib/amd64/libntfs-3g.so"
|
||||
#define LIBFILE "/usr/lib/libntfs-3g.so"
|
||||
#else
|
||||
#define LIBFILE64 "/lib64/libntfs-3g.so"
|
||||
#define LIBFILE "/lib/libntfs-3g.so"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MAPDIR ".NTFS-3G"
|
||||
#define MAPFILE "UserMapping"
|
||||
#define MAGIC_API 0x09042009
|
||||
|
||||
#ifndef _NTFS_ENDIANS_H
|
||||
|
||||
typedef char s8;
|
||||
typedef short s16;
|
||||
typedef long long s64;
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short le16, be16, u16;
|
||||
typedef unsigned long long u64;
|
||||
#ifdef STSC
|
||||
typedef long s32;
|
||||
typedef unsigned long le32, be32, u32;
|
||||
#else
|
||||
typedef int s32;
|
||||
typedef unsigned int le32, be32, u32;
|
||||
#endif
|
||||
|
||||
#ifdef STSC
|
||||
#define endian_rev16(x) ((((x) & 255L) << 8) + (((x) >> 8) & 255L))
|
||||
#define endian_rev32(x) ((((x) & 255L) << 24) + (((x) & 0xff00L) << 8) \
|
||||
+ (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L))
|
||||
#else
|
||||
#define endian_rev16(x) ((((x) & 255) << 8) + (((x) >> 8) & 255))
|
||||
#define endian_rev32(x) ((((x) & 255) << 24) + (((x) & 0xff00) << 8) \
|
||||
+ (((x) >> 8) & 0xff00) + (((x) >> 24) & 255))
|
||||
#endif
|
||||
#define endian_rev64(x) ((((x) & 255LL) << 56) + (((x) & 0xff00LL) << 40) \
|
||||
+ (((x) & 0xff0000LL) << 24) + (((x) & 0xff000000LL) << 8) \
|
||||
+ (((x) >> 8) & 0xff000000LL) + (((x) >> 24) & 0xff0000LL) \
|
||||
+ (((x) >> 40) & 0xff00LL) + (((x) >> 56) & 255LL))
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
|
||||
#define cpu_to_be16(x) endian_rev16(x)
|
||||
#define cpu_to_be32(x) endian_rev32(x)
|
||||
#define cpu_to_le16(x) (x)
|
||||
#define cpu_to_le32(x) (x)
|
||||
#define cpu_to_le64(x) (x)
|
||||
#define le16_to_cpu(x) (x)
|
||||
#define le32_to_cpu(x) (x)
|
||||
#define le64_to_cpu(x) (x)
|
||||
|
||||
#else
|
||||
|
||||
#define cpu_to_be16(x) (x)
|
||||
#define cpu_to_be32(x) (x)
|
||||
#define cpu_to_le16(x) endian_rev16(x)
|
||||
#define cpu_to_le32(x) endian_rev32(x)
|
||||
#define cpu_to_le64(x) endian_rev64(x)
|
||||
#define le16_to_cpu(x) endian_rev16(x)
|
||||
#define le32_to_cpu(x) endian_rev32(x)
|
||||
#define le64_to_cpu(x) endian_rev64(x)
|
||||
|
||||
#endif
|
||||
|
||||
#define const_le16_to_cpu(x) le16_to_cpu(x)
|
||||
#define const_cpu_to_le16(x) cpu_to_le16(x)
|
||||
#define const_cpu_to_le32(x) cpu_to_le32(x)
|
||||
#define const_cpu_to_be16(x) cpu_to_be16(x)
|
||||
#define const_cpu_to_be32(x) cpu_to_be32(x)
|
||||
|
||||
#endif /* _NTFS_ENDIANS_H */
|
||||
|
||||
#ifndef FALSE
|
||||
enum { FALSE, TRUE } ;
|
||||
#endif /* FALSE */
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
typedef unsigned short uid_t;
|
||||
typedef unsigned short gid_t;
|
||||
|
||||
#define UNICODE(c) ((unsigned short)(c))
|
||||
|
||||
#define __attribute__(x)
|
||||
|
||||
#else
|
||||
|
||||
#ifndef BOOL
|
||||
typedef int BOOL; /* Already defined in windows.h */
|
||||
#endif /* BOOL */
|
||||
|
||||
#ifdef STSC
|
||||
|
||||
#define ENOTSUP 95
|
||||
|
||||
#endif /* STSC */
|
||||
|
||||
typedef u32 DWORD; /* must be 32 bits whatever the platform */
|
||||
typedef DWORD *LPDWORD;
|
||||
|
||||
#define NTFS_MNT_NONE 0 /* no flag for mounting the device */
|
||||
#define NTFS_MNT_RDONLY 1 /* flag for mounting the device read-only */
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
#if defined(WIN32) | defined(STSC)
|
||||
|
||||
/*
|
||||
* On non-Linux computers, there is no mount and the user mapping
|
||||
* if fetched from a real file (or a dummy one for self tests)
|
||||
*/
|
||||
|
||||
#define NTFS_FIND_USID(map,uid,buf) ntfs_find_usid(map,uid,buf)
|
||||
#define NTFS_FIND_GSID(map,gid,buf) ntfs_find_gsid(map,gid,buf)
|
||||
#define NTFS_FIND_USER(map,usid) ntfs_find_user(map,usid)
|
||||
#define NTFS_FIND_GROUP(map,gsid) ntfs_find_group(map,gsid)
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* On Linux computers, there is a mount and the user mapping
|
||||
* if either obtained through the mount process or fetched
|
||||
* from a dummy file for self-tests
|
||||
*/
|
||||
|
||||
#define NTFS_FIND_USID(map,uid,buf) (mappingtype != MAPEXTERN ? \
|
||||
ntfs_find_usid(map,uid,buf) : relay_find_usid(map,uid,buf))
|
||||
#define NTFS_FIND_GSID(map,gid,buf) (mappingtype != MAPEXTERN ? \
|
||||
ntfs_find_gsid(map,gid,buf) : relay_find_gsid(map,gid,buf))
|
||||
#define NTFS_FIND_USER(map,usid) (mappingtype != MAPEXTERN ? \
|
||||
ntfs_find_user(map,usid) : relay_find_user(map,usid))
|
||||
#define NTFS_FIND_GROUP(map,gsid) (mappingtype != MAPEXTERN ? \
|
||||
ntfs_find_group(map,gsid) : relay_find_group(map,gsid))
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A few name hijackings or definitions
|
||||
* needed for using code from ntfs-3g
|
||||
*/
|
||||
|
||||
#ifdef WIN32
|
||||
#define ACL MY_ACL
|
||||
#define SID MY_SID
|
||||
#define ACCESS_ALLOWED_ACE MY_ACCESS_ALLOWED_ACE
|
||||
#define ACCESS_DENIED_ACE MY_ACCESS_DENIED_ACE
|
||||
#define FILE_ATTRIBUTE_REPARSE_POINT 0x400
|
||||
#define IO_REPARSE_TAG_MOUNT_POINT 0xa0000003
|
||||
#define IO_REPARSE_TAG_SYMLINK 0xa000000c
|
||||
#else
|
||||
#define SE_OWNER_DEFAULTED const_cpu_to_le16(1)
|
||||
#define SE_GROUP_DEFAULTED const_cpu_to_le16(2)
|
||||
#define SE_DACL_PRESENT const_cpu_to_le16(4)
|
||||
#define SE_SACL_PRESENT const_cpu_to_le16(0x10)
|
||||
#define SE_DACL_DEFAULTED const_cpu_to_le16(8)
|
||||
#define SE_SELF_RELATIVE const_cpu_to_le16(0x8000)
|
||||
#define SID_REVISION 1
|
||||
#endif /* WIN32 */
|
||||
#define SE_DACL_PROTECTED const_cpu_to_le16(0x1000)
|
||||
#define SE_SACL_PROTECTED const_cpu_to_le16(0x2000)
|
||||
#define SE_DACL_AUTO_INHERITED const_cpu_to_le16(0x400)
|
||||
#define SE_SACL_AUTO_INHERITED const_cpu_to_le16(0x800)
|
||||
#define SE_DACL_AUTO_INHERIT_REQ const_cpu_to_le16(0x100)
|
||||
#define SE_SACL_AUTO_INHERIT_REQ const_cpu_to_le16(0x200)
|
||||
|
||||
typedef le16 ntfschar;
|
||||
|
||||
#define ntfs_log_error(args...) do { printf("** " args); if (!isatty(1)) fprintf(stderr,args); } while(0)
|
||||
|
||||
/*
|
||||
* Struct to hold the input mapping file
|
||||
* (private to this module)
|
||||
*/
|
||||
|
||||
struct MAPLIST {
|
||||
struct MAPLIST *next;
|
||||
char *uidstr; /* uid text from the same record */
|
||||
char *gidstr; /* gid text from the same record */
|
||||
char *sidstr; /* sid text from the same record */
|
||||
char maptext[LINESZ + 1];
|
||||
};
|
||||
|
||||
/*
|
||||
* A few dummy declarations needed for using code from security.c
|
||||
*/
|
||||
|
||||
#define MFT_RECORD_IS_DIRECTORY const_cpu_to_le16(1)
|
||||
|
||||
struct SECURITY_DATA {
|
||||
u64 offset;
|
||||
char *attr;
|
||||
u32 hash;
|
||||
u32 length;
|
||||
unsigned int filecount:16;
|
||||
unsigned int mode:12;
|
||||
unsigned int flags:4;
|
||||
} ;
|
||||
|
||||
/* default security sub-authorities */
|
||||
enum {
|
||||
DEFSECAUTH1 = -1153374643, /* 3141592653 */
|
||||
DEFSECAUTH2 = 589793238,
|
||||
DEFSECAUTH3 = 462843383,
|
||||
DEFSECBASE = 10000
|
||||
};
|
||||
|
||||
#define OWNERID 1016
|
||||
#define GROUPID 513
|
||||
|
||||
|
||||
#define INSDS1 1
|
||||
#define INSDS2 2
|
||||
#define INSII 4
|
||||
#define INSDH 8
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
typedef enum { RECSHOW, RECSET, RECSETPOSIX } RECURSE;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A type large enough to hold any SID
|
||||
*/
|
||||
|
||||
typedef char BIGSID[40];
|
||||
|
||||
/*
|
||||
* Declarations for memory allocation checks
|
||||
*/
|
||||
|
||||
struct CHKALLOC
|
||||
{
|
||||
struct CHKALLOC *next;
|
||||
void *alloc;
|
||||
const char *file;
|
||||
int line;
|
||||
size_t size;
|
||||
} ;
|
||||
|
||||
#if defined(WIN32) | defined(STSC)
|
||||
|
||||
#define S_ISVTX 01000
|
||||
#define S_ISGID 02000
|
||||
#define S_ISUID 04000
|
||||
#define S_IXUSR 0100
|
||||
#define S_IWUSR 0200
|
||||
#define S_IRUSR 0400
|
||||
#define S_IXGRP 010
|
||||
#define S_IWGRP 020
|
||||
#define S_IRGRP 040
|
||||
#define S_IXOTH 001
|
||||
#define S_IWOTH 002
|
||||
#define S_IROTH 004
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#else
|
||||
/*
|
||||
*
|
||||
* See http://msdn2.microsoft.com/en-us/library/aa379649.aspx
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
DACL_SECURITY_INFORMATION = 4, // The DACL of the object is being referenced.
|
||||
SACL_SECURITY_INFORMATION = 8, // The SACL of the object is being referenced.
|
||||
LABEL_SECURITY_INFORMATION = 8, // The mandatory integrity label is being referenced.
|
||||
GROUP_SECURITY_INFORMATION = 2, // The primary group identifier of the object is being referenced.
|
||||
OWNER_SECURITY_INFORMATION = 1, // The owner identifier of the object is being referenced.
|
||||
} SECURITY_INFORMATION;
|
||||
|
||||
#define STANDARD_RIGHTS_READ const_cpu_to_le32(0x20000)
|
||||
#define STANDARD_RIGHTS_WRITE const_cpu_to_le32(0x20000)
|
||||
#define STANDARD_RIGHTS_EXECUTE const_cpu_to_le32(0x20000)
|
||||
#define STANDARD_RIGHTS_REQUIRED const_cpu_to_le32(0xf0000)
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct SECHEAD {
|
||||
s8 revision;
|
||||
s8 alignment;
|
||||
le16 control;
|
||||
le32 owner;
|
||||
le32 group;
|
||||
le32 sacl;
|
||||
le32 dacl;
|
||||
} SECURITY_DESCRIPTOR_RELATIVE;
|
||||
|
||||
typedef struct ACL {
|
||||
s8 revision;
|
||||
s8 alignment1;
|
||||
le16 size;
|
||||
le16 ace_count;
|
||||
le16 alignment2;
|
||||
} ACL;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
unsigned char revision;
|
||||
unsigned char sub_authority_count;
|
||||
} ;
|
||||
struct {
|
||||
/* evade an alignment problem when a 4 byte field */
|
||||
/* in a struct implies alignment of the struct */
|
||||
le16 dummy;
|
||||
be16 high_part;
|
||||
be32 low_part;
|
||||
} identifier_authority;
|
||||
} ;
|
||||
le32 sub_authority[1];
|
||||
} SID;
|
||||
|
||||
typedef u8 ACE_FLAGS;
|
||||
|
||||
typedef struct ACE {
|
||||
u8 type;
|
||||
u8 flags;
|
||||
le16 size;
|
||||
le32 mask;
|
||||
SID sid;
|
||||
} ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE;
|
||||
|
||||
|
||||
/*
|
||||
* item in the mapping list
|
||||
*/
|
||||
|
||||
struct MAPPING {
|
||||
struct MAPPING *next;
|
||||
int xid; /* linux id : uid or gid */
|
||||
SID *sid; /* Windows id : usid or gsid */
|
||||
int grcnt; /* group count (for users only) */
|
||||
gid_t *groups; /* groups which the user is member of */
|
||||
};
|
||||
|
||||
/*
|
||||
* Posix ACL structures
|
||||
*/
|
||||
|
||||
struct POSIX_ACE {
|
||||
u16 tag;
|
||||
u16 perms;
|
||||
s32 id;
|
||||
} ;
|
||||
|
||||
struct POSIX_ACL {
|
||||
u8 version;
|
||||
u8 flags;
|
||||
u16 filler;
|
||||
struct POSIX_ACE ace[0];
|
||||
} ;
|
||||
|
||||
struct POSIX_SECURITY {
|
||||
mode_t mode;
|
||||
int acccnt;
|
||||
int defcnt;
|
||||
int firstdef;
|
||||
u16 tagsset;
|
||||
struct POSIX_ACL acl;
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Posix tags, cpu-endian 16 bits
|
||||
*/
|
||||
|
||||
enum {
|
||||
POSIX_ACL_USER_OBJ = 1,
|
||||
POSIX_ACL_USER = 2,
|
||||
POSIX_ACL_GROUP_OBJ = 4,
|
||||
POSIX_ACL_GROUP = 8,
|
||||
POSIX_ACL_MASK = 16,
|
||||
POSIX_ACL_OTHER = 32,
|
||||
POSIX_ACL_SPECIAL = 64 /* internal use only */
|
||||
} ;
|
||||
|
||||
/*
|
||||
* Posix permissions, cpu-endian 16 bits
|
||||
*/
|
||||
|
||||
enum {
|
||||
POSIX_PERM_X = 1,
|
||||
POSIX_PERM_W = 2,
|
||||
POSIX_PERM_R = 4,
|
||||
POSIX_PERM_DENIAL = 64 /* internal use only */
|
||||
} ;
|
||||
|
||||
#define POSIX_VERSION 2
|
||||
|
||||
/*
|
||||
* A few definitions adapted from winnt.h
|
||||
* (Windows version uses actual definitions from winnt.h, which are
|
||||
* not compatible with code from security.c on a big-endian computer)
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#define DELETE const_cpu_to_le32(0x00010000L)
|
||||
#define READ_CONTROL const_cpu_to_le32(0x00020000L)
|
||||
#define WRITE_DAC const_cpu_to_le32(0x00040000L)
|
||||
#define WRITE_OWNER const_cpu_to_le32(0x00080000L)
|
||||
#define SYNCHRONIZE const_cpu_to_le32(0x00100000L)
|
||||
|
||||
|
||||
#define FILE_READ_DATA const_cpu_to_le32(0x0001) // file & pipe
|
||||
#define FILE_LIST_DIRECTORY const_cpu_to_le32(0x0001) // directory
|
||||
|
||||
#define FILE_WRITE_DATA const_cpu_to_le32(0x0002) // file & pipe
|
||||
#define FILE_ADD_FILE const_cpu_to_le32(0x0002) // directory
|
||||
|
||||
#define FILE_APPEND_DATA const_cpu_to_le32(0x0004) // file
|
||||
#define FILE_ADD_SUBDIRECTORY const_cpu_to_le32(0x0004) // directory
|
||||
#define FILE_CREATE_PIPE_INSTANCE const_cpu_to_le32(0x0004) // named pipe
|
||||
|
||||
|
||||
#define FILE_READ_EA const_cpu_to_le32(0x0008) // file & directory
|
||||
|
||||
#define FILE_WRITE_EA const_cpu_to_le32(0x0010) // file & directory
|
||||
|
||||
#define FILE_EXECUTE const_cpu_to_le32(0x0020) // file
|
||||
#define FILE_TRAVERSE const_cpu_to_le32(0x0020) // directory
|
||||
|
||||
#define FILE_DELETE_CHILD const_cpu_to_le32(0x0040) // directory
|
||||
|
||||
#define FILE_READ_ATTRIBUTES const_cpu_to_le32(0x0080) // all
|
||||
|
||||
#define FILE_WRITE_ATTRIBUTES const_cpu_to_le32(0x0100) // all
|
||||
|
||||
#define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
|
||||
const_cpu_to_le32(0x1FF))
|
||||
|
||||
#define FILE_GENERIC_READ (STANDARD_RIGHTS_READ |\
|
||||
FILE_READ_DATA |\
|
||||
FILE_READ_ATTRIBUTES |\
|
||||
FILE_READ_EA |\
|
||||
SYNCHRONIZE)
|
||||
|
||||
|
||||
#define FILE_GENERIC_WRITE (STANDARD_RIGHTS_WRITE |\
|
||||
FILE_WRITE_DATA |\
|
||||
FILE_WRITE_ATTRIBUTES |\
|
||||
FILE_WRITE_EA |\
|
||||
FILE_APPEND_DATA |\
|
||||
SYNCHRONIZE)
|
||||
|
||||
|
||||
#define FILE_GENERIC_EXECUTE (STANDARD_RIGHTS_EXECUTE |\
|
||||
FILE_READ_ATTRIBUTES |\
|
||||
FILE_EXECUTE |\
|
||||
SYNCHRONIZE)
|
||||
|
||||
#define GENERIC_READ const_cpu_to_le32(0x80000000L)
|
||||
#define GENERIC_WRITE const_cpu_to_le32(0x40000000L)
|
||||
#define GENERIC_EXECUTE const_cpu_to_le32(0x20000000L)
|
||||
#define GENERIC_ALL const_cpu_to_le32(0x10000000L)
|
||||
|
||||
|
||||
#define OBJECT_INHERIT_ACE (0x1)
|
||||
#define CONTAINER_INHERIT_ACE (0x2)
|
||||
#define NO_PROPAGATE_INHERIT_ACE (0x4)
|
||||
#define INHERIT_ONLY_ACE (0x8)
|
||||
#define INHERITED_ACE (0x10)
|
||||
#define VALID_INHERIT_FLAGS (0x1F)
|
||||
|
||||
/*
|
||||
* Other useful definitions
|
||||
*/
|
||||
|
||||
#define ACL_REVISION 2
|
||||
#define ACCESS_ALLOWED_ACE_TYPE 0
|
||||
#define ACCESS_DENIED_ACE_TYPE 1
|
||||
#define SECURITY_DESCRIPTOR_REVISION 1
|
||||
|
||||
#endif /* !WIN32 */
|
||||
|
||||
#ifndef ACL_REVISION_DS /* not always defined in <windows.h> */
|
||||
#define ACL_REVISION_DS 4
|
||||
#endif
|
||||
|
||||
#ifndef INHERITED_ACE /* not always defined in <windows.h> */
|
||||
#define INHERITED_ACE (0x10)
|
||||
#undef VALID_INHERIT_FLAGS
|
||||
#define VALID_INHERIT_FLAGS (0x1F)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Matching of ntfs permissions to Linux permissions
|
||||
* these constants are adapted to endianness
|
||||
* when setting, set them all
|
||||
* when checking, check one is present
|
||||
*/
|
||||
|
||||
/* flags which are set to mean exec, write or read */
|
||||
|
||||
#define FILE_READ (FILE_READ_DATA)
|
||||
#define FILE_WRITE (FILE_WRITE_DATA | FILE_APPEND_DATA \
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
#define FILE_EXEC (FILE_EXECUTE)
|
||||
#define DIR_READ FILE_LIST_DIRECTORY
|
||||
#define DIR_WRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD \
|
||||
| READ_CONTROL | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA)
|
||||
#define DIR_EXEC (FILE_TRAVERSE)
|
||||
|
||||
/* flags tested for meaning exec, write or read */
|
||||
/* tests for write allow for interpretation of a sticky bit */
|
||||
|
||||
#define FILE_GREAD (FILE_READ_DATA | GENERIC_READ | GENERIC_ALL)
|
||||
#define FILE_GWRITE (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE \
|
||||
| GENERIC_ALL)
|
||||
#define FILE_GEXEC (FILE_EXECUTE | GENERIC_EXECUTE | GENERIC_ALL)
|
||||
#define DIR_GREAD (FILE_LIST_DIRECTORY | GENERIC_READ | GENERIC_ALL)
|
||||
#define DIR_GWRITE (FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | GENERIC_WRITE \
|
||||
| GENERIC_ALL)
|
||||
#define DIR_GEXEC (FILE_TRAVERSE | GENERIC_EXECUTE | GENERIC_ALL)
|
||||
|
||||
/* standard owner (and administrator) rights */
|
||||
|
||||
#define OWNER_RIGHTS (DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER \
|
||||
| SYNCHRONIZE \
|
||||
| FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES \
|
||||
| FILE_READ_EA | FILE_WRITE_EA)
|
||||
|
||||
/* standard world rights */
|
||||
|
||||
#define WORLD_RIGHTS (READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA \
|
||||
| SYNCHRONIZE)
|
||||
|
||||
/* inheritance flags for files and directories */
|
||||
|
||||
#define FILE_INHERITANCE NO_PROPAGATE_INHERIT_ACE
|
||||
#define DIR_INHERITANCE (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE)
|
||||
|
||||
/*
|
||||
* To identify NTFS ACL meaning Posix ACL granted to root
|
||||
* we use rights always granted to anybody, so they have no impact
|
||||
* either on Windows or on Linux.
|
||||
*/
|
||||
|
||||
#define ROOT_OWNER_UNMARK SYNCHRONIZE /* ACL granted to root as owner */
|
||||
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
|
||||
|
||||
|
||||
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;
|
||||
} ;
|
||||
|
||||
#ifndef INVALID_FILE_ATTRIBUTES /* not defined in old windows.h */
|
||||
#define INVALID_FILE_ATTRIBUTES (-1)
|
||||
#endif
|
||||
|
||||
enum { MAPUSERS, MAPGROUPS, MAPCOUNT } ;
|
||||
|
||||
struct SECURITY_CONTEXT {
|
||||
struct MAPPING *mapping[MAPCOUNT];
|
||||
} ;
|
||||
|
||||
typedef enum { MAPNONE, MAPEXTERN, MAPLOCAL, MAPDUMMY } MAPTYPE;
|
||||
|
||||
|
||||
|
||||
struct passwd {
|
||||
uid_t pw_uid;
|
||||
} ;
|
||||
|
||||
struct group {
|
||||
gid_t gr_gid;
|
||||
} ;
|
||||
|
||||
typedef int (*FILEREADER)(void *fileid, char *buf, size_t size, off_t pos);
|
||||
|
||||
/*
|
||||
* Data defined in secaudit.c
|
||||
*/
|
||||
|
||||
extern MAPTYPE mappingtype;
|
||||
|
||||
/*
|
||||
* Functions defined in acls.c
|
||||
*/
|
||||
|
||||
BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz);
|
||||
BOOL ntfs_valid_posix(const struct POSIX_SECURITY *pxdesc);
|
||||
BOOL ntfs_valid_pattern(const SID *sid);
|
||||
BOOL ntfs_same_sid(const SID *first, const SID *second);
|
||||
|
||||
|
||||
int ntfs_sid_size(const SID * sid);
|
||||
unsigned int ntfs_attr_size(const char *attr);
|
||||
|
||||
const SID *ntfs_find_usid(const struct MAPPING *usermapping,
|
||||
uid_t uid, SID *pdefsid);
|
||||
const SID *ntfs_find_gsid(const struct MAPPING *groupmapping,
|
||||
gid_t gid, SID *pdefsid);
|
||||
uid_t ntfs_find_user(const struct MAPPING *usermapping, const SID *usid);
|
||||
gid_t ntfs_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
||||
const SID *ntfs_acl_owner(const char *secattr);
|
||||
|
||||
void ntfs_sort_posix(struct POSIX_SECURITY *pxdesc);
|
||||
int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode);
|
||||
|
||||
|
||||
struct POSIX_SECURITY *ntfs_build_permissions_posix(
|
||||
struct MAPPING* const mapping[],
|
||||
const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
int ntfs_build_permissions(const char *securattr,
|
||||
const SID *usid, const SID *gsid, BOOL isdir);
|
||||
struct MAPLIST *ntfs_read_mapping(FILEREADER reader, void *fileid);
|
||||
struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem);
|
||||
struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem);
|
||||
void ntfs_free_mapping(struct MAPPING *mapping[]);
|
||||
|
||||
struct POSIX_SECURITY *ntfs_merge_descr_posix(const struct POSIX_SECURITY *first,
|
||||
const struct POSIX_SECURITY *second);
|
||||
char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
|
||||
struct POSIX_SECURITY *pxdesc,
|
||||
int isdir, const SID *usid, const SID *gsid);
|
||||
char *ntfs_build_descr(mode_t mode,
|
||||
int isdir, const SID * usid, const SID * gsid);
|
||||
|
||||
/*
|
||||
* Functions defined in secaudit.c
|
||||
*/
|
||||
|
||||
void *chkmalloc(size_t, const char*, int);
|
||||
void *chkcalloc(size_t, size_t, const char *, int);
|
||||
void chkfree(void*, const char*, int);
|
||||
BOOL chkisalloc(void*, const char*, int);
|
||||
void dumpalloc(const char*);
|
||||
|
||||
#define malloc(sz) chkmalloc(sz, __FILE__, __LINE__)
|
||||
#define calloc(cnt,sz) chkcalloc(cnt, sz, __FILE__, __LINE__)
|
||||
#define free(ptr) chkfree(ptr, __FILE__, __LINE__)
|
||||
#define isalloc(ptr) chkisalloc(ptr, __FILE__, __LINE__)
|
||||
#define ntfs_malloc(sz) chkmalloc(sz, __FILE__, __LINE__)
|
||||
|
||||
struct passwd *getpwnam(const char *user);
|
||||
struct group *getgrnam(const char *group);
|
||||
|
||||
const SID *relay_find_usid(const struct MAPPING *usermapping,
|
||||
uid_t uid, SID *pdefsid);
|
||||
const SID *relay_find_gsid(const struct MAPPING *groupmapping,
|
||||
gid_t gid, SID *pdefsid);
|
||||
uid_t relay_find_user(const struct MAPPING *usermapping, const SID *usid);
|
||||
gid_t relay_find_group(const struct MAPPING *groupmapping, const SID * gsid);
|
||||
|
Loading…
Reference in New Issue