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.c
edge.strict_endians
Erik Larsson 2017-03-21 05:41:54 +01:00
commit 26ed262ae4
67 changed files with 4044 additions and 5110 deletions

15
README
View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -30,7 +30,8 @@ headers = \
mst.h \
ntfstime.h \
object_id.h \
param.h \
param.h \
plugin.h \
realpath.h \
reparse.h \
runlist.h \

View File

@ -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

View File

@ -37,6 +37,10 @@
#define ENODATA ENOENT
#endif
#ifndef ELIBBAD
#define ELIBBAD ENOEXEC
#endif
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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_ */

View File

@ -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"

View File

@ -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
}
}

View File

@ -19,6 +19,7 @@
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <paths.h>
#ifdef __SOLARIS__
#include <sys/mnttab.h>

View File

@ -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) {

View File

@ -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__

View File

@ -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)

View File

@ -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");

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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>

View File

@ -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");

View File

@ -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 "

View File

@ -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.

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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))

View File

@ -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;

View File

@ -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");

View File

@ -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);
}

View File

@ -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(

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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:

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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);