Compare commits

..

10 Commits

Author SHA1 Message Date
szaka 74686cd644 release 2010.1.16 2010-01-15 19:33:29 +00:00
szaka c32f2a4f59 ntfs_attr_pclose: fix uninitialized variable which may lead to an infinite
loop on a read-only file system (Erik Larsson, Jean-Pierre Andre)
2010-01-15 19:32:44 +00:00
szaka 670d72620d fix compilation on OS X (Erik Larsson) 2010-01-15 16:18:21 +00:00
szaka 1af26b3d03 release 2010.1.15 2010-01-15 00:43:43 +00:00
szaka 09dec85cd8 secaudit: fix compilation on Mac OS X, OpenSuse and OpenSolaris (Jean-Pierre Andre) 2010-01-15 00:41:23 +00:00
szaka 5807572640 fix stat.h/attr.h related compilation errors (Jean-Pierre Andre) 2010-01-15 00:31:50 +00:00
szaka 2dfa3412da fix compilation error with -Werror on openSUSE 2010-01-15 00:24:03 +00:00
szaka 51f768af3b fix non-resident TXF_DATA creation, despite its AttrDef definition,
which caused Vista and later not being able to access files, volumes
(Anton Altaparmakov, Erik Larsson, Jean-Pierre Andre, Szabolcs Szakacsits)
2010-01-15 00:04:23 +00:00
szaka c7252ba416 Non-ascii characters in junctions may lead to segfault (Jean-Pierre Andre) 2010-01-14 23:48:42 +00:00
mechie b2b236656a This commit was manufactured by cvs2svn to create branch
'N2009_11_14_FIXES'.
2009-11-13 20:49:40 +00:00
163 changed files with 9733 additions and 74756 deletions

20
CREDITS
View File

@ -38,24 +38,4 @@ Ismail Donmez
Laszlo Dvornik
Pallaghy Ajtony
Szabolcs Szakacsits
Alexei Alexandrov
Albert D. Cahalan
Russ Christensen
Pete Curran
Andras Erdei
Matthew J. Fanto
Marcin GibuÅa
Christophe Grenier
Ian Jackson
Carmelo Kintana
Jan Kratochvil
Lode Leroy
David Martínez Moreno
Giang Nguyen
Leonard Norrgård
Holger Ohmacht
Per Olofsson
Yuri Per
Richard Russon
Erik Sørnes

View File

@ -1,3 +1,7 @@
ChangeLog can be found at :
https://github.com/tuxera/ntfs-3g/wiki
Detailed ChangeLog can be found at http://mercurial.creo.hu/repos/ntfs-3g-hg/
Alternatively it can be generated from the CVS source repository by cvs2cl.pl.
Instructions for CVS access: http://sourceforge.net/cvs/?group_id=181143
Home of the cvs2cl.pl utility: http://www.red-bean.com/cvs2cl/

View File

@ -24,37 +24,9 @@ MAINTAINERCLEANFILES=\
$(srcdir)/m4/lt~obsolete.m4 \
$(srcdir)/m4/ltoptions.m4
SUBDIRS = include libfuse-lite libntfs-3g ntfsprogs src
SUBDIRS = include libfuse-lite libntfs-3g src
doc_DATA = README
dist-hook:
$(MKDIR_P) "$(distdir)/m4"
libtool: $(LIBTOOL_DEPS)
$(SHELL) ./config.status --recheck
libs:
if FUSE_INTERNAL
(cd libfuse-lite && $(MAKE) libs) || exit 1;
endif
(cd libntfs-3g && $(MAKE) libs) || exit 1;
libntfs:
(cd libntfs-3g && $(MAKE) libs) || exit 1;
drivers: libs
(cd src && $(MAKE) drivers) || exit 1;
ntfsprogs: libntfs
(cd ntfsprogs && $(MAKE)) || exit 1;
if ENABLE_NTFSPROGS
strip:
(cd ntfsprogs && $(MAKE) strip) || exit 1;
extra: extras
extras: libs
(cd ntfsprogs && $(MAKE) extras) || exit 1;
endif

6
NEWS
View File

@ -1,3 +1,5 @@
Project information can be found at :
https://github.com/tuxera/ntfs-3g/
Project news are at http://www.ntfs-3g.org
Release notes are maintained at http://www.ntfs-3g.org/releases.html

128
README
View File

@ -3,10 +3,9 @@ INTRODUCTION
============
The NTFS-3G driver is an open source, freely available read/write NTFS driver
for Linux, FreeBSD, macOS, NetBSD, OpenIndiana, QNX and Haiku. It provides
for Linux, FreeBSD, Mac OS X, NetBSD, OpenSolaris, QNX and Haiku. It provides
safe and fast handling of the Windows XP, Windows Server 2003, Windows 2000,
Windows Vista, Windows Server 2008, Windows 7, Windows 8, Windows Server 2012,
Windows Server 2016, Windows 10 and Windows Server 2019 NTFS file systems.
Windows Vista, Windows Server 2008 and Windows 7 file systems.
The purpose of the project is to develop, quality assurance and support a
trustable, featureful and high performance solution for hardware platforms
@ -17,69 +16,35 @@ 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 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.
and creating compressed files. Parameter files in the directory .NTFS-3G may
be required to enable them, please get the instructions from
http://www.tuxera.com/community/ntfs-3g-advanced/
News, support answers, problem submission instructions, support and discussion
forums, and other information are available on the project web site at
forums, performance numbers and other information are available on the project
web site at
https://github.com/tuxera/ntfs-3g/wiki
The project has been funded, supported and maintained since 2008 by Tuxera:
https://tuxera.com
LICENSES
========
All the NTFS related components: the file system drivers, the ntfsprogs
utilities and the shared library libntfs-3g are distributed 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. See the included file COPYING.
The fuse-lite library is distributed under the terms of the GNU LGPLv2.
See the included file COPYING.LIB.
http://www.tuxera.com/community/
QUICK INSTALLATION
==================
Most distributions have an up-to-date NTFS-3G package ready for use, and
the recommended way is to install it.
If you need some specific customization, you can compile and install from
the released source code. Make sure you have the basic development tools
and the kernel includes the FUSE kernel module. Then unpack the source
tarball and type:
Linux: Make sure you have the basic development tools and the kernel includes
the FUSE kernel module. Then unpack the source tarball and type:
./configure
make
make install # or 'sudo make install' if you aren't root.
Please note that NTFS-3G doesn't require the FUSE user space package any
more.
Please note that NTFS-3G doesn't require the FUSE user space package.
The list of options for building specific configurations is displayed by
typing :
Non-Linux: Please see
./configure --help
http://www.tuxera.com/community/ntfs-3g-download/
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)
There are also a few make targets for building parts :
make libntfs : only build the libntfs-3g library
make libs : only build libntfs-3g (and libfuse-lite, if relevant)
make drivers : only build drivers and libraries, without ntfsprogs
make ntfsprogs : only build ntfsprogs and libntfs-3g, without drivers
for OS specific installation and source packages.
USAGE
@ -101,66 +66,3 @@ line at the END(!) of the /etc/fstab file:
/dev/sda1 /mnt/windows ntfs-3g defaults 0 0
TESTING WITHOUT INSTALLING
=========================
Newer versions of ntfs-3g can be tested without installing anything and
without disturbing an existing installation. Just configure and make as
shown previously. This will create the scripts ntfs-3g and lowntfs-3g
in the src directory, which you may activate for testing:
./configure
make
then, as root:
src/ntfs-3g [-o mount-options] /dev/sda1 /mnt/windows
And, to end the test, unmount the usual way:
umount /dev/sda1
NTFS UTILITIES
==============
The ntfsprogs directory includes utilities for doing all required tasks to
NTFS partitions. In general, just run a utility without any command line
options to display the version number and usage syntax.
The following utilities are so far implemented:
ntfsfix - Attempt to fix an NTFS partition and force Windows to check NTFS.
mkntfs - Format a partition with the NTFS filesystem. See man 8 mkntfs for
command line options.
ntfslabel - Display/change the label of an NTFS partition. See man 8 ntfslabel
for details.
ntfsundelete - Recover deleted files from an NTFS volume. See man 8
ntfsundelete for more details.
ntfsresize - Resize NTFS volumes. See man 8 ntfsresize for details.
ntfsclone - Efficiently create/restore an image of an NTFS partition. See
man 8 ntfsclone for details.
ntfscluster - Locate the owner of any given sector or cluster on an NTFS
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

@ -1,126 +0,0 @@
Please keep in alphabetical order so utilities are easier to find.
Thanks,
Anton
**********
* mkntfs *
**********
- Correct support for creating volumes with larger sector sizes (mft record
size, cluster size, and index block size must be >= sector size), so for 1k,
2k, and 4k sectors, we need to set the default mft record, cluster, and index
block size to be at least the sector size.
- Correct the odd last partition sector not being accessible under 2.4 kernels
by setting the device block size to the sector size (default is 1k on 2.4
kernels and they can't cope with partial sectors).
- Got a report that creating a floppy with mkntfs failed. Difference between
this floppy and the floppy created by the special tool found on the net was
said to be that the bitmap is 256kib on the special floppy while mkntfs will
make it much smaller. Need to verify this and experiment with the bitmap
size to make it work. Note, reporter was using win2k.
*************
* ntfsclone *
*************
- get rid of the unneeded lseek()'s during reads/writes (probably it
doesn't improve performance much, or any at all)
- catch if source and dest are the same
- disable consistency check for --metadata (e.g. if the check is crashing)
- option: --inode
- option: --data
- metadata cloning: skip more non-needed inodes
- manual: document LFS issues (smbfs' lfs option, nfs)
- manual: mention optimized seeks
- manual: optimal backup if disks have bad sectors
- manual: ntfsclone guarantees the restored image works only
if one restores to the exactly same partition. For example,
one can not copy system partition to a different partition:
minimum "hidden sectors" field and BOOT.INI need modifications.
We could do these adjustments optionally.
- check if kernel block size = GCD(page size, device size) makes
effect on performance (Al Viro says no)
- check whether the O_WRONLY -> O_RDWR change made effect on performance
***********
* ntfscmp *
***********
- compare mft record headers
- exit status is 0 if inputs are the same, 1 if different, other if trouble
- optionally ignore less interesting fields (e.g. attribute instance)
- new option: --metadata mode
- unnamed resident attributes with same type are ignored
- code cleanup, remove many cross-util duplicates
- handle deleted records
- performance: special handling for sparse files
**********
* ntfscp *
**********
- add ability to copy multiple files at once.
***********
* ntfsfix *
***********
- Cleanup to use ntfs_attr_* API for editing $MFTMirr, $Volume, and $LogFile.
This has the immediate benefit of enabling attribute list support and making
the code simpler.
- On ntfs 3.0+ volumes need to disable the usn journal if it is active. This
means deleting file $UsnJrnl from /$Extend directory.
- On ntfs 3.0+ volumes need to mark the quota out of date? - Probably, but
it shouldn't cause any corruption not doing so for the moment so this is
not a showstopper bug for the first release. (AIA)
*************
* ntfslabel *
*************
- Support ioctls for kernel driver and ntfsmount for reading/changing the label.
*************
* ntfsmount *
*************
**************
* ntfsresize *
**************
High priority
- move ntfs consistency check to libntfs (for ntfsck, ntfsclone, etc)
- use different exit codes (e.g. corrupt volume detected, unsupported case,
bad sectors, etc)
Medium priority
- cope with the rare, unsupported cases, see man ntfsresize 'KNOWN ISSUES'
- save $Bitmap if it was modified and an error occures (e.g. bad sector).
- handle signals (^C, etc)
Low priority
- fully support disks with bad sectors (attrlist attr, unknown bad sectors)
- move volume start
****************
* ntfsundelete *
****************
- undelete by name rather than inode number
- support for compressed files
- support for internationalisation
- recover by type?
- mass undelete (using wildcards)
- display parent directory
- name "<none>" to MFTn

View File

@ -2,8 +2,7 @@
# configure.ac - Source file to generate "./configure" to prepare package for
# compilation.
#
# Copyright (c) 2000-2013 Anton Altaparmakov
# Copyright (c) 2003 Jan Kratochvil
# Copyright (c) 2000-2006 Anton Altaparmakov
# Copyright (c) 2005-2009 Szabolcs Szakacsits
# Copyright (C) 2007-2008 Alon Bar-Lev
#
@ -24,8 +23,8 @@
# Autoconf
AC_PREREQ(2.59)
AC_INIT([ntfs-3g],[2022.10.3],[ntfs-3g-devel@lists.sf.net])
LIBNTFS_3G_VERSION="89"
AC_INIT([ntfs-3g],[2010.1.16],[ntfs-3g-devel@lists.sf.net])
LIBNTFS_3G_VERSION="73"
AC_CONFIG_SRCDIR([src/ntfs-3g.c])
# Environment
@ -33,7 +32,7 @@ AC_CANONICAL_HOST
AC_CANONICAL_TARGET
# Automake
AM_INIT_AUTOMAKE([])
AM_INIT_AUTOMAKE([${PACKAGE_NAME}], [${PACKAGE_VERSION}])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AM_MAINTAINER_MODE
@ -114,21 +113,6 @@ AC_ARG_ENABLE(
[enable_posix_acls="no"]
)
AC_ARG_ENABLE(
[xattr-mappings],
[AS_HELP_STRING([--enable-xattr-mappings],[enable system extended attributes mappings])],
,
[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])],
@ -136,43 +120,6 @@ AC_ARG_ENABLE(
[enable_device_default_io_ops="yes"]
)
AC_ARG_ENABLE(
[ntfs-3g],
[AS_HELP_STRING([--disable-ntfs-3g],[disable the ntfs-3g FUSE driver])],
,
[enable_ntfs_3g="yes"]
)
AC_ARG_ENABLE(
[ntfsprogs],
[AS_HELP_STRING([--disable-ntfsprogs],[disable ntfsprogs utilities
(default=no)])],
,
[enable_ntfsprogs="yes"]
)
AC_ARG_ENABLE(crypto,
AS_HELP_STRING(--enable-crypto,enable crypto related code and utilities
(default=no)), ,
enable_crypto=no
)
AC_ARG_ENABLE(
[extras],
[AS_HELP_STRING([--enable-extras],[enable extra ntfsprogs utilities
(default=no)])],
,
[enable_extras="no"]
)
AC_ARG_ENABLE(
[quarantined],
[AS_HELP_STRING([--enable-quarantined],[enable quarantined ntfsprogs utilities
(default=no)])],
,
[enable_quarantined="no"]
)
AC_ARG_ENABLE(
[nfconv],
[AS_HELP_STRING([--disable-nfconv],[disable the 'nfconv' patch, which adds support for Unicode normalization form conversion when built on Mac OS X @<:@default=enabled for Mac OS X@:>@])],
@ -199,9 +146,6 @@ ifdef(
[AC_PROG_LIBTOOL]
)
AC_PROG_INSTALL
PKG_PROG_PKG_CONFIG
AC_PATH_PROG([MV], [mv])
AC_PATH_PROG([RM], [rm])
AC_PATH_PROG([SED], [sed])
@ -226,31 +170,27 @@ case "${target}" in
;;
esac
if test "x${enable_ntfs_3g}" != "xyes"; then
with_fuse="none"
elif test "x${with_fuse}" = "x"; then
AC_MSG_CHECKING([fuse compatibility])
case "${target_os}" in
linux*|solaris*)
AC_ARG_WITH(
[fuse],
[AS_HELP_STRING([--with-fuse=<internal|external>],[Select FUSE library: internal or external @<:@default=internal@:>@])],
,
[with_fuse="internal"]
)
;;
darwin*|netbsd*|kfreebsd*-gnu)
with_fuse="external"
;;
freebsd*)
AC_MSG_ERROR([Please see FreeBSD support at http://www.freshports.org/sysutils/fusefs-ntfs])
;;
*)
AC_MSG_ERROR([ntfs-3g can be built for Linux, FreeBSD, Mac OS X, NetBSD, and Solaris only.])
;;
esac
AC_MSG_RESULT([${with_fuse}])
fi
AC_MSG_CHECKING([fuse compatibility])
case "${target_os}" in
linux*)
AC_ARG_WITH(
[fuse],
[AS_HELP_STRING([--with-fuse=<internal|external>],[Select FUSE library: internal or external @<:@default=internal@:>@])],
,
[with_fuse="internal"]
)
;;
darwin*|netbsd*|solaris*)
with_fuse="external"
;;
freebsd*)
AC_MSG_ERROR([Please see FreeBSD support at http://www.freshports.org/sysutils/fusefs-ntfs])
;;
*)
AC_MSG_ERROR([ntfs-3g can be built for Linux, FreeBSD, Mac OS X, NetBSD, and Solaris only.])
;;
esac
AC_MSG_RESULT([${with_fuse}])
case "${target_os}" in
solaris*)
@ -290,28 +230,7 @@ if test "${with_fuse}" = "internal"; then
[1],
[Define to 1 if using internal fuse]
)
AC_MSG_CHECKING([Solaris OS])
AC_LANG_PUSH([C])
AC_COMPILE_IFELSE(
[
AC_LANG_SOURCE(
[[#if !((defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)))]]
[[#error "Not a Solaris system."]]
[[#endif]]
)
],
[
AC_MSG_RESULT([yes])
LIBFUSE_LITE_CFLAGS="${LIBFUSE_LITE_CFLAGS} -std=c99 -D__SOLARIS__ -D_XOPEN_SOURCE=600 -D__EXTENSIONS__"
LIBFUSE_LITE_LIBS="${LIBFUSE_LITE_LIBS} -lxnet"
],
[
AC_MSG_RESULT([no])
]
)
AC_LANG_POP([C])
elif test "${with_fuse}" = "external"; then
else
if test -z "$PKG_CONFIG"; then
AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
fi
@ -330,158 +249,15 @@ elif test "${with_fuse}" = "external"; then
FUSE_LIB_PATH=`$PKG_CONFIG --libs-only-L fuse | sed -e 's,/[/]*,/,g' -e 's,[ ]*$,,'`
fi
# Autodetect whether we can build crypto stuff or not.
compile_crypto=false
if test "$enable_crypto" != "no"; then
have_libgcrypt=false
AM_PATH_LIBGCRYPT(1.2.2, [ have_libgcrypt=true ],
[
if test "$enable_crypto" = "yes"; then
AC_MSG_ERROR([ntfsprogs crypto code requires the gcrypt library.])
else
AC_MSG_WARN([ntfsprogs crypto code requires the gcrypt library.])
fi
])
have_libgnutls=false
PKG_CHECK_MODULES(GNUTLS, gnutls >= 1.4.4, [ have_libgnutls=true ],
if test "$enable_crypto" = "yes"; then
AC_MSG_ERROR([ntfsprogs crypto code requires the gnutls library.])
else
AC_MSG_WARN([ntfsprogs crypto code requires the gnutls library.])
fi
)
if test "$have_libgcrypt" = "true"; then
if test "$have_libgnutls" = "true"; then
compile_crypto=true
AC_DEFINE([ENABLE_CRYPTO], 1,
[Define this to 1 if you want to enable support of
encrypted files in libntfs and utilities.])
fi
fi
fi
AM_CONDITIONAL(ENABLE_CRYPTO, $compile_crypto)
# add --with-extra-includes and --with-extra-libs switch to ./configure
all_libraries="$all_libraries $USER_LDFLAGS"
all_includes="$all_includes $USER_INCLUDES"
AC_SUBST(all_includes)
AC_SUBST(all_libraries)
# Specify support for generating DCE compliant UUIDs (aka GUIDs). We check if
# uuid/uuid.h header is present and the uuid library is present that goes with
# it and then check if uuid_generate() is present and usable.
#
# DCE UUIDs are enabled by default and can be disabled with the --disable-uuid
# option to the configure script.
AC_ARG_WITH(uuid, [
--with-uuid@<:@=PFX@:>@ generate DCE compliant UUIDs, with optional prefix
to uuid library and headers @<:@default=detect@:>@
--without-uuid do not generate DCE compliant UUIDs],
if test "$with_uuid" = "yes"; then
extrapath=default
elif test "$with_uuid" = "no"; then
extrapath=
else
extrapath=$with_uuid
fi,
extrapath=default
)
if test "x$extrapath" != "x"; then
if test "x$extrapath" != "xdefault"; then
MKNTFS_CPPFLAGS="$MKNTFS_CPPFLAGS -I$extrapath/include"
MKNTFS_LIBS="$MKNTFS_LIBS -L$extrapath/lib"
fi
search_for_luuid="yes"
AC_CHECK_HEADER([uuid/uuid.h],
[],
[
AC_MSG_WARN([ntfsprogs DCE compliant UUID generation code requires the uuid library.])
search_for_luuid="no"
],
)
if test "x$search_for_luuid" != "xno"; then
# Look for uuid_generate in the standard C library.
AC_CHECK_FUNC([uuid_generate],
[
AC_DEFINE([ENABLE_UUID], 1,
[Define this to 1 if you want to enable
generation of DCE compliant UUIDs.])
search_for_luuid="no"
],
[],
)
fi
if test "x$search_for_luuid" != "xno"; then
# Look for uuid_generate in the 'uuid' library.
AC_CHECK_LIB([uuid], [uuid_generate],
[
AC_DEFINE([ENABLE_UUID], 1,
[Define this to 1 if you want to enable
generation of DCE compliant UUIDs.])
MKNTFS_LIBS="$MKNTFS_LIBS -luuid"
search_for_luuid="no"
],
[],
)
fi
if test "x$search_for_luuid" != "xno"; then
AC_MSG_WARN([ntfsprogs DCE compliant UUID generation code requires the uuid library.])
fi
fi
# Specify support for obtaining the correct BIOS legacy geometry needed for
# Windows to boot in CHS mode. We check if hd.h header is present and the hd
# library is present that goes with it and then check if the hd_list() function
# is present and usable.
#
# Using the hd library is enabled by default and can be disabled with the
# --disable-hd option to the configure script.
AC_ARG_WITH(hd, [
--with-hd@<:@=PFX@:>@ use Windows compliant disk geometry, with optional
prefix to hd library and headers @<:@default=detect@:>@
--without-hd do not use Windows compliant disk geometry],
if test "$with_hd" = "yes"; then
extrapath2=default
elif test "$with_hd" = "no"; then
extrapath2=
else
extrapath2=$with_hd
fi,
extrapath2=default
)
if test "x$extrapath2" != "x"; then
if test "x$extrapath2" != "xdefault"; then
LIBNTFS_CPPFLAGS="$LIBNTFS_CPPFLAGS -I$extrapath2/include"
LIBNTFS_LIBS="$LIBNTFS_LIBS -L$extrapath2/lib"
fi
AC_CHECK_HEADER([hd.h],
AC_CHECK_LIB([hd], [hd_list],
AC_DEFINE([ENABLE_HD], 1,
[Define this to 1 if you want to enable use of Windows
compliant disk geometry.])
LIBNTFS_LIBS="$LIBNTFS_LIBS -lhd"
NTFSPROGS_STATIC_LIBS="$NTFSPROGS_STATIC_LIBS -lhd",
AC_MSG_WARN([ntfsprogs Windows compliant geometry code requires the hd library.]),
),
AC_MSG_WARN([ntfsprogs Windows compliant geometry code requires the hd library.]),
)
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/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])
endian.h byteswap.h sys/byteorder.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 linux/hdreg.h \
machine/endian.h windows.h syslog.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
@ -497,7 +273,6 @@ AC_C_BIGENDIAN(
]
,
)
AC_C_CONST
AC_C_INLINE
AC_TYPE_OFF_T
AC_TYPE_SIZE_T
@ -505,7 +280,6 @@ AC_STRUCT_ST_BLOCKS
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_CHECK_MEMBERS([struct stat.st_atim])
AC_CHECK_MEMBERS([struct stat.st_atimespec])
AC_CHECK_MEMBERS([struct stat.st_atimensec])
# For the 'nfconv' patch (Mac OS X only):
case "${target_os}" in
@ -539,20 +313,10 @@ AC_CHECK_FUNCS([ \
atexit basename daemon dup2 fdatasync ffs getopt_long hasmntopt \
mbsinit memmove memset realpath regcomp setlocale setxattr \
strcasecmp strchr strdup strerror strnlen strsep strtol strtoul \
sysconf utime utimensat gettimeofday clock_gettime fork memcpy random snprintf \
sysconf utime fork \
])
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"
@ -564,7 +328,7 @@ if test "${enable_pedantic}" = "yes"; then
fi
if test "${enable_warnings}" = "yes"; then
CFLAGS="${CFLAGS} -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Winline -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wmultichar -Wnested-externs -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings -Wformat -Wformat-security -Wuninitialized"
CFLAGS="${CFLAGS} -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align -Wcast-qual -Wdisabled-optimization -Wdiv-by-zero -Wfloat-equal -Winline -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wmultichar -Wnested-externs -Wpointer-arith -Wredundant-decls -Wshadow -Wsign-compare -Wstrict-prototypes -Wundef -Wwrite-strings -Wformat -Wformat-security"
fi
if test "${enable_debug}" = "yes"; then
@ -584,8 +348,6 @@ 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,13 +379,7 @@ AC_SUBST([rootbindir])
AC_SUBST([rootsbindir])
AC_SUBST([rootlibdir])
AC_SUBST([LIBNTFS_3G_VERSION])
AC_SUBST([LIBFUSE_LITE_CFLAGS])
AC_SUBST([LIBFUSE_LITE_LIBS])
AC_SUBST([MKNTFS_CPPFLAGS])
AC_SUBST([MKNTFS_LIBS])
AC_SUBST([LIBNTFS_CPPFLAGS])
AC_SUBST([LIBNTFS_LIBS])
AC_SUBST([NTFSPROGS_STATIC_LIBS])
AC_SUBST([OUTPUT_FORMAT])
AM_CONDITIONAL([FUSE_INTERNAL], [test "${with_fuse}" = "internal"])
AM_CONDITIONAL([GENERATE_LDSCRIPT], [test "${enable_ldscript}" = "yes"])
@ -633,11 +389,6 @@ AM_CONDITIONAL([RUN_LDCONFIG], [test "${enable_ldconfig}" = "yes"])
AM_CONDITIONAL([REALLYSTATIC], [test "${enable_really_static}" = "yes"])
AM_CONDITIONAL([INSTALL_LIBRARY], [test "${enable_library}" = "yes"])
AM_CONDITIONAL([ENABLE_MOUNT_HELPER], [test "${enable_mount_helper}" = "yes"])
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
@ -660,30 +411,11 @@ AC_CONFIG_FILES([
libntfs-3g/Makefile
libntfs-3g/libntfs-3g.pc
libntfs-3g/libntfs-3g.script.so
ntfsprogs/Makefile
ntfsprogs/mkntfs.8
ntfsprogs/ntfscat.8
ntfsprogs/ntfsclone.8
ntfsprogs/ntfscluster.8
ntfsprogs/ntfscmp.8
ntfsprogs/ntfscp.8
ntfsprogs/ntfsfix.8
ntfsprogs/ntfsinfo.8
ntfsprogs/ntfslabel.8
ntfsprogs/ntfsls.8
ntfsprogs/ntfsprogs.8
ntfsprogs/ntfsresize.8
ntfsprogs/ntfsundelete.8
ntfsprogs/ntfsdecrypt.8
ntfsprogs/ntfswipe.8
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

@ -67,7 +67,6 @@ typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
* Changed in fuse 2.8.0 (regardless of API version)
* Previously, paths were limited to a length of PATH_MAX.
*/
struct fuse_operations {
/** Get file attributes.
*
@ -420,34 +419,6 @@ struct fuse_operations {
* Introduced in version 2.6
*/
int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
/**
* Ioctl
*
* flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
* 64bit environment. The size and direction of data is
* determined by _IOC_*() decoding of cmd. For _IOC_NONE,
* data will be NULL, for _IOC_WRITE data is out area, for
* _IOC_READ in area and if both are set in/out area. In all
* non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
*
* Introduced in version 2.8
*
* Note : the unsigned long request submitted by the application
* is truncated to 32 bits, and forwarded as a signed int.
*/
int (*ioctl) (const char *, int cmd, void *arg,
struct fuse_file_info *, unsigned int flags, void *data);
/*
* The flags below have been discarded, they should not be used
*/
unsigned int flag_nullpath_ok : 1;
/**
* Reserved flags, don't set
*/
unsigned int flag_reserved : 30;
};
/** Extra context that may be needed by some filesystems
@ -471,8 +442,10 @@ struct fuse_context {
/** Private filesystem data */
void *private_data;
#ifdef POSIXACLS
/** Umask of the calling process (introduced in version 2.8) */
mode_t umask;
#endif
};
/* ----------------------------------------------------------- *
@ -620,8 +593,6 @@ int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
const char *name);
int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
uint64_t *idx);
int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
struct fuse_file_info *fi, unsigned int flags, void *data);
void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
void fuse_fs_destroy(struct fuse_fs *fs);
@ -639,47 +610,6 @@ void fuse_fs_destroy(struct fuse_fs *fs);
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
void *user_data);
#ifdef __SOLARIS__
/**
* Filesystem module
*
* Filesystem modules are registered with the FUSE_REGISTER_MODULE()
* macro.
*
* If the "-omodules=modname:..." option is present, filesystem
* objects are created and pushed onto the stack with the 'factory'
* function.
*/
struct fuse_module {
/**
* Name of filesystem
*/
const char *name;
/**
* Factory for creating filesystem objects
*
* The function may use and remove options from 'args' that belong
* to this module.
*
* For now the 'fs' vector always contains exactly one filesystem.
* This is the filesystem which will be below the newly created
* filesystem in the stack.
*
* @param args the command line arguments
* @param fs NULL terminated filesystem object vector
* @return the new filesystem object
*/
struct fuse_fs *(*factory)(struct fuse_args *args, struct fuse_fs *fs[]);
struct fuse_module *next;
struct fusemod_so *so;
int ctr;
};
#endif /* __SOLARIS__ */
/* ----------------------------------------------------------- *
* Advanced API for event handling, don't worry about this... *
* ----------------------------------------------------------- */

View File

@ -32,11 +32,6 @@
#define FUSE_MAKE_VERSION(maj, min) ((maj) * 10 + (min))
#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
/* This interface uses 64 bit off_t */
#if defined(__SOLARIS__) && !defined(__x86_64__) && (_FILE_OFFSET_BITS != 64)
#error Please add -D_FILE_OFFSET_BITS=64 to your compile flags!
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -44,30 +39,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)
#define FUSE_CAP_IOCTL_DIR (1 << 11)
/**
* Ioctl flags
*
* FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
* FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
* FUSE_IOCTL_RETRY: retry with new iovecs
* FUSE_IOCTL_DIR: is a directory
*/
#define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
#define FUSE_IOCTL_RETRY (1 << 2)
#define FUSE_IOCTL_DIR (1 << 4)
#define FUSE_IOCTL_MAX_IOV 256
/**
* Information about open files
*
@ -141,12 +116,19 @@ struct fuse_conn_info {
*/
unsigned max_readahead;
#ifdef POSIXACLS
unsigned capable;
unsigned want;
/**
* For future use.
*/
unsigned reserved[25];
#else
/**
* For future use.
*/
unsigned reserved[27];
#endif
};
struct fuse_session;
@ -172,41 +154,6 @@ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args);
*/
void fuse_unmount(const char *mountpoint, struct fuse_chan *ch);
#ifdef __SOLARIS__
/**
* Parse common options
*
* The following options are parsed:
*
* '-f' foreground
* '-d' '-odebug' foreground, but keep the debug option
* '-s' single threaded
* '-h' '--help' help
* '-ho' help without header
* '-ofsname=..' file system name, if not present, then set to the program
* name
*
* All parameters may be NULL
*
* @param args argument vector
* @param mountpoint the returned mountpoint, should be freed after use
* @param multithreaded set to 1 unless the '-s' option is present
* @param foreground set to 1 if one of the relevant options is present
* @return 0 on success, -1 on failure
*/
int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
int *multithreaded, int *foreground);
/**
* Go into the background
*
* @param foreground if true, stay in the foreground
* @return 0 on success, -1 on failure
*/
int fuse_daemonize(int foreground);
#endif /* __SOLARIS__ */
/**
* Get the version of the library
*

View File

@ -48,20 +48,13 @@
/** Version number of this interface */
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface
* We introduce ourself as 7.18 (Posix ACLS : 7.12, IOCTL_DIR : 7.18)
* and we expect features features defined for 7.18, but not implemented
* here to not be triggered by ntfs-3g.
*/
#define FUSE_KERNEL_MINOR_VERSION 18
/*
* For binary compatibility with old kernels we accept falling back
* to 7.12 or earlier maximum version supported by the kernel
*/
#define FUSE_KERNEL_MAJOR_FALLBACK 7
#define FUSE_KERNEL_MINOR_FALLBACK 12
/** Minor version number of this interface */
#ifdef POSIXACLS
#define FUSE_KERNEL_MINOR_VERSION 12
#define FUSE_KERNEL_MINOR_FALLBACK 8
#else
#define FUSE_KERNEL_MINOR_VERSION 8
#endif
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@ -90,7 +83,9 @@ struct fuse_attr {
__u32 uid;
__u32 gid;
__u32 rdev;
#ifdef POSIXACLS
__u64 filling; /* JPA needed for minor >= 12, but meaning unknown */
#endif
};
struct fuse_kstatfs {
@ -135,17 +130,11 @@ struct fuse_file_lock {
/**
* INIT request/reply flags
* 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
@ -189,7 +178,6 @@ enum fuse_opcode {
FUSE_INTERRUPT = 36,
FUSE_BMAP = 37,
FUSE_DESTROY = 38,
FUSE_IOCTL = 39,
};
/* The read buffer is required to be at least 8k, but may be much larger */
@ -225,8 +213,10 @@ struct fuse_attr_out {
struct fuse_mknod_in {
__u32 mode;
__u32 rdev;
#ifdef POSIXACLS
__u32 umask;
__u32 padding;
#endif
};
struct fuse_mkdir_in {
@ -263,14 +253,20 @@ struct fuse_setattr_in {
struct fuse_open_in {
__u32 flags;
__u32 mode; /* unused for protocol < 7.12 */
#ifdef POSIXACLS
__u32 unused;
#else
__u32 mode;
#endif
};
struct fuse_create_in {
__u32 flags;
__u32 mode;
#ifdef POSIXACLS
__u32 umask;
__u32 padding;
#endif
};
struct fuse_open_out {
@ -307,9 +303,11 @@ struct fuse_write_in {
__u64 offset;
__u32 size;
__u32 write_flags;
#ifdef POSIXACLS
__u64 lock_owner; /* JPA */
__u32 flags; /* JPA */
__u32 padding; /* JPA */
#endif
};
struct fuse_write_out {
@ -389,27 +387,6 @@ struct fuse_bmap_out {
__u64 block;
};
struct fuse_ioctl_in {
__u64 fh;
__u32 flags;
__u32 cmd;
__u64 arg;
__u32 in_size;
__u32 out_size;
};
struct fuse_ioctl_iovec {
__u64 base;
__u64 len;
};
struct fuse_ioctl_out {
__s32 result;
__u32 flags;
__u32 in_iovs;
__u32 out_iovs;
};
struct fuse_in_header {
__u32 len;
__u32 opcode;

View File

@ -101,8 +101,10 @@ struct fuse_ctx {
/** Thread ID of the calling process */
pid_t pid;
#ifdef POSIXACLS
/** Umask of the calling process (introduced in version 2.8) */
mode_t umask;
#endif
};
/* 'to_set' flags in setattr */
@ -112,8 +114,6 @@ struct fuse_ctx {
#define FUSE_SET_ATTR_SIZE (1 << 3)
#define FUSE_SET_ATTR_ATIME (1 << 4)
#define FUSE_SET_ATTR_MTIME (1 << 5)
#define FUSE_SET_ATTR_ATIME_NOW (1 << 7)
#define FUSE_SET_ATTR_MTIME_NOW (1 << 8)
/* ----------------------------------------------------------- *
* Request methods and replies *
@ -803,40 +803,6 @@ struct fuse_lowlevel_ops {
*/
void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
uint64_t idx);
/**
* Ioctl
*
* Note: For unrestricted ioctls (not allowed for FUSE
* servers), data in and out areas can be discovered by giving
* iovs and setting FUSE_IOCTL_RETRY in @flags. For
* restricted ioctls, kernel prepares in/out data area
* according to the information encoded in cmd.
*
* Introduced in version 2.8
*
* Note : the unsigned long request submitted by the application
* is truncated to 32 bits, and forwarded as a signed int.
*
* Valid replies:
* fuse_reply_ioctl_retry
* fuse_reply_ioctl
* fuse_reply_ioctl_iov
* fuse_reply_err
*
* @param req request handle
* @param ino the inode number
* @param cmd ioctl command
* @param arg ioctl argument
* @param fi file information
* @param flags for FUSE_IOCTL_* flags
* @param in_buf data fetched from the caller
* @param in_bufsz number of fetched bytes
* @param out_bufsz maximum size of output data
*/
void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
struct fuse_file_info *fi, unsigned flags,
const void *in_buf, size_t in_bufsz, size_t out_bufsz);
};
/**
@ -1054,20 +1020,6 @@ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
const char *name, const struct stat *stbuf,
off_t off);
/**
* Reply to finish ioctl
*
* Possible requests:
* ioctl
*
* @param req request handle
* @param result result to be passed to the caller
* @param buf buffer containing output data
* @param size length of output data
*/
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
/* ----------------------------------------------------------- *
* Utility functions *
* ----------------------------------------------------------- */
@ -1125,13 +1077,6 @@ int fuse_req_interrupted(fuse_req_t req);
* Filesystem setup *
* ----------------------------------------------------------- */
#ifdef __SOLARIS__
/* Deprecated, don't use */
int fuse_lowlevel_is_lib_option(const char *opt);
#endif /* __SOLARIS__ */
/**
* Create a low level session
*

View File

@ -7,7 +7,6 @@ headers = \
attrlist.h \
bitmap.h \
bootsect.h \
cache.h \
collate.h \
compat.h \
compress.h \
@ -15,12 +14,10 @@ headers = \
device.h \
device_io.h \
dir.h \
ea.h \
efs.h \
endians.h \
index.h \
inode.h \
ioctl.h \
layout.h \
lcnalloc.h \
logfile.h \
@ -29,18 +26,13 @@ headers = \
misc.h \
mst.h \
ntfstime.h \
object_id.h \
param.h \
plugin.h \
realpath.h \
reparse.h \
runlist.h \
security.h \
support.h \
types.h \
unistr.h \
volume.h \
xattrs.h
volume.h
if INSTALL_LIBRARY
ntfs3ginclude_HEADERS = $(headers)

View File

@ -24,19 +24,41 @@
#ifndef ACLS_H
#define ACLS_H
#include "endians.h"
/*
* JPA configuration modes for security.c / acls.c
* should be moved to some config file
*/
#define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
#define BUFSZ 1024 /* buffer size to read mapping file */
#define MAPPINGFILE ".NTFS-3G/UserMapping" /* default mapping file */
#define LINESZ 120 /* maximum useful size of a mapping line */
#define CACHE_PERMISSIONS_BITS 6 /* log2 of unitary allocation of permissions */
#define CACHE_PERMISSIONS_SIZE 262144 /* max cacheable permissions */
/*
* JPA The following must be in some library...
* but did not found out where
*/
#define endian_rev16(x) (((x >> 8) & 255) | ((x & 255) << 8))
#define endian_rev32(x) (((x >> 24) & 255) | ((x >> 8) & 0xff00) \
| ((x & 0xff00) << 8) | ((x & 255) << 24))
#define cpu_to_be16(x) endian_rev16(cpu_to_le16(x))
#define cpu_to_be32(x) endian_rev32(cpu_to_le32(x))
/*
* 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
@ -92,11 +114,10 @@
#define ROOT_GROUP_UNMARK FILE_READ_EA /* ACL granted to root as group */
/*
* Maximum SID size and a type large enough to hold it
* A type large enough to hold any SID
*/
#define MAX_SID_SIZE (8 + SID_MAX_SUB_AUTHORITIES*4)
typedef char BIGSID[MAX_SID_SIZE];
typedef char BIGSID[40];
/*
* Struct to hold the input mapping file
@ -151,9 +172,6 @@ int ntfs_merge_mode_posix(struct POSIX_SECURITY *pxdesc, mode_t mode);
struct POSIX_SECURITY *ntfs_build_inherited_posix(
const struct POSIX_SECURITY *pxdesc, mode_t mode,
mode_t umask, BOOL isdir);
struct POSIX_SECURITY *ntfs_build_basic_posix(
const struct POSIX_SECURITY *pxdesc, mode_t mode,
mode_t umask, BOOL isdir);
struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc,
const struct POSIX_ACL *newacl, int count, BOOL deflt);
struct POSIX_SECURITY *ntfs_build_permissions_posix(
@ -169,8 +187,7 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[],
#endif /* POSIXACLS */
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
const SID *usid, const SID *gsid,
BOOL fordir, le16 inherited);
const SID *usid, const SID *gsid, BOOL fordir);
int ntfs_build_permissions(const char *securattr,
const SID *usid, const SID *gsid, BOOL isdir);
char *ntfs_build_descr(mode_t mode,

View File

@ -4,7 +4,6 @@
* Copyright (c) 2000-2004 Anton Altaparmakov
* Copyright (c) 2004-2005 Yura Pakhuchiy
* Copyright (c) 2006-2007 Szabolcs Szakacsits
* Copyright (c) 2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -58,13 +57,6 @@ typedef enum {
LCN_EIO = -5,
} ntfs_lcn_special_values;
typedef enum { /* ways of processing holes when expanding */
HOLES_NO,
HOLES_OK,
HOLES_DELAY,
HOLES_NONRES
} hole_type;
/**
* struct ntfs_attr_search_ctx - search context used in attribute search functions
* @mrec: buffer containing mft record to search
@ -197,7 +189,6 @@ struct _ntfs_attr {
u32 compression_block_size;
u8 compression_block_size_bits;
u8 compression_block_clusters;
s8 unused_runs; /* pre-reserved entries available */
};
/**
@ -207,11 +198,6 @@ struct _ntfs_attr {
typedef enum {
NA_Initialized, /* 1: structure is initialized. */
NA_NonResident, /* 1: Attribute is not resident. */
NA_BeingNonResident, /* 1: Attribute is being made not resident. */
NA_FullyMapped, /* 1: Attribute has been fully mapped */
NA_DataAppending, /* 1: Attribute is being appended to */
NA_ComprClosing, /* 1: Compressed attribute is being closed */
NA_RunlistDirty, /* 1: Runlist has been updated */
} ntfs_attr_state_bits;
#define test_nattr_flag(na, flag) test_bit(NA_##flag, (na)->state)
@ -226,26 +212,6 @@ typedef enum {
#define NAttrSetNonResident(na) set_nattr_flag(na, NonResident)
#define NAttrClearNonResident(na) clear_nattr_flag(na, NonResident)
#define NAttrBeingNonResident(na) test_nattr_flag(na, BeingNonResident)
#define NAttrSetBeingNonResident(na) set_nattr_flag(na, BeingNonResident)
#define NAttrClearBeingNonResident(na) clear_nattr_flag(na, BeingNonResident)
#define NAttrFullyMapped(na) test_nattr_flag(na, FullyMapped)
#define NAttrSetFullyMapped(na) set_nattr_flag(na, FullyMapped)
#define NAttrClearFullyMapped(na) clear_nattr_flag(na, FullyMapped)
#define NAttrDataAppending(na) test_nattr_flag(na, DataAppending)
#define NAttrSetDataAppending(na) set_nattr_flag(na, DataAppending)
#define NAttrClearDataAppending(na) clear_nattr_flag(na, DataAppending)
#define NAttrRunlistDirty(na) test_nattr_flag(na, RunlistDirty)
#define NAttrSetRunlistDirty(na) set_nattr_flag(na, RunlistDirty)
#define NAttrClearRunlistDirty(na) clear_nattr_flag(na, RunlistDirty)
#define NAttrComprClosing(na) test_nattr_flag(na, ComprClosing)
#define NAttrSetComprClosing(na) set_nattr_flag(na, ComprClosing)
#define NAttrClearComprClosing(na) clear_nattr_flag(na, ComprClosing)
#define GenNAttrIno(func_name, flag) \
extern int NAttr##func_name(ntfs_attr *na); \
extern void NAttrSet##func_name(ntfs_attr *na); \
@ -322,22 +288,20 @@ extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
const ATTR_TYPES type);
int ntfs_attr_make_non_resident(ntfs_attr *na,
ntfs_attr_search_ctx *ctx);
int ntfs_attr_force_non_resident(ntfs_attr *na);
extern int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size);
extern int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
const ntfschar *name, u8 name_len, const u8 *val, u32 size,
ntfschar *name, u8 name_len, u8 *val, u32 size,
ATTR_FLAGS flags);
extern int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
const ntfschar *name, u8 name_len, VCN lowest_vcn,
int dataruns_size, ATTR_FLAGS flags);
ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
ATTR_FLAGS flags);
extern int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx);
extern int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
ntfschar *name, u8 name_len, const u8 *val, s64 size);
ntfschar *name, u8 name_len, u8 *val, s64 size);
extern int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type,
const ntfschar *name, u8 name_len, ATTR_FLAGS flags,
ATTR_FLAGS mask);
ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask);
extern int ntfs_attr_rm(ntfs_attr *na);
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
@ -351,7 +315,6 @@ extern int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra);
extern int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn);
extern int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize);
extern int ntfs_attr_truncate_solid(ntfs_attr *na, const s64 newsize);
/**
* get_attribute_value_length - return the length of the value of an attribute
@ -386,19 +349,10 @@ extern s64 ntfs_get_attribute_value(const ntfs_volume *vol,
extern void ntfs_attr_name_free(char **name);
extern char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len);
extern int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type,
const ntfschar *name, u32 name_len);
ntfschar *name, u32 name_len);
extern int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type,
ntfschar *name, u32 name_len);
extern s64 ntfs_attr_get_free_bits(ntfs_attr *na);
extern int ntfs_attr_data_read(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
char *buf, size_t size, off_t offset);
extern int ntfs_attr_data_write(ntfs_inode *ni,
ntfschar *stream_name, int stream_name_len,
const char *buf, size_t size, off_t offset);
extern int ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name,
int stream_name_len, off_t offset);
extern int ntfs_attr_inconsistent(const ATTR_RECORD *a, const MFT_REF mref);
#endif /* defined _NTFS_ATTRIB_H */

View File

@ -1,118 +0,0 @@
/*
* cache.h : deal with indexed LRU caches
*
* Copyright (c) 2008-2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_CACHE_H_
#define _NTFS_CACHE_H_
#include "volume.h"
struct CACHED_GENERIC {
struct CACHED_GENERIC *next;
struct CACHED_GENERIC *previous;
void *variable;
size_t varsize;
union ALIGNMENT payload[0];
} ;
struct CACHED_INODE {
struct CACHED_INODE *next;
struct CACHED_INODE *previous;
const char *pathname;
size_t varsize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 inum;
} ;
struct CACHED_NIDATA {
struct CACHED_NIDATA *next;
struct CACHED_NIDATA *previous;
const char *pathname; /* not used */
size_t varsize; /* not used */
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 inum;
ntfs_inode *ni;
} ;
struct CACHED_LOOKUP {
struct CACHED_LOOKUP *next;
struct CACHED_LOOKUP *previous;
const char *name;
size_t namesize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 parent;
u64 inum;
} ;
enum {
CACHE_FREE = 1,
CACHE_NOHASH = 2
} ;
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
const struct CACHED_GENERIC *item);
typedef void (*cache_free)(const struct CACHED_GENERIC *cached);
typedef int (*cache_hash)(const struct CACHED_GENERIC *cached);
struct HASH_ENTRY {
struct HASH_ENTRY *next;
struct CACHED_GENERIC *entry;
} ;
struct CACHE_HEADER {
const char *name;
struct CACHED_GENERIC *most_recent_entry;
struct CACHED_GENERIC *oldest_entry;
struct CACHED_GENERIC *free_entry;
struct HASH_ENTRY *free_hash;
struct HASH_ENTRY **first_hash;
cache_free dofree;
cache_hash dohash;
unsigned long reads;
unsigned long writes;
unsigned long hits;
int fixed_size;
int max_hash;
struct CACHED_GENERIC entry[0];
} ;
/* cast to generic, avoiding gcc warnings */
#define GENERIC(pstr) ((const struct CACHED_GENERIC*)(const void*)(pstr))
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *wanted,
cache_compare compare);
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item,
cache_compare compare);
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item,
cache_compare compare, int flags);
int ntfs_remove_cache(struct CACHE_HEADER *cache,
struct CACHED_GENERIC *item, int flags);
void ntfs_create_lru_caches(ntfs_volume *vol);
void ntfs_free_lru_caches(ntfs_volume *vol);
#endif /* _NTFS_CACHE_H_ */

View File

@ -29,6 +29,9 @@
#define NTFS_COLLATION_ERROR -2
extern COLLATE ntfs_get_collate_function(COLLATION_RULES);
extern BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr);
extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr,
const void *data1, const int data1_len,
const void *data2, const int data2_len);
#endif /* _NTFS_COLLATE_H */

View File

@ -1,10 +1,9 @@
/*
* compat.h - Tweaks for compatibility with non-Linux systems.
* compat.h - Tweaks for Windows compatibility.
*
* Copyright (c) 2002 Richard Russon
* Copyright (c) 2002-2004 Anton Altaparmakov
* Copyright (c) 2008-2009 Szabolcs Szakacsits
* Copyright (c) 2019 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
@ -32,30 +31,6 @@
#include <sys/param.h>
#endif
#include <errno.h> /* ENODATA */
#ifndef ENODATA
#define ENODATA ENOENT
#endif
#ifndef ELIBBAD
#define ELIBBAD ENOEXEC
#endif
#ifndef ELIBACC
#define ELIBACC ENOENT
#endif
/* xattr APIs in macOS differs from Linux ones in that they expect the special
* error code ENOATTR to be returned when an attribute cannot be found. So
* define NTFS_NOXATTR_ERRNO to the appropriate "no xattr found" errno value for
* the platform. */
#if defined(__APPLE__) || defined(__DARWIN__)
#define NTFS_NOXATTR_ERRNO ENOATTR
#else
#define NTFS_NOXATTR_ERRNO ENODATA
#endif
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

View File

@ -31,11 +31,9 @@ extern s64 ntfs_compressed_attr_pread(ntfs_attr *na, s64 pos, s64 count,
extern s64 ntfs_compressed_pwrite(ntfs_attr *na, runlist_element *brl, s64 wpos,
s64 offs, s64 to_write, s64 rounded,
const void *b, int compressed_part,
VCN *update_from);
const void *b, int compressed_part);
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl,
s64 offs, VCN *update_from);
extern int ntfs_compressed_close(ntfs_attr *na, runlist_element *brl, s64 offs);
#endif /* defined _NTFS_COMPRESS_H */

View File

@ -38,10 +38,10 @@ static __inline__ void ntfs_debug_runlist_dump(const struct _runlist_element *rl
#define NTFS_BUG(msg) \
{ \
int ___i = 1; \
int ___i; \
ntfs_log_critical("Bug in %s(): %s\n", __FUNCTION__, msg); \
ntfs_log_debug("Forcing segmentation fault!"); \
___i = ((int*)NULL)[___i]; \
___i = ((int*)NULL)[1]; \
}
#endif /* defined _NTFS_DEBUG_H */

View File

@ -1,8 +1,7 @@
/*
* device.h - Exports for low level device io. Originated from the Linux-NTFS project.
*
* Copyright (c) 2000-2013 Anton Altaparmakov
* Copyright (c) 2008-2013 Tuxera Inc.
* Copyright (c) 2000-2006 Anton Altaparmakov
*
* 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
@ -42,7 +41,6 @@ typedef enum {
ND_ReadOnly, /* 1: Device is read-only. */
ND_Dirty, /* 1: Device is dirty, needs sync. */
ND_Block, /* 1: Device is a block device. */
ND_Sync, /* 1: Device is mounted with "-o sync" */
} ntfs_device_state_bits;
#define test_ndev_flag(nd, flag) test_bit(ND_##flag, (nd)->d_state)
@ -65,20 +63,11 @@ typedef enum {
#define NDevSetBlock(nd) set_ndev_flag(nd, Block)
#define NDevClearBlock(nd) clear_ndev_flag(nd, Block)
#define NDevSync(nd) test_ndev_flag(nd, Sync)
#define NDevSetSync(nd) set_ndev_flag(nd, Sync)
#define NDevClearSync(nd) clear_ndev_flag(nd, Sync)
/**
* struct ntfs_device -
*
* The ntfs device structure defining all operations needed to access the low
* level device underlying the ntfs volume.
*
* Note d_heads and d_sectors_per_track are only set as a result of a call to
* either ntfs_device_heads_get() or ntfs_device_sectors_per_track_get() (both
* calls will set up both fields or if getting them failed they will be left at
* -1).
*/
struct ntfs_device {
struct ntfs_device_operations *d_ops; /* Device operations. */
@ -86,10 +75,6 @@ struct ntfs_device {
char *d_name; /* Name of device. */
void *d_private; /* Private data used by the
device operations. */
int d_heads; /* Disk geometry: number of
heads or -1. */
int d_sectors_per_track; /* Disk geometry: number of
sectors per track or -1. */
};
struct stat;
@ -111,14 +96,12 @@ struct ntfs_device_operations {
s64 offset);
int (*sync)(struct ntfs_device *dev);
int (*stat)(struct ntfs_device *dev, struct stat *buf);
int (*ioctl)(struct ntfs_device *dev, unsigned long request,
void *argp);
int (*ioctl)(struct ntfs_device *dev, int request, void *argp);
};
extern struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
struct ntfs_device_operations *dops, void *priv_data);
extern int ntfs_device_free(struct ntfs_device *dev);
extern int ntfs_device_sync(struct ntfs_device *dev);
extern s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count,
void *b);

View File

@ -28,18 +28,12 @@
#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
#if defined(linux) || defined(__uClinux__) || defined(__sun) \
|| defined(__APPLE__) || defined(__DARWIN__)
/* Make sure the presence of <windows.h> means compiling for Windows */
#undef HAVE_WINDOWS_H
#endif
#ifndef __CYGWIN32__
#ifndef HAVE_WINDOWS_H
/* Not for Windows use standard Unix style low level device operations. */
/* Not on Cygwin; use standard Unix style low level device operations. */
#define ntfs_device_default_io_ops ntfs_device_unix_io_ops
#else /* HAVE_WINDOWS_H */
#else /* __CYGWIN32__ */
#ifndef HDIO_GETGEO
# define HDIO_GETGEO 0x301
@ -66,15 +60,10 @@ struct hd_geometry {
# define BLKBSZSET 0x40041271
#endif
/* On Windows (and Cygwin) : use Win32 low level device operations. */
/* On Cygwin; use Win32 low level device operations. */
#define ntfs_device_default_io_ops ntfs_device_win32_io_ops
/* A few useful functions */
int ntfs_win32_set_sparse(int);
int ntfs_win32_ftruncate(int fd, s64 size);
int ntfs_device_win32_ftruncate(struct ntfs_device*, s64);
#endif /* HAVE_WINDOWS_H */
#endif /* __CYGWIN32__ */
/* Forward declaration. */

View File

@ -61,25 +61,21 @@ extern ntfschar NTFS_INDEX_R[3];
extern u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni,
const ntfschar *uname, const int uname_len);
extern u64 ntfs_inode_lookup_by_mbsname(ntfs_inode *dir_ni, const char *name);
extern void ntfs_inode_update_mbsname(ntfs_inode *dir_ni, const char *name,
u64 inum);
extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,
const char *pathname);
extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, le32 securid,
const ntfschar *name, u8 name_len, mode_t type);
ntfschar *name, u8 name_len, mode_t type);
extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, le32 securid,
const ntfschar *name, u8 name_len, mode_t type, dev_t dev);
ntfschar *name, u8 name_len, mode_t type, dev_t dev);
extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, le32 securid,
const ntfschar *name, u8 name_len, const ntfschar *target,
int target_len);
ntfschar *name, u8 name_len, ntfschar *target, int target_len);
extern int ntfs_check_empty_dir(ntfs_inode *ni);
extern int ntfs_delete(ntfs_volume *vol, const char *path,
ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
u8 name_len);
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name,
u8 name_len);
/*
@ -94,7 +90,6 @@ extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
#define NTFS_DT_LNK 10
#define NTFS_DT_SOCK 12
#define NTFS_DT_WHT 14
#define NTFS_DT_REPARSE 32
/*
* This is the "ntfs_filldir" function type, used by ntfs_readdir() to let
@ -109,24 +104,12 @@ typedef int (*ntfs_filldir_t)(void *dirent, const ntfschar *name,
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);
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
const char *value, size_t size, int flags);
int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
int ntfs_dir_link_cnt(ntfs_inode *ni);
#if CACHE_INODE_SIZE
struct CACHED_GENERIC;
extern int ntfs_dir_inode_hash(const struct CACHED_GENERIC *cached);
extern int ntfs_dir_lookup_hash(const struct CACHED_GENERIC *cached);
#endif
int ntfs_get_ntfs_dos_name(const char *path,
char *value, size_t size, ntfs_inode *ni);
int ntfs_set_ntfs_dos_name(const char *path,
const char *value, size_t size, int flags,
ntfs_inode *ni);
int ntfs_remove_ntfs_dos_name(const char *path, ntfs_inode *ni);
#endif /* defined _NTFS_DIR_H */

View File

@ -1,37 +0,0 @@
/*
*
* Copyright (c) 2014-2021 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
*/
#ifndef EA_H
#define EA_H
int ntfs_ea_check_wsldev(ntfs_inode *ni, dev_t *rdevp);
int ntfs_ea_set_wsl_not_symlink(ntfs_inode *ni, mode_t mode, dev_t dev);
int ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size);
int ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags);
int ntfs_remove_ntfs_ea(ntfs_inode *ni);
#endif /* EA_H */

View File

@ -21,10 +21,11 @@
#ifndef EFS_H
#define EFS_H
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size);
int ntfs_set_efs_info(ntfs_inode *ni,
const char *value, size_t size, int flags);
int ntfs_get_efs_info(const char *path,
char *value, size_t size, ntfs_inode *ni);
int ntfs_set_efs_info(const char *path,
const char *value, size_t size, int flags,
ntfs_inode *ni);
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na);
#endif /* EFS_H */

View File

@ -61,16 +61,10 @@
# define __BYTE_ORDER BYTE_ORDER
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __BIG_ENDIAN BIG_ENDIAN
# elif defined(__BYTE_ORDER__) && defined(__LITTLE_ENDIAN__) && \
defined(__BIG_ENDIAN__)
# elif defined(__BYTE_ORDER__)
# define __BYTE_ORDER __BYTE_ORDER__
# define __LITTLE_ENDIAN __LITTLE_ENDIAN__
# define __BIG_ENDIAN __BIG_ENDIAN__
# elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
defined(__ORDER_BIG_ENDIAN__)
# define __BYTE_ORDER __BYTE_ORDER__
# define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
# define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
# elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \
defined(WORDS_LITTLEENDIAN)
# define __BYTE_ORDER 1
@ -132,22 +126,6 @@
#define __constant_cpu_to_le32(x) (x)
#define __constant_cpu_to_le64(x) (x)
#define __be16_to_cpu(x) bswap_16(x)
#define __be32_to_cpu(x) bswap_32(x)
#define __be64_to_cpu(x) bswap_64(x)
#define __cpu_to_be16(x) bswap_16(x)
#define __cpu_to_be32(x) bswap_32(x)
#define __cpu_to_be64(x) bswap_64(x)
#define __constant_be16_to_cpu(x) __ntfs_bswap_constant_16((u16)(x))
#define __constant_be32_to_cpu(x) __ntfs_bswap_constant_32((u32)(x))
#define __constant_be64_to_cpu(x) __ntfs_bswap_constant_64((u64)(x))
#define __constant_cpu_to_be16(x) __ntfs_bswap_constant_16((u16)(x))
#define __constant_cpu_to_be32(x) __ntfs_bswap_constant_32((u32)(x))
#define __constant_cpu_to_be64(x) __ntfs_bswap_constant_64((u64)(x))
#elif defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN)
#define __le16_to_cpu(x) bswap_16(x)
@ -166,22 +144,6 @@
#define __constant_cpu_to_le32(x) __ntfs_bswap_constant_32((u32)(x))
#define __constant_cpu_to_le64(x) __ntfs_bswap_constant_64((u64)(x))
#define __be16_to_cpu(x) (x)
#define __be32_to_cpu(x) (x)
#define __be64_to_cpu(x) (x)
#define __cpu_to_be16(x) (x)
#define __cpu_to_be32(x) (x)
#define __cpu_to_be64(x) (x)
#define __constant_be16_to_cpu(x) (x)
#define __constant_be32_to_cpu(x) (x)
#define __constant_be64_to_cpu(x) (x)
#define __constant_cpu_to_be16(x) (x)
#define __constant_cpu_to_be32(x) (x)
#define __constant_cpu_to_be64(x) (x)
#else
#error "You must define __BYTE_ORDER to be __LITTLE_ENDIAN or __BIG_ENDIAN."
@ -228,78 +190,14 @@
#define cpu_to_sle32p(x) (s32)__cpu_to_le32(*(s32*)(x))
#define cpu_to_sle64p(x) (s64)__cpu_to_le64(*(s64*)(x))
/* Unsigned from BE to CPU conversion. */
#define be16_to_cpu(x) (u16)__be16_to_cpu((u16)(x))
#define be32_to_cpu(x) (u32)__be32_to_cpu((u32)(x))
#define be64_to_cpu(x) (u64)__be64_to_cpu((u64)(x))
#define be16_to_cpup(x) (u16)__be16_to_cpu(*(const u16*)(x))
#define be32_to_cpup(x) (u32)__be32_to_cpu(*(const u32*)(x))
#define be64_to_cpup(x) (u64)__be64_to_cpu(*(const u64*)(x))
/* Signed from BE to CPU conversion. */
#define sbe16_to_cpu(x) (s16)__be16_to_cpu((s16)(x))
#define sbe32_to_cpu(x) (s32)__be32_to_cpu((s32)(x))
#define sbe64_to_cpu(x) (s64)__be64_to_cpu((s64)(x))
#define sbe16_to_cpup(x) (s16)__be16_to_cpu(*(s16*)(x))
#define sbe32_to_cpup(x) (s32)__be32_to_cpu(*(s32*)(x))
#define sbe64_to_cpup(x) (s64)__be64_to_cpu(*(s64*)(x))
/* Unsigned from CPU to BE conversion. */
#define cpu_to_be16(x) (u16)__cpu_to_be16((u16)(x))
#define cpu_to_be32(x) (u32)__cpu_to_be32((u32)(x))
#define cpu_to_be64(x) (u64)__cpu_to_be64((u64)(x))
#define cpu_to_be16p(x) (u16)__cpu_to_be16(*(u16*)(x))
#define cpu_to_be32p(x) (u32)__cpu_to_be32(*(u32*)(x))
#define cpu_to_be64p(x) (u64)__cpu_to_be64(*(u64*)(x))
/* Signed from CPU to BE conversion. */
#define cpu_to_sbe16(x) (s16)__cpu_to_be16((s16)(x))
#define cpu_to_sbe32(x) (s32)__cpu_to_be32((s32)(x))
#define cpu_to_sbe64(x) (s64)__cpu_to_be64((s64)(x))
#define cpu_to_sbe16p(x) (s16)__cpu_to_be16(*(s16*)(x))
#define cpu_to_sbe32p(x) (s32)__cpu_to_be32(*(s32*)(x))
#define cpu_to_sbe64p(x) (s64)__cpu_to_be64(*(s64*)(x))
/* Constant endianness conversion defines. */
#define const_le16_to_cpu(x) ((u16) __constant_le16_to_cpu(x))
#define const_le32_to_cpu(x) ((u32) __constant_le32_to_cpu(x))
#define const_le64_to_cpu(x) ((u64) __constant_le64_to_cpu(x))
#define const_le16_to_cpu(x) __constant_le16_to_cpu(x)
#define const_le32_to_cpu(x) __constant_le32_to_cpu(x)
#define const_le64_to_cpu(x) __constant_le64_to_cpu(x)
#define const_cpu_to_le16(x) ((le16) __constant_cpu_to_le16(x))
#define const_cpu_to_le32(x) ((le32) __constant_cpu_to_le32(x))
#define const_cpu_to_le64(x) ((le64) __constant_cpu_to_le64(x))
#define const_sle16_to_cpu(x) ((s16) __constant_le16_to_cpu((le16) x))
#define const_sle32_to_cpu(x) ((s32) __constant_le32_to_cpu((le32) x))
#define const_sle64_to_cpu(x) ((s64) __constant_le64_to_cpu((le64) x))
#define const_cpu_to_sle16(x) ((sle16) __constant_cpu_to_le16((u16) x))
#define const_cpu_to_sle32(x) ((sle32) __constant_cpu_to_le32((u32) x))
#define const_cpu_to_sle64(x) ((sle64) __constant_cpu_to_le64((u64) x))
#define const_be16_to_cpu(x) ((u16) __constant_be16_to_cpu(x)))
#define const_be32_to_cpu(x) ((u32) __constant_be32_to_cpu(x)))
#define const_be64_to_cpu(x) ((u64) __constant_be64_to_cpu(x)))
#define const_cpu_to_be16(x) ((be16) __constant_cpu_to_be16(x))
#define const_cpu_to_be32(x) ((be32) __constant_cpu_to_be32(x))
#define const_cpu_to_be64(x) ((be64) __constant_cpu_to_be64(x))
#define const_sbe16_to_cpu(x) ((s16) __constant_be16_to_cpu((be16) x))
#define const_sbe32_to_cpu(x) ((s32) __constant_be32_to_cpu((be32) x))
#define const_sbe64_to_cpu(x) ((s64) __constant_be64_to_cpu((be64) x))
#define const_cpu_to_sbe16(x) ((sbe16) __constant_cpu_to_be16((u16) x))
#define const_cpu_to_sbe32(x) ((sbe32) __constant_cpu_to_be32((u32) x))
#define const_cpu_to_sbe64(x) ((sbe64) __constant_cpu_to_be64((u64) x))
#define const_cpu_to_le16(x) __constant_cpu_to_le16(x)
#define const_cpu_to_le32(x) __constant_cpu_to_le32(x)
#define const_cpu_to_le64(x) __constant_cpu_to_le64(x)
#endif /* defined _NTFS_ENDIANS_H */

View File

@ -63,9 +63,6 @@
#define MAX_PARENT_VCN 32
typedef int (*COLLATE)(ntfs_volume *vol, const void *data1, int len1,
const void *data2, int len2);
/**
* struct ntfs_index_context -
* @ni: inode containing the @entry described by this context
@ -119,7 +116,7 @@ typedef struct {
INDEX_ENTRY *entry;
void *data;
u16 data_len;
COLLATE collate;
COLLATION_RULES cr;
BOOL is_in_root;
INDEX_ROOT *ir;
ntfs_attr_search_ctx *actx;
@ -129,7 +126,6 @@ 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;
@ -139,10 +135,6 @@ extern ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
extern void ntfs_index_ctx_put(ntfs_index_context *ictx);
extern void ntfs_index_ctx_reinit(ntfs_index_context *ictx);
extern int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size,
u64 inum, VCN vcn);
extern int ntfs_index_entry_inconsistent(const INDEX_ENTRY *ie,
COLLATION_RULES collation_rule, u64 inum);
extern int ntfs_index_lookup(const void *key, const int key_len,
ntfs_index_context *ictx) __attribute_warn_unused_result__;

View File

@ -32,7 +32,6 @@ typedef struct _ntfs_inode ntfs_inode;
#include "layout.h"
#include "support.h"
#include "volume.h"
#include "ntfstime.h"
/**
* enum ntfs_inode_state_bits -
@ -50,8 +49,7 @@ typedef enum {
NI_FileNameDirty, /* 1: FILE_NAME attributes need to be updated
in the index. */
NI_v3_Extensions, /* 1: JPA v3.x extensions present. */
NI_TimesSet, /* 1: Use times which were set */
NI_KnownSize, /* 1: Set if sizes are meaningful */
NI_TimesDirty, /* 1: Times need to be updated */
} ntfs_inode_state_bits;
#define test_nino_flag(ni, flag) test_bit(NI_##flag, (ni)->state)
@ -137,11 +135,8 @@ struct _ntfs_inode {
* These two fields are used to sync filename index and guaranteed to be
* correct, however value in index itself maybe wrong (windows itself
* do not update them properly).
* For directories, they hold the index size, provided the
* flag KnownSize is set.
*/
s64 data_size; /* Data size of unnamed DATA attribute
(or INDEX_ROOT for directories) */
s64 data_size; /* Data size of unnamed DATA attribute. */
s64 allocated_size; /* Allocated size stored in the filename
index. (NOTE: Equal to allocated size of
the unnamed data attribute for normal or
@ -154,10 +149,10 @@ struct _ntfs_inode {
* STANDARD_INFORMATION attribute and used to sync it and FILE_NAME
* attribute in the index.
*/
ntfs_time creation_time;
ntfs_time last_data_change_time;
ntfs_time last_mft_change_time;
ntfs_time last_access_time;
time_t creation_time;
time_t last_data_change_time;
time_t last_mft_change_time;
time_t last_access_time;
/* NTFS 3.x extensions added by JPA */
/* only if NI_v3_Extensions is set in state */
le32 owner_id;
@ -182,22 +177,9 @@ extern ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol);
extern ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref);
extern int ntfs_inode_close(ntfs_inode *ni);
extern int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni);
#if CACHE_NIDATA_SIZE
struct CACHED_GENERIC;
extern int ntfs_inode_real_close(ntfs_inode *ni);
extern void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref);
extern void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached);
extern int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item);
#endif
extern ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni,
const leMFT_REF mref);
const MFT_REF mref);
extern int ntfs_inode_attach_all_extents(ntfs_inode *ni);
@ -213,13 +195,9 @@ extern int ntfs_inode_free_space(ntfs_inode *ni, int size);
extern int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *a);
extern int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size);
extern int ntfs_inode_set_times(ntfs_inode *ni, const char *value,
size_t size, int flags);
/* debugging */
#define debug_double_inode(num, type)
#define debug_cached_inode(ni)
extern int ntfs_inode_get_times(const char *path, char *value,
size_t size, ntfs_inode *ni);
extern int ntfs_inode_set_times(const char *path, const char *value,
size_t size, int flags, ntfs_inode *ni);
#endif /* defined _NTFS_INODE_H */

View File

@ -1,35 +0,0 @@
/*
*
* Copyright (c) 2014 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
*/
#ifndef IOCTL_H
#define IOCTL_H
/*
* Using an "unsigned long cmd" internally, like in <sys/ioctl.h> for Linux
* Note however that fuse truncates the arg to 32 bits, and that
* some commands (e.g. FITRIM) do not fit in a signed 32 bit field.
*/
int ntfs_ioctl(ntfs_inode *ni, unsigned long cmd, void *arg,
unsigned int flags, void *data);
#endif /* IOCTL_H */

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,6 @@ extern runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
LCN start_lcn, const NTFS_CLUSTER_ALLOCATION_ZONES zone);
extern int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl);
extern int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count);
extern int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn,
s64 count);

View File

@ -2,7 +2,6 @@
* 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
@ -94,8 +93,7 @@ typedef struct {
version is 1. */
/* 28*/ sle16 major_ver; /* Log file major version. We only support
version 1.1. */
/* 30*/ le16 usn;
/* sizeof() = 32 (0x20) bytes */
/* sizeof() = 30 (0x1e) bytes */
} __attribute__((__packed__)) RESTART_PAGE_HEADER;
/*
@ -103,8 +101,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
@ -310,36 +308,35 @@ typedef struct {
typedef struct {
/* 0 NTFS_RECORD; -- Unfolded here as gcc doesn't like unnamed structs. */
NTFS_RECORD_TYPES magic;/* Usually the magic is "RCRD". */
le16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
u16 usa_ofs; /* See NTFS_RECORD definition in layout.h.
When creating, set this to be immediately
after this header structure (without any
alignment). */
le16 usa_count; /* See NTFS_RECORD definition in layout.h. */
u16 usa_count; /* See NTFS_RECORD definition in layout.h. */
union {
leLSN last_lsn;
sle64 file_offset;
LSN last_lsn;
s64 file_offset;
} __attribute__((__packed__)) copy;
le32 flags;
le16 page_count;
le16 page_position;
le16 next_record_offset;
le16 reserved[3];
leLSN last_end_lsn;
u32 flags;
u16 page_count;
u16 page_position;
union {
struct {
u16 next_record_offset;
u8 reserved[6];
LSN last_end_lsn;
} __attribute__((__packed__)) packed;
} __attribute__((__packed__)) header;
} __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?)
*/
typedef enum {
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),
LOG_RECORD_SIZE_PLACE_HOLDER = 0xffff,
/* This has nothing to do with the log record. It is only so
gcc knows to make the flags 16-bit. */
@ -349,120 +346,47 @@ typedef enum {
* struct LOG_CLIENT_ID - The log client id structure identifying a log client.
*/
typedef struct {
le16 seq_number;
le16 client_index;
u16 seq_number;
u16 client_index;
} __attribute__((__packed__)) LOG_CLIENT_ID;
/*
* LOG_RECORD_TYPE : types of log records
*/
enum {
LOG_STANDARD = const_cpu_to_le32(1),
LOG_CHECKPOINT = const_cpu_to_le32(2),
LOG_RECORD_TYPE_PLACE_HOLDER = 0xffffffffU
} ;
typedef le32 LOG_RECORD_TYPE;
/*
* ATTRIBUTE_FLAGS : flags describing the kind of NTFS record
* is being updated.
* These flags were introduced in Vista, only two flags are known?
*/
enum {
ACTS_ON_MFT = const_cpu_to_le16(2),
ACTS_ON_INDX = const_cpu_to_le16(8),
ATTRIBUTE_FLAGS_PLACE_HOLDER = 0xffff,
} ;
typedef le16 ATTRIBUTE_FLAGS;
#define LOG_RECORD_HEAD_SZ 0x30 /* size of header of struct LOG_RECORD */
/**
* struct LOG_RECORD - Log record header.
*
* Each log record seems to have a constant size of 0x70 bytes.
*/
typedef struct {
leLSN this_lsn;
leLSN client_previous_lsn;
leLSN client_undo_next_lsn;
le32 client_data_length;
LSN this_lsn;
LSN client_previous_lsn;
LSN client_undo_next_lsn;
u32 client_data_length;
LOG_CLIENT_ID client_id;
LOG_RECORD_TYPE record_type;
le32 transaction_id;
LOG_RECORD_FLAGS log_record_flags;
le16 reserved_or_alignment[3];
u32 record_type;
u32 transaction_id;
u16 flags;
u16 reserved_or_alignment[3];
/* Now are at ofs 0x30 into struct. */
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; /* Number of lcn_list entries
u16 redo_operation;
u16 undo_operation;
u16 redo_offset;
u16 redo_length;
u16 undo_offset;
u16 undo_length;
u16 target_attribute;
u16 lcns_to_follow; /* Number of lcn_list entries
following this entry. */
/* Now at ofs 0x40. */
le16 record_offset;
le16 attribute_offset;
le16 cluster_index;
ATTRIBUTE_FLAGS attribute_flags;
leVCN target_vcn;
u16 record_offset;
u16 attribute_offset;
u32 alignment_or_reserved;
VCN target_vcn;
/* Now at ofs 0x50. */
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__));
struct { /* Only present if lcns_to_follow
is not 0. */
LCN lcn;
} __attribute__((__packed__)) lcn_list[0];
} __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

@ -114,8 +114,5 @@ int ntfs_log_redirect(const char *function, const char *file, int line,
#define ntfs_log_leave(FORMAT, ARGS...)do {} while (0)
#endif /* DEBUG */
void ntfs_log_early_error(const char *format, ...)
__attribute__((format(printf, 1, 2)));
#endif /* _LOGGING_H_ */

View File

@ -124,8 +124,6 @@ extern int ntfs_mft_record_format(const ntfs_volume *vol, const MFT_REF mref);
extern ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni);
extern ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data);
extern int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni);
extern int ntfs_mft_usn_dec(MFT_RECORD *mrec);

View File

@ -1,6 +1,7 @@
/*
* misc.h : miscellaneous exports
* - memory allocation
* - LRU caches
*
* Copyright (c) 2008 Jean-Pierre Andre
*
@ -23,10 +24,51 @@
#ifndef _NTFS_MISC_H_
#define _NTFS_MISC_H_
#include "volume.h"
struct CACHED_GENERIC {
struct CACHED_GENERIC *next;
void *variable;
size_t varsize;
void *fixed[0];
} ;
struct CACHED_INODE {
struct CACHED_INODE *next;
const char *pathname;
size_t varsize;
/* above fields must match "struct CACHED_GENERIC" */
u64 inum;
} ;
typedef int (*cache_compare)(const struct CACHED_GENERIC *cached,
const struct CACHED_GENERIC *item);
struct CACHE_HEADER {
const char *name;
struct CACHED_GENERIC *most_recent_entry;
struct CACHED_GENERIC *free_entry;
unsigned long reads;
unsigned long writes;
unsigned long hits;
int fixed_size;
struct CACHED_GENERIC entry[0];
} ;
/* cast to generic, avoiding gcc warnings */
#define GENERIC(pstr) ((const struct CACHED_GENERIC*)(const void*)(pstr))
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *wanted, cache_compare compare);
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item, cache_compare compare);
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item, cache_compare compare);
void ntfs_create_lru_caches(ntfs_volume *vol);
void ntfs_free_lru_caches(ntfs_volume *vol);
void *ntfs_calloc(size_t size);
void *ntfs_malloc(size_t size);
void *ntfs_realloc(void *ptr, size_t size);
void ntfs_free(void *ptr);
#endif /* _NTFS_MISC_H_ */

View File

@ -25,11 +25,8 @@
#include "types.h"
#include "layout.h"
#include "volume.h"
extern int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size);
extern int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
BOOL warn);
extern int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size);
extern void ntfs_mst_post_write_fixup(NTFS_RECORD *b);

View File

@ -3,7 +3,6 @@
*
* Copyright (c) 2005 Anton Altaparmakov
* Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -27,105 +26,44 @@
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif
#include "types.h"
/*
* assume "struct timespec" is not defined if st_mtime is not defined
*/
#if !defined(st_mtime) & !defined(__timespec_defined)
struct timespec {
time_t tv_sec;
long tv_nsec;
} ;
#endif
/*
* There are four times more conversions of internal representation
* to ntfs representation than any other conversion, so the most
* efficient internal representation is ntfs representation
* (with low endianness)
*/
typedef sle64 ntfs_time;
#define NTFS_TIME_OFFSET ((s64)(369 * 365 + 89) * 24 * 3600 * 10000000)
/**
* ntfs2timespec - Convert an NTFS time to Unix time
* ntfs2utc - Convert an NTFS time to Unix time
* @ntfs_time: An NTFS time in 100ns units since 1601
*
* NTFS stores times as the number of 100ns intervals since January 1st 1601 at
* 00:00 UTC. This system will not suffer from Y2K problems until ~57000AD.
*
* Return: A Unix time (number of seconds since 1970, and nanoseconds)
* Return: n A Unix time (number of seconds since 1970)
*/
static __inline__ struct timespec ntfs2timespec(ntfs_time ntfstime)
static __inline__ time_t ntfs2utc(s64 ntfs_time)
{
struct timespec spec;
s64 cputime;
cputime = sle64_to_cpu(ntfstime);
spec.tv_sec = (cputime - (NTFS_TIME_OFFSET)) / 10000000;
spec.tv_nsec = (cputime - (NTFS_TIME_OFFSET)
- (s64)spec.tv_sec*10000000)*100;
/* force zero nsec for overflowing dates */
if ((spec.tv_nsec < 0) || (spec.tv_nsec > 999999999))
spec.tv_nsec = 0;
return (spec);
return (sle64_to_cpu(ntfs_time) - (NTFS_TIME_OFFSET)) / 10000000;
}
/**
* timespec2ntfs - Convert Linux time to NTFS time
* utc2ntfs - Convert Linux time to NTFS time
* @utc_time: Linux time to convert to NTFS
*
* Convert the Linux time @utc_time to its corresponding NTFS time.
*
* Linux stores time in a long at present and measures it as the number of
* 1-second intervals since 1st January 1970, 00:00:00 UTC
* with a separated non-negative nanosecond value
* 1-second intervals since 1st January 1970, 00:00:00 UTC.
*
* NTFS uses Microsoft's standard time format which is stored in a sle64 and is
* NTFS uses Microsoft's standard time format which is stored in a s64 and is
* measured as the number of 100 nano-second intervals since 1st January 1601,
* 00:00:00 UTC.
*
* Return: An NTFS time (100ns units since Jan 1601)
* Return: n An NTFS time (100ns units since Jan 1601)
*/
static __inline__ ntfs_time timespec2ntfs(struct timespec spec)
static __inline__ s64 utc2ntfs(time_t utc_time)
{
s64 units;
units = (s64)spec.tv_sec * 10000000
+ NTFS_TIME_OFFSET + spec.tv_nsec/100;
return (cpu_to_sle64(units));
}
/*
* Return the current time in ntfs format
*/
static __inline__ ntfs_time ntfs_current_time(void)
{
struct timespec now;
#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_SYS_CLOCK_GETTIME)
clock_gettime(CLOCK_REALTIME, &now);
#elif defined(HAVE_GETTIMEOFDAY)
struct timeval microseconds;
gettimeofday(&microseconds, (struct timezone*)NULL);
now.tv_sec = microseconds.tv_sec;
now.tv_nsec = microseconds.tv_usec*1000;
#else
now.tv_sec = time((time_t*)NULL);
now.tv_nsec = 0;
#endif
return (timespec2ntfs(now));
/* Convert to 100ns intervals and then add the NTFS time offset. */
return cpu_to_sle64((s64)utc_time * 10000000 + NTFS_TIME_OFFSET);
}
#endif /* _NTFS_NTFSTIME_H */

View File

@ -1,35 +0,0 @@
/*
*
* Copyright (c) 2008 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
*/
#ifndef OBJECT_ID_H
#define OBJECT_ID_H
int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size);
int ntfs_set_ntfs_object_id(ntfs_inode *ni, const char *value,
size_t size, int flags);
int ntfs_remove_ntfs_object_id(ntfs_inode *ni);
int ntfs_delete_object_id_index(ntfs_inode *ni);
#endif /* OBJECT_ID_H */

View File

@ -1,163 +0,0 @@
/*
* param.h - Parameter values for ntfs-3g
*
* Copyright (c) 2009-2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_PARAM_H
#define _NTFS_PARAM_H
#define CACHE_INODE_SIZE 32 /* inode cache, zero or >= 3 and not too big */
#define CACHE_NIDATA_SIZE 64 /* idata cache, zero or >= 3 and not too big */
#define CACHE_LOOKUP_SIZE 64 /* lookup cache, zero or >= 3 and not too big */
#define CACHE_SECURID_SIZE 16 /* securid cache, zero or >= 3 and not too big */
#define CACHE_LEGACY_SIZE 8 /* legacy cache size, zero or >= 3 and not too big */
#define FORCE_FORMAT_v1x 0 /* Insert security data as in NTFS v1.x */
#define OWNERFROMACL 1 /* Get the owner from ACL (not Windows owner) */
/* default security sub-authorities */
enum {
DEFSECAUTH1 = -1153374643, /* 3141592653 */
DEFSECAUTH2 = 589793238,
DEFSECAUTH3 = 462843383,
DEFSECBASE = 10000
};
/*
* Parameters for formatting
*/
/* Up to Windows 10, the cluster size was limited to 64K */
#define NTFS_MAX_CLUSTER_SIZE 2097152 /* Windows 10 Creators allows 2MB */
/*
* Parameters for compression
*/
/* default option for compression */
#define DEFAULT_COMPRESSION 1
/* (log2 of) number of clusters in a compression block for new files */
#define STANDARD_COMPRESSION_UNIT 4
/* maximum cluster size for allowing compression for new files */
#define MAX_COMPRESSION_CLUSTER_SIZE 4096
/*
* Parameters for default options
*/
#define DEFAULT_DMTIME 60 /* default 1mn for delay_mtime */
/*
* Use of big write buffers
*
* With small volumes, the cluster allocator may fail to allocate
* enough clusters when the volume is nearly full. At most a run
* can be allocated per bitmap chunk. So, there is a danger when the
* number of chunks (capacity/(32768*clsiz)) is less than the number
* of clusters in the biggest write buffer (131072/clsiz). Hence
* a safe minimal capacity is 4GB
*/
#define SAFE_CAPACITY_FOR_BIG_WRITES 0x100000000LL
/*
* Parameters for runlists
*/
/* only update the final extent of a runlist when appending data */
#define PARTIAL_RUNLIST_UPDATING 1
/*
* Parameters for upper-case table
*/
/* Create upper-case tables as defined by Windows 6.1 (Win7) */
#define UPCASE_MAJOR 6
#define UPCASE_MINOR 1
/*
* Parameters for user and xattr mappings
*/
#define XATTRMAPPINGFILE ".NTFS-3G/XattrMapping" /* default mapping file */
/*
* Parameters for path canonicalization
*/
#define MAPPERNAMELTH 256
/*
* Permission checking modes for high level and low level
*
* The choices for high and low lowel are independent, they have
* no effect on the library
*
* Stick to the recommended values unless you understand the consequences
* on protection and performances. Use of cacheing is good for
* 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.
*
* Irrespective of the selected mode, cacheing is always used
* in read-only mounts
*
* Possible values for high level :
* 1 : no cache, kernel control (recommended)
* 4 : no cache, file system control
* 6 : kernel/fuse cache, file system control (OpenIndiana only)
* 7 : no cache, kernel control for ACLs
*
* Possible values for low level :
* 2 : no cache, kernel control
* 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, 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.
*/
#define TIMEOUT_RO 600 /* Attribute time out for read-only mounts */
#if defined(__sun) && defined(__SVR4)
/*
* Access control by kernel is not implemented on OpenIndiana,
* however care is taken of cacheing hard-linked files.
*/
#define HPERMSCONFIG 6
#define LPERMSCONFIG 6
#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.
* Also ACL checks by recent kernels do not prove satisfactory.
*/
#define HPERMSCONFIG 1
#define LPERMSCONFIG 3
#endif /* defined(__sun) && defined(__SVR4) */
#endif /* defined _NTFS_PARAM_H */

View File

@ -1,194 +0,0 @@
/*
* plugin.h : define interface for plugin development
*
* Copyright (c) 2015-2021 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 "layout.h"
#include "inode.h"
#include "dir.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 or directory
* 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 or directory
* 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
* with 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);
/*
* Open a directory
* 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 readdir(). When used
* this field must be non-null and freed in release().
* The returned value is zero for success and a negative errno
* value for failure.
*/
int (*opendir)(ntfs_inode *ni, const REPARSE_POINT *reparse,
struct fuse_file_info *fi);
/*
* Get entries from a directory
*
* Use the filldir() function with fillctx argument to return
* the directory entries.
* Names "." and ".." are expected to be returned.
* The returned value is zero for success and a negative errno
* value for failure.
*/
int (*readdir)(ntfs_inode *ni, const REPARSE_POINT *reparse,
s64 *pos, void *fillctx, ntfs_filldir_t filldir,
struct fuse_file_info *fi);
/*
* Create a new file of any type
*
* The returned value is a pointer to the inode created, or
* NULL if failed, with errno telling why.
*/
ntfs_inode *(*create)(ntfs_inode *dir_ni, const REPARSE_POINT *reparse,
le32 securid, ntfschar *name, int name_len,
mode_t type);
/*
* Link a new name to a file or directory
* Linking a directory is needed for renaming a directory
* 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 (*link)(ntfs_inode *dir_ni, const REPARSE_POINT *reparse,
ntfs_inode *ni, ntfschar *name, int name_len);
/*
* Unlink a name from a directory
* The argument pathname may be NULL
* The returned value is zero for success or a negative errno
* value for failure.
*/
int (*unlink)(ntfs_inode *dir_ni, const REPARSE_POINT *reparse,
const char *pathname,
ntfs_inode *ni, ntfschar *name, int name_len);
} 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

@ -1,24 +0,0 @@
/*
* realpath.h - realpath() aware of device mapper
*/
#ifndef REALPATH_H
#define REALPATH_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_REALPATH
#define ntfs_realpath realpath
#else
extern char *ntfs_realpath(const char *path, char *resolved_path);
#endif
#ifdef linux
extern char *ntfs_realpath_canonicalize(const char *path, char *resolved_path);
#else
#define ntfs_realpath_canonicalize ntfs_realpath
#endif
#endif /* REALPATH_H */

View File

@ -24,27 +24,15 @@
#ifndef REPARSE_H
#define REPARSE_H
char *ntfs_make_symlink(ntfs_inode *ni, const char *mnt_point);
char *ntfs_make_symlink(const char *org_path,
ntfs_inode *ni, int *pattr_size);
BOOL ntfs_possible_symlink(ntfs_inode *ni);
int ntfs_get_ntfs_reparse_data(ntfs_inode *ni, char *value, size_t size);
char *ntfs_get_abslink(ntfs_volume *vol, ntfschar *junction,
int count, const char *mnt_point, BOOL isdir);
REPARSE_POINT *ntfs_get_reparse_point(ntfs_inode *ni);
int ntfs_reparse_check_wsl(ntfs_inode *ni, const REPARSE_POINT *reparse);
int ntfs_reparse_set_wsl_symlink(ntfs_inode *ni,
const ntfschar *target, int target_len);
int ntfs_reparse_set_wsl_not_symlink(ntfs_inode *ni, mode_t mode);
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);
int ntfs_get_ntfs_reparse_data(const char *path,
char *value, size_t size, ntfs_inode *ni);
int ntfs_set_ntfs_reparse_data(const char *path, const char *value,
size_t size, int flags, ntfs_inode *ni);
int ntfs_remove_ntfs_reparse_data(const char *path, ntfs_inode *ni);
int ntfs_delete_reparse_index(ntfs_inode *ni);

View File

@ -49,8 +49,7 @@ struct _runlist_element {/* In memory vcn to lcn mapping structure element. */
s64 length; /* Run length in clusters. */
};
extern runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
int more_entries);
extern runlist_element *ntfs_rl_extend(runlist_element *rl, int more_entries);
extern LCN ntfs_rl_vcn_to_lcn(const runlist_element *rl, const VCN vcn);

View File

@ -4,7 +4,7 @@
*
* Copyright (c) 2004 Anton Altaparmakov
* Copyright (c) 2005-2006 Szabolcs Szakacsits
* Copyright (c) 2007-2010 Jean-Pierre Andre
* Copyright (c) 2007-2008 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
@ -29,12 +29,20 @@
#include "layout.h"
#include "inode.h"
#include "dir.h"
#include "endians.h"
#ifndef POSIXACLS
#define POSIXACLS 0
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define const_cpu_to_be16(x) ((((x) & 255L) << 8) + (((x) >> 8) & 255L))
#define const_cpu_to_be32(x) ((((x) & 255L) << 24) + (((x) & 0xff00L) << 8) \
+ (((x) >> 8) & 0xff00L) + (((x) >> 24) & 255L))
#else
#define const_cpu_to_be16(x) (x)
#define const_cpu_to_be32(x) (x)
#endif
/*
* item in the mapping list
*/
@ -71,10 +79,8 @@ struct CACHED_PERMISSIONS {
struct CACHED_PERMISSIONS_LEGACY {
struct CACHED_PERMISSIONS_LEGACY *next;
struct CACHED_PERMISSIONS_LEGACY *previous;
void *variable;
size_t varsize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
u64 mft_no;
struct CACHED_PERMISSIONS perm;
@ -86,10 +92,8 @@ struct CACHED_PERMISSIONS_LEGACY {
struct CACHED_SECURID {
struct CACHED_SECURID *next;
struct CACHED_SECURID *previous;
void *variable;
size_t varsize;
union ALIGNMENT payload[0];
/* above fields must match "struct CACHED_GENERIC" */
uid_t uid;
gid_t gid;
@ -126,7 +130,6 @@ struct PERMISSIONS_CACHE {
enum {
SECURITY_DEFAULT, /* rely on fuse for permissions checking */
SECURITY_RAW, /* force same ownership/permissions on files */
SECURITY_ACL, /* enable Posix ACLs (when compiled in) */
SECURITY_ADDSECURIDS, /* upgrade old security descriptors */
SECURITY_STATICGRPS, /* use static groups for access control */
SECURITY_WANTED /* a security related option was present */
@ -158,14 +161,14 @@ struct POSIX_ACE {
u16 tag;
u16 perms;
s32 id;
} __attribute__((__packed__));
} ;
struct POSIX_ACL {
u8 version;
u8 flags;
u16 filler;
struct POSIX_ACE ace[0];
} __attribute__((__packed__));
} ;
struct POSIX_SECURITY {
mode_t mode;
@ -173,7 +176,6 @@ struct POSIX_SECURITY {
int defcnt;
int firstdef;
u16 tagsset;
u16 filler;
struct POSIX_ACL acl;
} ;
@ -211,6 +213,22 @@ enum {
extern BOOL ntfs_guid_is_zero(const GUID *guid);
extern char *ntfs_guid_to_mbs(const GUID *guid, char *guid_str);
/**
* ntfs_sid_is_valid - determine if a SID is valid
* @sid: SID for which to determine if it is valid
*
* Determine if the SID pointed to by @sid is valid.
*
* Return TRUE if it is valid and FALSE otherwise.
*/
static __inline__ BOOL ntfs_sid_is_valid(const SID *sid)
{
if (!sid || sid->revision != SID_REVISION ||
sid->sub_authority_count > SID_MAX_SUB_AUTHORITIES)
return FALSE;
return TRUE;
}
extern int ntfs_sid_to_mbs_size(const SID *sid);
extern char *ntfs_sid_to_mbs(const SID *sid, char *sid_str,
size_t sid_str_size);
@ -220,31 +238,28 @@ extern int ntfs_sd_add_everyone(ntfs_inode *ni);
extern le32 ntfs_security_hash(const SECURITY_DESCRIPTOR_RELATIVE *sd,
const u32 len);
int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path,
BOOL allowdef);
int ntfs_build_mapping(struct SECURITY_CONTEXT *scx, const char *usermap_path);
int ntfs_get_owner_mode(struct SECURITY_CONTEXT *scx,
ntfs_inode *ni, struct stat*);
int ntfs_set_mode(struct SECURITY_CONTEXT *scx, ntfs_inode *ni, mode_t mode);
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni);
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx,
const char *path, ntfs_inode *ni, struct stat*);
int ntfs_set_mode(struct SECURITY_CONTEXT *scx,
const char *path, ntfs_inode *ni, mode_t mode);
BOOL ntfs_allowed_as_owner(struct SECURITY_CONTEXT *scx,
const char *path, ntfs_inode *ni);
int ntfs_allowed_access(struct SECURITY_CONTEXT *scx, const char *path,
ntfs_inode *ni, int accesstype);
int ntfs_allowed_create(struct SECURITY_CONTEXT *scx,
ntfs_inode *ni, gid_t *pgid, mode_t *pdsetgid);
BOOL old_ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
BOOL ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
const char *path, int accesstype);
#if POSIXACLS
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
uid_t uid, gid_t gid, ntfs_inode *dir_ni,
mode_t mode, BOOL isdir);
uid_t uid, gid_t gid, const char *dir_path,
ntfs_inode *dir_ni, mode_t mode, BOOL isdir);
#else
le32 ntfs_alloc_securid(struct SECURITY_CONTEXT *scx,
uid_t uid, gid_t gid, mode_t mode, BOOL isdir);
#endif
int ntfs_set_owner(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
uid_t uid, gid_t gid);
int ntfs_set_ownmod(struct SECURITY_CONTEXT *scx,
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
int ntfs_set_owner(struct SECURITY_CONTEXT *scx,
const char *path, ntfs_inode *ni, uid_t uid, gid_t gid);
#if POSIXACLS
int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
ntfs_inode *ni, uid_t uid, gid_t gid,
@ -254,35 +269,36 @@ int ntfs_set_owner_mode(struct SECURITY_CONTEXT *scx,
ntfs_inode *ni, uid_t uid, gid_t gid, mode_t mode);
#endif
le32 ntfs_inherited_id(struct SECURITY_CONTEXT *scx,
ntfs_inode *dir_ni, BOOL fordir);
const char *dir_path, ntfs_inode *dir_ni, BOOL fordir);
int ntfs_open_secure(ntfs_volume *vol);
int ntfs_close_secure(ntfs_volume *vol);
void ntfs_destroy_security_context(struct SECURITY_CONTEXT *scx);
void ntfs_close_secure(struct SECURITY_CONTEXT *scx);
#if POSIXACLS
int ntfs_set_inherited_posix(struct SECURITY_CONTEXT *scx,
ntfs_inode *ni, uid_t uid, gid_t gid,
ntfs_inode *dir_ni, mode_t mode);
int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
const char *name, char *value, size_t size);
int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
const char *dir_path, ntfs_inode *dir_ni, mode_t mode);
int ntfs_get_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
const char *name, char *value, size_t size,
ntfs_inode *ni);
int ntfs_set_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
const char *name, const char *value, size_t size,
int flags);
int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
const char *name);
int flags, ntfs_inode *ni);
int ntfs_remove_posix_acl(struct SECURITY_CONTEXT *scx, const char *path,
const char *name, ntfs_inode *ni);
#endif
int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
char *value, size_t size);
int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, ntfs_inode *ni,
const char *value, size_t size, int flags);
int ntfs_get_ntfs_attrib(ntfs_inode *ni, char *value, size_t size);
int ntfs_set_ntfs_attrib(ntfs_inode *ni,
const char *value, size_t size, int flags);
int ntfs_get_ntfs_acl(struct SECURITY_CONTEXT *scx, const char *path,
const char *name, char *value, size_t size,
ntfs_inode *ni);
int ntfs_set_ntfs_acl(struct SECURITY_CONTEXT *scx, const char *path,
const char *name, const char *value, size_t size,
int flags, ntfs_inode *ni);
int ntfs_get_ntfs_attrib(const char *path,
char *value, size_t size, ntfs_inode *ni);
int ntfs_set_ntfs_attrib(const char *path,
const char *value, size_t size, int flags,
ntfs_inode *ni);
/*
* Security API for direct access to security descriptors
@ -327,7 +343,7 @@ INDEX_ENTRY *ntfs_read_sii(struct SECURITY_API *scapi,
INDEX_ENTRY *ntfs_read_sdh(struct SECURITY_API *scapi,
INDEX_ENTRY *entry);
struct SECURITY_API *ntfs_initialize_file_security(const char *device,
unsigned long flags);
int flags);
BOOL ntfs_leave_file_security(struct SECURITY_API *scx);
int ntfs_get_usid(struct SECURITY_API *scapi, uid_t uid, char *buf);

View File

@ -48,23 +48,15 @@ typedef u16 le16;
typedef u32 le32;
typedef u64 le64;
typedef u16 be16;
typedef u32 be32;
typedef u64 be64;
/*
* Declare s{l,b}e{16,32,64} to be unsigned because we do not want sign
* extension on BE architectures.
* Declare sle{16,32,64} to be unsigned because we do not want sign extension
* on BE architectures.
*/
typedef u16 sle16;
typedef u32 sle32;
typedef u64 sle64;
typedef u16 sbe16;
typedef u32 sbe32;
typedef u64 sbe64;
typedef le16 ntfschar; /* 2-byte Unicode character type. */
typedef u16 ntfschar; /* 2-byte Unicode character type. */
#define UCHAR_T_SIZE_BITS 1
/*
@ -128,13 +120,5 @@ typedef enum {
#define STATUS_KEEP_SEARCHING (-3)
#define STATUS_NOT_FOUND (-4)
/*
* Force alignment in a struct if required by processor
*/
union ALIGNMENT {
u64 u64align;
void *ptralign;
} ;
#endif /* defined _NTFS_TYPES_H */

View File

@ -30,9 +30,9 @@ extern BOOL ntfs_names_are_equal(const ntfschar *s1, size_t s1_len,
const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
const ntfschar *upcase, const u32 upcase_size);
extern int ntfs_names_full_collate(const ntfschar *name1, const u32 name1_len,
extern int ntfs_names_collate(const ntfschar *name1, const u32 name1_len,
const ntfschar *name2, const u32 name2_len,
const IGNORE_CASE_BOOL ic,
const int err_val, const IGNORE_CASE_BOOL ic,
const ntfschar *upcase, const u32 upcase_len);
extern int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n);
@ -47,30 +47,25 @@ extern ntfschar *ntfs_ucsndup(const ntfschar *s, u32 maxlen);
extern void ntfs_name_upcase(ntfschar *name, u32 name_len,
const ntfschar *upcase, const u32 upcase_len);
extern void ntfs_name_locase(ntfschar *name, u32 name_len,
const ntfschar *locase, const u32 locase_len);
extern void ntfs_file_value_upcase(FILE_NAME_ATTR *file_name_attr,
const ntfschar *upcase, const u32 upcase_len);
extern int ntfs_file_values_compare(const FILE_NAME_ATTR *file_name_attr1,
const FILE_NAME_ATTR *file_name_attr2,
const int err_val, const IGNORE_CASE_BOOL ic,
const ntfschar *upcase, const u32 upcase_len);
extern int ntfs_ucstombs(const ntfschar *ins, const int ins_len, char **outs,
int outs_len);
extern int ntfs_mbstoucs(const char *ins, ntfschar **outs);
extern char *ntfs_uppercase_mbs(const char *low,
const ntfschar *upcase, u32 upcase_len);
extern void ntfs_upcase_table_build(ntfschar *uc, u32 uc_len);
extern u32 ntfs_upcase_build_default(ntfschar **upcase);
extern ntfschar *ntfs_locase_table_build(const ntfschar *uc, u32 uc_cnt);
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, BOOL strict);
extern BOOL ntfs_forbidden_names(ntfs_volume *vol,
const ntfschar *name, int len, BOOL strict);
extern BOOL ntfs_forbidden_chars(const ntfschar *name, int len);
extern BOOL ntfs_collapsible_chars(ntfs_volume *vol,
const ntfschar *shortname, int shortlen,
const ntfschar *longname, int longlen);

View File

@ -5,7 +5,6 @@
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2005-2006 Yura Pakhuchiy
* Copyright (c) 2005-2009 Szabolcs Szakacsits
* Copyright (c) 2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -36,15 +35,36 @@
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
/* Do not #include <sys/mount.h> here : conflicts with <linux/fs.h> */
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
#define CACHE_INODE_SIZE 32 /* inode cache, zero or >= 3 and not too big */
#define CACHE_SECURID_SIZE 16 /* securid cache, zero or >= 3 and not too big */
#define CACHE_LEGACY_SIZE 8 /* legacy cache size, zero or >= 3 and not too big */
/*
* Under Cygwin, DJGPP and FreeBSD we do not have MS_RDONLY,
* so we define them ourselves.
*/
#ifndef MS_RDONLY
#define MS_RDONLY 1
#endif
#define MS_EXCLUSIVE 0x08000000
#ifndef MS_RECOVER
#define MS_RECOVER 0x10000000
#endif
#define MS_IGNORE_HIBERFILE 0x20000000
/* Forward declaration */
typedef struct _ntfs_volume ntfs_volume;
#include "param.h"
#include "types.h"
#include "support.h"
#include "device.h"
@ -55,30 +75,13 @@ typedef struct _ntfs_volume ntfs_volume;
/**
* enum ntfs_mount_flags -
*
* Flags for the ntfs_mount() function.
*/
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,
NTFS_MNT_RECOVER = 0x10000000,
NTFS_MNT_IGNORE_HIBERFILE = 0x20000000,
};
typedef unsigned long ntfs_mount_flags;
/**
* enum ntfs_mounted_flags -
*
* Flags returned by the ntfs_check_if_mounted() function.
*/
typedef enum {
NTFS_MF_MOUNTED = 1, /* Device is mounted. */
NTFS_MF_ISROOT = 2, /* Device is mounted as system root. */
NTFS_MF_READONLY = 4, /* Device is mounted read-only. */
} ntfs_mounted_flags;
} ntfs_mount_flags;
extern int ntfs_check_if_mounted(const char *file, unsigned long *mnt_flags);
@ -98,11 +101,6 @@ typedef enum {
NTFS_VOLUME_INSECURE = 22
} ntfs_volume_status;
typedef enum {
NTFS_FILES_INTERIX,
NTFS_FILES_WSL,
} ntfs_volume_special_files;
/**
* enum ntfs_volume_state_bits -
*
@ -112,12 +110,6 @@ typedef enum {
NV_ReadOnly, /* 1: Volume is read-only. */
NV_CaseSensitive, /* 1: Volume is mounted case-sensitive. */
NV_LogFileEmpty, /* 1: $logFile journal is empty. */
NV_ShowSysFiles, /* 1: Show NTFS metafiles. */
NV_ShowHidFiles, /* 1: Show files marked hidden. */
NV_HideDotFiles, /* 1: Set hidden flag on dot files */
NV_Compression, /* 1: allow compression */
NV_NoFixupWarn, /* 1: Do not log fixup errors */
NV_FreeSpaceKnown, /* 1: The free space is now known */
} ntfs_volume_state_bits;
#define test_nvol_flag(nv, flag) test_bit(NV_##flag, (nv)->state)
@ -136,30 +128,6 @@ typedef enum {
#define NVolSetLogFileEmpty(nv) set_nvol_flag(nv, LogFileEmpty)
#define NVolClearLogFileEmpty(nv) clear_nvol_flag(nv, LogFileEmpty)
#define NVolShowSysFiles(nv) test_nvol_flag(nv, ShowSysFiles)
#define NVolSetShowSysFiles(nv) set_nvol_flag(nv, ShowSysFiles)
#define NVolClearShowSysFiles(nv) clear_nvol_flag(nv, ShowSysFiles)
#define NVolShowHidFiles(nv) test_nvol_flag(nv, ShowHidFiles)
#define NVolSetShowHidFiles(nv) set_nvol_flag(nv, ShowHidFiles)
#define NVolClearShowHidFiles(nv) clear_nvol_flag(nv, ShowHidFiles)
#define NVolHideDotFiles(nv) test_nvol_flag(nv, HideDotFiles)
#define NVolSetHideDotFiles(nv) set_nvol_flag(nv, HideDotFiles)
#define NVolClearHideDotFiles(nv) clear_nvol_flag(nv, HideDotFiles)
#define NVolCompression(nv) test_nvol_flag(nv, Compression)
#define NVolSetCompression(nv) set_nvol_flag(nv, Compression)
#define NVolClearCompression(nv) clear_nvol_flag(nv, Compression)
#define NVolNoFixupWarn(nv) test_nvol_flag(nv, NoFixupWarn)
#define NVolSetNoFixupWarn(nv) set_nvol_flag(nv, NoFixupWarn)
#define NVolClearNoFixupWarn(nv) clear_nvol_flag(nv, NoFixupWarn)
#define NVolFreeSpaceKnown(nv) test_nvol_flag(nv, FreeSpaceKnown)
#define NVolSetFreeSpaceKnown(nv) set_nvol_flag(nv, FreeSpaceKnown)
#define NVolClearFreeSpaceKnown(nv) clear_nvol_flag(nv, FreeSpaceKnown)
/*
* NTFS version 1.1 and 1.2 are used by Windows NT4.
* NTFS version 2.x is used by Windows 2000 Beta
@ -191,7 +159,7 @@ struct _ntfs_volume {
ntfs_inode *vol_ni; /* ntfs_inode structure for FILE_Volume. */
u8 major_ver; /* Ntfs major version of volume. */
u8 minor_ver; /* Ntfs minor version of volume. */
le16 flags; /* Bit array of VOLUME_* flags. */
u16 flags; /* Bit array of VOLUME_* flags. */
u16 sector_size; /* Byte size of a sector. */
u8 sector_size_bits; /* Log(2) of the byte size of a sector. */
@ -252,9 +220,6 @@ struct _ntfs_volume {
FILE_UpCase. */
u32 upcase_len; /* Length in Unicode characters of the upcase
table. */
ntfschar *locase; /* Lower case equivalents of all 65536 2-byte
Unicode characters. Only if option
case_ignore is set. */
ATTR_DEF *attrdef; /* Attribute definitions. Obtained from
FILE_AttrDef. */
@ -266,26 +231,17 @@ struct _ntfs_volume {
s64 free_mft_records; /* Same for free mft records (see above) */
BOOL efs_raw; /* volume is mounted for raw access to
efs-encrypted files */
ntfs_volume_special_files special_files; /* Implementation of special files */
const char *abs_mnt_point; /* Mount point */
#ifdef XATTR_MAPPINGS
struct XATTRMAPPING *xattr_mapping;
#endif /* XATTR_MAPPINGS */
#if CACHE_INODE_SIZE
struct CACHE_HEADER *xinode_cache;
#endif
#if CACHE_NIDATA_SIZE
struct CACHE_HEADER *nidata_cache;
#endif
#if CACHE_LOOKUP_SIZE
struct CACHE_HEADER *lookup_cache;
#endif
#if CACHE_SECURID_SIZE
struct CACHE_HEADER *securid_cache;
#endif
#if CACHE_LEGACY_SIZE
struct CACHE_HEADER *legacy_cache;
#endif
};
extern const char *ntfs_home;
@ -293,31 +249,26 @@ extern const char *ntfs_home;
extern ntfs_volume *ntfs_volume_alloc(void);
extern ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
ntfs_mount_flags flags);
unsigned long flags);
extern ntfs_volume *ntfs_device_mount(struct ntfs_device *dev,
ntfs_mount_flags flags);
unsigned long flags);
extern ntfs_volume *ntfs_mount(const char *name, ntfs_mount_flags flags);
extern ntfs_volume *ntfs_mount(const char *name, unsigned long flags);
extern int ntfs_umount(ntfs_volume *vol, const BOOL force);
extern int ntfs_version_is_supported(ntfs_volume *vol);
extern int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose);
extern int ntfs_logfile_reset(ntfs_volume *vol);
extern int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags);
extern int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags);
extern int ntfs_volume_error(int err);
extern void ntfs_mount_error(const char *vol, const char *mntpoint, int err);
extern int ntfs_volume_get_free_space(ntfs_volume *vol);
extern int ntfs_volume_rename(ntfs_volume *vol, const ntfschar *label,
int label_len);
extern int ntfs_set_shown_files(ntfs_volume *vol,
BOOL show_sys_files, BOOL show_hid_files, BOOL hide_dot_files);
extern int ntfs_set_locale(void);
extern int ntfs_set_ignore_case(ntfs_volume *vol);
#endif /* defined _NTFS_VOLUME_H */

View File

@ -1,97 +0,0 @@
/*
* xattrs.h : definitions related to system extended attributes
*
* Copyright (c) 2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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
*/
enum SYSTEMXATTRS {
XATTR_UNMAPPED,
XATTR_NTFS_ACL,
XATTR_NTFS_ATTRIB,
XATTR_NTFS_ATTRIB_BE,
XATTR_NTFS_EFSINFO,
XATTR_NTFS_REPARSE_DATA,
XATTR_NTFS_OBJECT_ID,
XATTR_NTFS_DOS_NAME,
XATTR_NTFS_TIMES,
XATTR_NTFS_TIMES_BE,
XATTR_NTFS_CRTIME,
XATTR_NTFS_CRTIME_BE,
XATTR_NTFS_EA,
XATTR_POSIX_ACC,
XATTR_POSIX_DEF
} ;
struct XATTRMAPPING {
struct XATTRMAPPING *next;
enum SYSTEMXATTRS xattr;
char name[1]; /* variable length */
} ;
#ifdef XATTR_MAPPINGS
struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol,
const char *path);
void ntfs_xattr_free_mapping(struct XATTRMAPPING*);
#endif /* XATTR_MAPPINGS */
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,
char *value, size_t size);
int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx,
enum SYSTEMXATTRS attr,
ntfs_inode *ni, ntfs_inode *dir_ni,
const char *value, size_t size, int flags);
int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
enum SYSTEMXATTRS attr,
ntfs_inode *ni, ntfs_inode *dir_ni);
#endif /* _NTFS_XATTRS_H_ */

View File

@ -7,10 +7,6 @@ endif
libfuse_lite_la_CFLAGS= \
$(AM_CFLAGS) \
$(LIBFUSE_LITE_CFLAGS)
libfuse_lite_la_CPPFLAGS= \
$(AM_CPPFLAGS) \
-I$(top_srcdir)/include/fuse-lite
libfuse_lite_la_LIBADD = $(LIBFUSE_LITE_LIBS)
@ -30,5 +26,3 @@ libfuse_lite_la_SOURCES = \
mount.c \
mount_util.c \
mount_util.h
libs: libfuse-lite.la

View File

@ -6,11 +6,6 @@
See the file COPYING.LIB
*/
#ifdef __SOLARIS__
/* For pthread_rwlock_t */
#define _GNU_SOURCE
#endif /* __SOLARIS__ */
#include "config.h"
#include "fuse_i.h"
#include "fuse_lowlevel.h"
@ -33,10 +28,6 @@
#include <sys/uio.h>
#include <sys/time.h>
#ifdef __SOLARIS__
#define FUSE_MAX_PATH 4096
#endif /* __SOLARIS__ */
#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
#define FUSE_UNKNOWN_INO 0xffffffff
@ -63,27 +54,13 @@ struct fuse_config {
int intr;
int intr_signal;
int help;
#ifdef __SOLARIS__
int auto_cache;
char *modules;
#endif /* __SOLARIS__ */
};
struct fuse_fs {
struct fuse_operations op;
void *user_data;
#ifdef __SOLARIS__
struct fuse_module *m;
#endif /* __SOLARIS__ */
};
#ifdef __SOLARIS__
struct fusemod_so {
void *handle;
int ctr;
};
#endif /* __SOLARIS__ */
struct fuse {
struct fuse_session *se;
struct node **name_table;
@ -120,12 +97,6 @@ struct node {
uint64_t nlookup;
int open_count;
int is_hidden;
#ifdef __SOLARIS__
struct timespec stat_updated;
struct timespec mtime;
off_t size;
int cache_valid;
#endif /* __SOLARIS__ */
struct lock *locks;
};
@ -134,6 +105,7 @@ struct fuse_dh {
struct fuse *fuse;
fuse_req_t req;
char *contents;
int allocated;
unsigned len;
unsigned size;
unsigned needlen;
@ -152,107 +124,6 @@ static pthread_key_t fuse_context_key;
static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
static int fuse_context_ref;
#ifdef __SOLARIS__
static struct fusemod_so *fuse_current_so;
static struct fuse_module *fuse_modules;
static int fuse_load_so_name(const char *soname)
{
struct fusemod_so *so;
so = calloc(1, sizeof(struct fusemod_so));
if (!so) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
fuse_current_so = so;
so->handle = dlopen(soname, RTLD_NOW);
fuse_current_so = NULL;
if (!so->handle) {
fprintf(stderr, "fuse: %s\n", dlerror());
goto err;
}
if (!so->ctr) {
fprintf(stderr, "fuse: %s did not register any modules", soname);
goto err;
}
return 0;
err:
if (so->handle)
dlclose(so->handle);
free(so);
return -1;
}
static int fuse_load_so_module(const char *module)
{
int res;
char *soname = malloc(strlen(module) + 64);
if (!soname) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
sprintf(soname, "libfusemod_%s.so", module);
res = fuse_load_so_name(soname);
free(soname);
return res;
}
static struct fuse_module *fuse_find_module(const char *module)
{
struct fuse_module *m;
for (m = fuse_modules; m; m = m->next) {
if (strcmp(module, m->name) == 0) {
m->ctr++;
break;
}
}
return m;
}
static struct fuse_module *fuse_get_module(const char *module)
{
struct fuse_module *m;
pthread_mutex_lock(&fuse_context_lock);
m = fuse_find_module(module);
if (!m) {
int err = fuse_load_so_module(module);
if (!err)
m = fuse_find_module(module);
}
pthread_mutex_unlock(&fuse_context_lock);
return m;
}
static void fuse_put_module(struct fuse_module *m)
{
pthread_mutex_lock(&fuse_context_lock);
assert(m->ctr > 0);
m->ctr--;
if (!m->ctr && m->so) {
struct fusemod_so *so = m->so;
assert(so->ctr > 0);
so->ctr--;
if (!so->ctr) {
struct fuse_module **mp;
for (mp = &fuse_modules; *mp;) {
if ((*mp)->so == so)
*mp = (*mp)->next;
else
mp = &(*mp)->next;
}
dlclose(so->handle);
free(so);
}
}
pthread_mutex_unlock(&fuse_context_lock);
}
#endif /* __SOLARIS__ */
static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
{
size_t hash = nodeid % f->id_table_size;
@ -425,15 +296,10 @@ static struct node *find_node(struct fuse *f, fuse_ino_t parent,
return node;
}
#ifndef __SOLARIS__
static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
#else /* __SOLARIS__ */
static char *add_name(char *buf, char *s, const char *name)
#endif /* __SOLARIS__ */
{
size_t len = strlen(name);
#ifndef __SOLARIS__
if (s - len <= *buf) {
unsigned pathlen = *bufsize - (s - *buf);
unsigned newbufsize = *bufsize;
@ -456,14 +322,7 @@ static char *add_name(char *buf, char *s, const char *name)
*bufsize = newbufsize;
}
s -= len;
#else /* ! __SOLARIS__ */
s -= len;
if (s <= buf) {
fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
return NULL;
}
#endif /* __SOLARIS__ */
memcpy(s, name, len);
strncpy(s, name, len);
s--;
*s = '/';
@ -472,42 +331,6 @@ static char *add_name(char *buf, char *s, const char *name)
static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
{
#ifdef __SOLARIS__
char buf[FUSE_MAX_PATH];
char *s = buf + FUSE_MAX_PATH - 1;
struct node *node;
*s = '\0';
if (name != NULL) {
s = add_name(buf, s, name);
if (s == NULL)
return NULL;
}
pthread_mutex_lock(&f->lock);
for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
node = node->parent) {
if (node->name == NULL) {
s = NULL;
break;
}
s = add_name(buf, s, node->name);
if (s == NULL)
break;
}
pthread_mutex_unlock(&f->lock);
if (node == NULL || s == NULL)
return NULL;
else if (*s == '\0')
return strdup("/");
else
return strdup(s);
#else /* __SOLARIS__ */
unsigned bufsize = 256;
char *buf;
char *s;
@ -552,7 +375,6 @@ static char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
out_free:
free(buf);
return NULL;
#endif /* __SOLARIS__ */
}
static char *get_path(struct fuse *f, fuse_ino_t nodeid)
@ -1039,21 +861,6 @@ int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
return -ENOSYS;
}
int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
struct fuse_file_info *fi, unsigned int flags, void *data)
{
fuse_get_context()->private_data = fs->user_data;
if (fs->op.ioctl) {
/*
if (fs->debug)
fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
(unsigned long long) fi->fh, cmd, flags);
*/
return fs->op.ioctl(path, cmd, arg, fi, flags, data);
} else
return -ENOSYS;
}
static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
{
struct node *node;
@ -1122,44 +929,6 @@ static int hide_node(struct fuse *f, const char *oldpath,
return err;
}
#ifdef __SOLARIS__
static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
{
return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
}
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
static void curr_time(struct timespec *now)
{
static clockid_t clockid = CLOCK_MONOTONIC;
int res = clock_gettime(clockid, now);
if (res == -1 && errno == EINVAL) {
clockid = CLOCK_REALTIME;
res = clock_gettime(clockid, now);
}
if (res == -1) {
perror("fuse: clock_gettime");
abort();
}
}
static void update_stat(struct node *node, const struct stat *stbuf)
{
if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
stbuf->st_size != node->size))
node->cache_valid = 0;
node->mtime.tv_sec = stbuf->st_mtime;
node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
node->size = stbuf->st_size;
curr_time(&node->stat_updated);
}
#endif /* __SOLARIS__ */
static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
const char *name, const char *path,
struct fuse_entry_param *e, struct fuse_file_info *fi)
@ -1182,13 +951,6 @@ static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
e->generation = node->generation;
e->entry_timeout = f->conf.entry_timeout;
e->attr_timeout = f->conf.attr_timeout;
#ifdef __SOLARIS__
if (f->conf.auto_cache) {
pthread_mutex_lock(&f->lock);
update_stat(node, &e->attr);
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
set_stat(f, e->ino, &e->attr);
if (f->conf.debug)
fprintf(stderr, " NODEID: %lu\n", (unsigned long) e->ino);
@ -1265,11 +1027,7 @@ static struct fuse *req_fuse_prepare(fuse_req_t req)
return c->ctx.fuse;
}
#ifndef __SOLARIS__
static void reply_err(fuse_req_t req, int err)
#else /* __SOLARIS__ */
static inline void reply_err(fuse_req_t req, int err)
#endif /* __SOLARIS__ */
{
/* fuse_reply_err() uses non-negated errno values */
fuse_reply_err(req, -err);
@ -1280,15 +1038,8 @@ 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);
}
@ -1315,10 +1066,6 @@ void fuse_fs_destroy(struct fuse_fs *fs)
fuse_get_context()->private_data = fs->user_data;
if (fs->op.destroy)
fs->op.destroy(fs->user_data);
#ifdef __SOLARIS__
if (fs->m)
fuse_put_module(fs->m);
#endif /* __SOLARIS__ */
free(fs);
}
@ -1395,13 +1142,6 @@ static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
}
pthread_rwlock_unlock(&f->tree_lock);
if (!err) {
#ifdef __SOLARIS__
if (f->conf.auto_cache) {
pthread_mutex_lock(&f->lock);
update_stat(get_node(f, ino), &buf);
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
set_stat(f, ino, &buf);
fuse_reply_attr(req, &buf, f->conf.attr_timeout);
} else
@ -1447,29 +1187,6 @@ static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
else
err = fuse_fs_truncate(f->fs, path, attr->st_size);
}
#ifdef HAVE_UTIMENSAT
if (!err &&
(valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) {
struct timespec tv[2];
tv[0].tv_sec = 0;
tv[1].tv_sec = 0;
tv[0].tv_nsec = UTIME_OMIT;
tv[1].tv_nsec = UTIME_OMIT;
if (valid & FUSE_SET_ATTR_ATIME_NOW)
tv[0].tv_nsec = UTIME_NOW;
else if (valid & FUSE_SET_ATTR_ATIME)
tv[0] = attr->st_atim;
if (valid & FUSE_SET_ATTR_MTIME_NOW)
tv[1].tv_nsec = UTIME_NOW;
else if (valid & FUSE_SET_ATTR_MTIME)
tv[1] = attr->st_mtim;
err = fuse_fs_utimens(f->fs, path, tv);
} else
#endif
if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
(FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
struct timespec tv[2];
@ -1486,13 +1203,6 @@ static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
}
pthread_rwlock_unlock(&f->tree_lock);
if (!err) {
#ifdef __SOLARIS__
if (f->conf.auto_cache) {
pthread_mutex_lock(&f->lock);
update_stat(get_node(f, ino), &buf);
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
set_stat(f, ino, &buf);
fuse_reply_attr(req, &buf, f->conf.attr_timeout);
} else
@ -1837,47 +1547,6 @@ static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
pthread_rwlock_unlock(&f->tree_lock);
}
#ifdef __SOLARIS__
static double diff_timespec(const struct timespec *t1,
const struct timespec *t2)
{
return (t1->tv_sec - t2->tv_sec) +
((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
}
static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
struct fuse_file_info *fi)
{
struct node *node;
pthread_mutex_lock(&f->lock);
node = get_node(f, ino);
if (node->cache_valid) {
struct timespec now;
curr_time(&now);
if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
struct stat stbuf;
int err;
pthread_mutex_unlock(&f->lock);
err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
pthread_mutex_lock(&f->lock);
if (!err)
update_stat(node, &stbuf);
else
node->cache_valid = 0;
}
}
if (node->cache_valid)
fi->keep_cache = 1;
node->cache_valid = 1;
pthread_mutex_unlock(&f->lock);
}
#endif /* __SOLARIS__ */
static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
struct fuse_file_info *fi)
{
@ -1897,11 +1566,6 @@ static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
fi->direct_io = 1;
if (f->conf.kernel_cache)
fi->keep_cache = 1;
#ifdef __SOLARIS__
if (f->conf.auto_cache)
open_auto_cache(f, ino, path, fi);
#endif /* __SOLARIS__ */
}
fuse_finish_interrupt(f, req, &d);
}
@ -2101,17 +1765,12 @@ static int extend_contents(struct fuse_dh *dh, unsigned minsize)
unsigned newsize = dh->size;
if (!newsize)
newsize = 1024;
#ifndef __SOLARIS__
while (newsize < minsize) {
if (newsize >= 0x80000000)
newsize = 0xffffffff;
else
newsize *= 2;
}
#else /* __SOLARIS__ */
while (newsize < minsize)
newsize *= 2;
#endif /* __SOLARIS__ */
newptr = (char *) realloc(dh->contents, newsize);
if (!newptr) {
@ -2223,7 +1882,7 @@ static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
}
}
if (dh->filled) {
if ((off >= 0) && (off < dh->len)) {
if (off < dh->len) {
if (off + size > dh->len)
size = dh->len - off;
} else
@ -2735,62 +2394,6 @@ static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
reply_err(req, err);
}
static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
struct fuse_file_info *llfi, unsigned int flags,
const void *in_buf, size_t in_bufsz,
size_t out_bufsz)
{
struct fuse *f = req_fuse_prepare(req);
struct fuse_intr_data d;
struct fuse_file_info fi;
char *path, *out_buf = NULL;
int err;
err = -EPERM;
if (flags & FUSE_IOCTL_UNRESTRICTED)
goto err;
if (flags & FUSE_IOCTL_DIR)
get_dirhandle(llfi, &fi);
else
fi = *llfi;
if (out_bufsz) {
err = -ENOMEM;
out_buf = malloc(out_bufsz);
if (!out_buf)
goto err;
}
assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
if (out_buf)
memcpy(out_buf, in_buf, in_bufsz);
path = get_path(f, ino); /* Should be get_path_nullok() */
if (!path) {
err = ENOENT;
goto err;
}
fuse_prepare_interrupt(f, req, &d);
/* Note : const qualifier dropped */
err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags,
out_buf ? (void*)out_buf : (void*)(uintptr_t)in_buf);
fuse_finish_interrupt(f, req, &d);
free(path);
if (err >= 0) { /* not an error */
fuse_reply_ioctl(req, err, out_buf, out_bufsz);
goto out;
}
err:
reply_err(req, err);
out:
free(out_buf);
}
static struct fuse_lowlevel_ops fuse_path_ops = {
.init = fuse_lib_init,
.destroy = fuse_lib_destroy,
@ -2826,7 +2429,6 @@ static struct fuse_lowlevel_ops fuse_path_ops = {
.getlk = fuse_lib_getlk,
.setlk = fuse_lib_setlk,
.bmap = fuse_lib_bmap,
.ioctl = fuse_lib_ioctl,
};
struct fuse_session *fuse_get_session(struct fuse *f)
@ -2875,10 +2477,6 @@ static const struct fuse_opt fuse_lib_opts[] = {
FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
FUSE_LIB_OPT("direct_io", direct_io, 1),
FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
#ifdef __SOLARIS__
FUSE_LIB_OPT("auto_cache", auto_cache, 1),
FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
#endif /* __SOLARIS__ */
FUSE_LIB_OPT("umask=", set_mode, 1),
FUSE_LIB_OPT("umask=%o", umask, 0),
FUSE_LIB_OPT("uid=", set_uid, 1),
@ -2892,9 +2490,6 @@ static const struct fuse_opt fuse_lib_opts[] = {
FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
FUSE_LIB_OPT("intr", intr, 1),
FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
#ifdef __SOLARIS__
FUSE_LIB_OPT("modules=%s", modules, 0),
#endif /* __SOLARIS__ */
FUSE_OPT_END
};
@ -2906,9 +2501,6 @@ static void fuse_lib_help(void)
" -o readdir_ino try to fill in d_ino in readdir\n"
" -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 (off)\n"
#endif /* __SOLARIS__ */
" -o umask=M set file permissions (octal)\n"
" -o uid=N set file owner\n"
" -o gid=N set file group\n"
@ -2918,42 +2510,9 @@ static void fuse_lib_help(void)
" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
" -o intr allow requests to be interrupted\n"
" -o intr_signal=NUM signal to send on interrupt (%i)\n"
#ifdef __SOLARIS__
" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"
#endif /* __SOLARIS__ */
"\n", FUSE_DEFAULT_INTR_SIGNAL);
}
#ifdef __SOLARIS__
static void fuse_lib_help_modules(void)
{
struct fuse_module *m;
fprintf(stderr, "\nModule options:\n");
pthread_mutex_lock(&fuse_context_lock);
for (m = fuse_modules; m; m = m->next) {
struct fuse_fs *fs = NULL;
struct fuse_fs *newfs;
struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
if (fuse_opt_add_arg(&args, "") != -1 &&
fuse_opt_add_arg(&args, "-h") != -1) {
fprintf(stderr, "\n[%s]\n", m->name);
newfs = m->factory(&args, &fs);
assert(newfs == NULL);
}
fuse_opt_free_args(&args);
}
pthread_mutex_unlock(&fuse_context_lock);
}
int fuse_is_lib_option(const char *opt)
{
return fuse_lowlevel_is_lib_option(opt) ||
fuse_opt_match(fuse_lib_opts, opt);
}
#endif /* __SOLARIS__ */
static int fuse_lib_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
@ -3002,32 +2561,6 @@ static void fuse_restore_intr_signal(int signum)
sigaction(signum, &sa, NULL);
}
#ifdef __SOLARIS__
static int fuse_push_module(struct fuse *f, const char *module,
struct fuse_args *args)
{
struct fuse_fs *newfs;
struct fuse_module *m = fuse_get_module(module);
struct fuse_fs *fs[2];
fs[0] = f->fs;
fs[1] = NULL;
if (!m)
return -1;
newfs = m->factory(args, fs);
if (!newfs) {
fuse_put_module(m);
return -1;
}
newfs->m = m;
f->fs = newfs;
return 0;
}
#endif /* __SOLARIS__ */
struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
void *user_data)
{
@ -3088,26 +2621,10 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
goto out_free_fs;
#ifdef __SOLARIS__
if (f->conf.modules) {
char *module;
char *next;
for (module = f->conf.modules; module; module = next) {
char *p;
for (p = module; *p && *p != ':'; p++);
next = *p ? p + 1 : NULL;
*p = '\0';
if (module[0] && fuse_push_module(f, module, args) == -1)
goto out_free_fs;
}
}
#endif /* __SOLARIS__ */
if (!f->conf.ac_attr_timeout_set)
f->conf.ac_attr_timeout = f->conf.attr_timeout;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#ifdef __FreeBSD__
/*
* In FreeBSD, we always use these settings as inode numbers are needed to
* make getcwd(3) work.
@ -3116,12 +2633,7 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
#endif
f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f);
if (f->se == NULL) {
#ifdef __SOLARIS__
if (f->conf.help)
fuse_lib_help_modules();
#endif /* __SOLARIS__ */
goto out_free_fs;
}
@ -3189,9 +2701,6 @@ struct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
called on the filesystem without init being called first */
fs->op.destroy = NULL;
fuse_fs_destroy(f->fs);
#ifdef __SOLARIS__
free(f->conf.modules);
#endif /* __SOLARIS__ */
out_free:
free(f);
out_delete_context_key:
@ -3241,9 +2750,7 @@ void fuse_destroy(struct fuse *f)
pthread_mutex_destroy(&f->lock);
pthread_rwlock_destroy(&f->tree_lock);
fuse_session_destroy(f->se);
#ifdef __SOLARIS__
free(f->conf.modules);
#endif /* __SOLARIS__ */
free(f);
fuse_delete_context_key();
}

View File

@ -22,16 +22,6 @@
#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
@ -79,13 +69,7 @@ static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
attr->nlink = stbuf->st_nlink;
attr->uid = stbuf->st_uid;
attr->gid = stbuf->st_gid;
#if defined(__SOLARIS__) && defined(_LP64)
/* Must pack the device the old way (attr->rdev limited to 32 bits) */
attr->rdev = ((major(stbuf->st_rdev) & 0x3fff) << 18)
| (minor(stbuf->st_rdev) & 0x3ffff);
#else
attr->rdev = stbuf->st_rdev;
#endif
attr->size = stbuf->st_size;
attr->blocks = stbuf->st_blocks;
attr->atime = stbuf->st_atime;
@ -201,15 +185,13 @@ static int send_reply(fuse_req_t req, int error, const void *arg,
struct iovec iov[2];
int count = 1;
if (argsize) {
/* Note : const qualifier dropped */
iov[1].iov_base = (void *)(uintptr_t) arg;
iov[1].iov_base = (void *) arg;
iov[1].iov_len = argsize;
count++;
}
return send_reply_iov(req, error, iov, count);
}
#if 0 /* not used */
int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
{
int res;
@ -227,7 +209,6 @@ int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
return res;
}
#endif
size_t fuse_dirent_size(size_t namelen)
{
@ -247,7 +228,7 @@ char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
dirent->off = off;
dirent->namelen = namelen;
dirent->type = (stbuf->st_mode & 0170000) >> 12;
memcpy(dirent->name, name, namelen);
strncpy(dirent->name, name, namelen);
if (padlen)
memset(buf + entlen, 0, padlen);
@ -350,8 +331,12 @@ int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
memset(&arg, 0, sizeof(arg));
fill_entry(&arg, e);
#ifdef POSIXACLS
return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
? sizeof(arg) : FUSE_COMPAT_ENTRY_OUT_SIZE));
#else
return send_reply_ok(req, &arg, sizeof(arg));
#endif
}
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
@ -364,6 +349,7 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
memset(&arg, 0, sizeof(arg));
fill_entry(&arg.e, e);
#ifdef POSIXACLS
if (req->f->conn.proto_minor < 12) {
fill_open((struct fuse_open_out*)
((char*)&arg + FUSE_COMPAT_ENTRY_OUT_SIZE), f);
@ -373,6 +359,10 @@ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
fill_open(&arg.o, f);
return send_reply_ok(req, &arg, sizeof(arg));
}
#else
fill_open(&arg.o, f);
return send_reply_ok(req, &arg, sizeof(arg));
#endif
}
int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
@ -385,8 +375,12 @@ int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
convert_stat(attr, &arg.attr);
#ifdef POSIXACLS
return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
? sizeof(arg) : FUSE_COMPAT_FUSE_ATTR_OUT_SIZE));
#else
return send_reply_ok(req, &arg, sizeof(arg));
#endif
}
int fuse_reply_readlink(fuse_req_t req, const char *linkname)
@ -466,28 +460,6 @@ int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
return send_reply_ok(req, &arg, sizeof(arg));
}
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
{
struct fuse_ioctl_out arg;
struct iovec iov[3];
size_t count = 1;
memset(&arg, 0, sizeof(arg));
arg.result = result;
iov[count].iov_base = &arg;
iov[count].iov_len = sizeof(arg);
count++;
if (size) {
/* Note : const qualifier dropped */
iov[count].iov_base = (char *)(uintptr_t) buf;
iov[count].iov_len = size;
count++;
}
return send_reply_iov(req, 0, iov, count);
}
static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
const char *name = (const char *) inarg;
@ -564,24 +536,16 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
const struct fuse_mknod_in *arg = (const struct fuse_mknod_in *) inarg;
const char *name = PARAM(arg);
#ifdef POSIXACLS
if (req->f->conn.proto_minor >= 12)
req->ctx.umask = arg->umask;
else
#endif
name = (const char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
if (req->f->op.mknod) {
#if defined(__SOLARIS__) && defined(_LP64)
/*
* 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) & 0x3fff,
arg->rdev & 0x3ffff));
#else
req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
#endif
} else
if (req->f->op.mknod)
req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
else
fuse_reply_err(req, ENOSYS);
}
@ -589,8 +553,10 @@ static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
const struct fuse_mkdir_in *arg = (const struct fuse_mkdir_in *) inarg;
#ifdef POSIXACLS
if (req->f->conn.proto_minor >= 12)
req->ctx.umask = arg->umask;
#endif
if (req->f->op.mkdir)
req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
@ -653,7 +619,7 @@ static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
const struct fuse_create_in *arg = (const struct fuse_create_in *) inarg;
const struct fuse_create_in *arg = (const struct fuse_create_in *) inarg;
if (req->f->op.create) {
struct fuse_file_info fi;
@ -662,9 +628,11 @@ static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
memset(&fi, 0, sizeof(fi));
fi.flags = arg->flags;
#ifdef POSIXACLS
if (req->f->conn.proto_minor >= 12)
req->ctx.umask = arg->umask;
else
#endif
name = (const char *) inarg + sizeof(struct fuse_open_in);
req->f->op.create(req, nodeid, name, arg->mode, &fi);
@ -712,6 +680,7 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
fi.writepage = arg->write_flags & 1;
if (req->f->op.write) {
#ifdef POSIXACLS
const char *buf;
if (req->f->conn.proto_minor >= 12)
@ -719,6 +688,9 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
else
buf = ((const char*)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
req->f->op.write(req, nodeid, buf, arg->size, arg->offset, &fi);
#else
req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
#endif
} else
fuse_reply_err(req, ENOSYS);
}
@ -1037,39 +1009,6 @@ static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
fuse_reply_err(req, ENOSYS);
}
static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
const struct fuse_ioctl_in *arg = (const struct fuse_ioctl_in *) inarg;
unsigned int flags = arg->flags;
const void *in_buf = arg->in_size ? PARAM(arg) : NULL;
struct fuse_file_info fi;
if (flags & FUSE_IOCTL_DIR &&
!(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) {
fuse_reply_err(req, ENOTTY);
return;
}
memset(&fi, 0, sizeof(fi));
fi.fh = arg->fh;
/* TODO JPA (need req->ioctl_64bit in obscure fuse_req_t)
// probably a 64 bit ioctl on a 32-bit cpu
// this is to forward a request from the kernel
if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 &&
!(flags & FUSE_IOCTL_32BIT)) {
req->ioctl_64bit = 1;
}
*/
if (req->f->op.ioctl)
req->f->op.ioctl(req, nodeid, arg->cmd,
(void *)(uintptr_t)arg->arg, &fi, flags,
in_buf, arg->in_size, arg->out_size);
else
fuse_reply_err(req, ENOSYS);
}
static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
{
const struct fuse_init_in *arg = (const struct fuse_init_in *) inarg;
@ -1103,13 +1042,7 @@ 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;
if (arg->flags & FUSE_HAS_IOCTL_DIR)
f->conn.capable |= FUSE_CAP_IOCTL_DIR;
} else {
f->conn.async_read = 0;
f->conn.max_readahead = 0;
@ -1132,46 +1065,28 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
memset(&outarg, 0, sizeof(outarg));
outarg.major = FUSE_KERNEL_VERSION;
/*
* Suggest using protocol 7.18 when available, and fallback
* to 7.12 or even earlier when running on an old kernel.
* Protocol 7.12 has the ability to process the umask
* conditionnally (as needed if POSIXACLS is set)
* Protocol 7.18 has the ability to process the ioctls
* if POSIXACLS is not set, protocol 7.8 provides a good
* compatibility with older kernel modules.
* if POSIXACLS is set, we try to use protocol 7.12 supposed
* to have the ability to process the umask conditionnally,
* but, when using an older kernel module, we fallback to 7.8
*/
if (arg->major > 7 || (arg->major == 7 && arg->minor >= 18)) {
#ifdef POSIXACLS
if (arg->major > 7 || (arg->major == 7 && arg->minor >= 12))
outarg.minor = FUSE_KERNEL_MINOR_VERSION;
if (f->conn.want & FUSE_CAP_IOCTL_DIR)
outarg.flags |= FUSE_HAS_IOCTL_DIR;
#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 */
if ((arg->major < FUSE_KERNEL_MAJOR_FALLBACK)
|| ((arg->major == FUSE_KERNEL_MAJOR_FALLBACK)
&& (arg->minor < FUSE_KERNEL_MINOR_FALLBACK))) {
outarg.major = arg->major;
outarg.minor = arg->minor;
} else {
outarg.major = FUSE_KERNEL_MAJOR_FALLBACK;
else
outarg.minor = FUSE_KERNEL_MINOR_FALLBACK;
#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;
#else
outarg.minor = FUSE_KERNEL_MINOR_VERSION;
#endif
}
}
if (f->conn.async_read)
outarg.flags |= FUSE_ASYNC_READ;
if (f->op.getlk && f->op.setlk)
outarg.flags |= FUSE_POSIX_LOCKS;
if (f->conn.want & FUSE_CAP_BIG_WRITES)
outarg.flags |= FUSE_BIG_WRITES;
#ifdef POSIXACLS
if (f->conn.want & FUSE_CAP_DONT_MASK)
outarg.flags |= FUSE_DONT_MASK;
#endif
outarg.max_readahead = f->conn.max_readahead;
outarg.max_write = f->conn.max_write;
@ -1209,6 +1124,18 @@ const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
return &req->ctx;
}
/*
* The size of fuse_ctx got extended, so need to be careful about
* incompatibility (i.e. a new binary cannot work with an old
* library).
*/
const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req);
const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req)
{
return fuse_req_ctx(req);
}
//FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4");
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
void *data)
{
@ -1270,7 +1197,6 @@ static struct {
[FUSE_CREATE] = { do_create, "CREATE" },
[FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
[FUSE_BMAP] = { do_bmap, "BMAP" },
[FUSE_IOCTL] = { do_ioctl, "IOCTL" },
[FUSE_DESTROY] = { do_destroy, "DESTROY" },
};
@ -1395,15 +1321,6 @@ static int fuse_ll_opt_proc(void *data, const char *arg, int key,
return -1;
}
#ifdef __SOLARIS__
int fuse_lowlevel_is_lib_option(const char *opt)
{
return fuse_opt_match(fuse_ll_opts, opt);
}
#endif /* __SOLARIS__ */
static void fuse_ll_destroy(void *data)
{
struct fuse_ll *f = (struct fuse_ll *) data;
@ -1464,3 +1381,4 @@ struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
out:
return NULL;
}

View File

@ -36,12 +36,6 @@ static inline void fuse_mutex_init(pthread_mutex_t *mut)
#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimensec)
#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimensec)
#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimensec)
#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimensec = (val)
#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimensec = (val)
#else
#define ST_ATIM_NSEC(stbuf) 0
#define ST_CTIM_NSEC(stbuf) 0

View File

@ -264,23 +264,9 @@ static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
do {
int res;
#ifdef __SOLARIS__
/*
* On Solaris, the device name contains commas, so the
* option "fsname" has to be the last one and its commas
* should not be interpreted as option separators.
* This had to be hardcoded because the option "fsname"
* may be found though not present in option list.
*/
if (!strncmp(opts,"fsname=",7))
sep = (char*)NULL;
else
#endif /* __SOLARIS__ */
{
sep = strchr(opts, ',');
if (sep)
*sep = '\0';
}
sep = strchr(opts, ',');
if (sep)
*sep = '\0';
res = process_gopt(ctx, opts, 1);
if (res == -1)
return -1;

View File

@ -165,20 +165,9 @@ struct fuse_session *fuse_chan_session(struct fuse_chan *ch)
int fuse_chan_recv(struct fuse_chan **chp, char *buf, size_t size)
{
struct fuse_chan *ch = *chp;
return ch->op.receive(chp, buf, size);
}
#ifdef __SOLARIS__
int fuse_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
{
int res;
res = fuse_chan_recv(&ch, buf, size);
return res >= 0 ? res : (res != -EINTR && res != -EAGAIN) ? -1 : 0;
}
#endif /* __SOLARIS__ */
int fuse_chan_send(struct fuse_chan *ch, const struct iovec iov[], size_t count)
{
return ch->op.send(ch, iov, count);
@ -191,3 +180,4 @@ void fuse_chan_destroy(struct fuse_chan *ch)
ch->op.destroy(ch);
free(ch);
}

View File

@ -22,13 +22,13 @@ static void exit_handler(int sig)
fuse_session_exit(fuse_instance);
}
static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
static int set_one_signal_handler(int sig, void (*handler)(int))
{
struct sigaction sa;
struct sigaction old_sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = remove ? SIG_DFL : handler;
sa.sa_handler = handler;
sigemptyset(&(sa.sa_mask));
sa.sa_flags = 0;
@ -37,7 +37,7 @@ static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
return -1;
}
if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
if (old_sa.sa_handler == SIG_DFL &&
sigaction(sig, &sa, NULL) == -1) {
perror("fuse: cannot set signal handler");
return -1;
@ -47,10 +47,10 @@ static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
int fuse_set_signal_handlers(struct fuse_session *se)
{
if (set_one_signal_handler(SIGHUP, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGINT, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler, 0) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN, 0) == -1)
if (set_one_signal_handler(SIGHUP, exit_handler) == -1 ||
set_one_signal_handler(SIGINT, exit_handler) == -1 ||
set_one_signal_handler(SIGTERM, exit_handler) == -1 ||
set_one_signal_handler(SIGPIPE, SIG_IGN) == -1)
return -1;
fuse_instance = se;
@ -65,9 +65,9 @@ void fuse_remove_signal_handlers(struct fuse_session *se)
else
fuse_instance = NULL;
set_one_signal_handler(SIGHUP, exit_handler, 1);
set_one_signal_handler(SIGINT, exit_handler, 1);
set_one_signal_handler(SIGTERM, exit_handler, 1);
set_one_signal_handler(SIGPIPE, SIG_IGN, 1);
set_one_signal_handler(SIGHUP, SIG_DFL);
set_one_signal_handler(SIGINT, SIG_DFL);
set_one_signal_handler(SIGTERM, SIG_DFL);
set_one_signal_handler(SIGPIPE, SIG_DFL);
}

View File

@ -19,21 +19,14 @@
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <paths.h>
#ifdef __SOLARIS__
#include <sys/mnttab.h>
#else /* __SOLARIS__ */
#include <grp.h>
#include <mntent.h>
#include <sys/fsuid.h>
#endif /* __SOLARIS__ */
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/fsuid.h>
#include <sys/socket.h>
#include <sys/utsname.h>
#include <grp.h>
#define FUSE_DEV_NEW "/dev/fuse"
@ -48,32 +41,6 @@ static int mount_max = 1000;
int drop_privs(void);
int restore_privs(void);
#ifdef __SOLARIS__
/*
* fusermount is not implemented in fuse-lite for Solaris,
* only the minimal functions are provided.
*/
/*
* Solaris doesn't have setfsuid/setfsgid.
* This doesn't really matter anyway as this program shouldn't be made
* suid on Solaris. It should instead be used via a profile with the
* sys_mount privilege.
*/
int drop_privs(void)
{
return (0);
}
int restore_privs(void)
{
return (0);
}
#else /* __SOLARIS__ */
static const char *get_user_name(void)
{
struct passwd *pw = getpwuid(getuid());
@ -445,7 +412,7 @@ static int do_mount(const char *mnt, char **typep, mode_t rootmode,
if (errno_save == EPERM)
fprintf(stderr, "User doesn't have privilege to mount. "
"For more information\nplease see: "
"http://tuxera.com/community/ntfs-3g-faq/#unprivileged\n");
"http://ntfs-3g.org/support.html#unprivileged\n");
}
goto err;
} else {
@ -621,8 +588,7 @@ static int mount_fuse(const char *mnt, const char *opts)
&source, &mnt_opts);
if (currdir_fd != -1) {
__attribute__((unused))int ignored_fchdir_status =
fchdir(currdir_fd);
fchdir(currdir_fd);
close(currdir_fd);
}
if (mountpoint_fd != -1)
@ -701,5 +667,3 @@ out:
free(mnt);
return res;
}
#endif /* __SOLARIS__ */

View File

@ -15,18 +15,6 @@ struct fuse_chan *fuse_mount(const char *mountpoint, struct fuse_args *args)
struct fuse_chan *ch;
int fd;
#ifdef __SOLARIS__
/*
* Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
* would ensue.
*/
do {
fd = open("/dev/null", O_RDWR);
if (fd > 2)
close(fd);
} while (fd >= 0 && fd <= 2);
#endif /* __SOLARIS__ */
fd = fuse_kern_mount(mountpoint, args);
if (fd == -1)
return NULL;
@ -50,12 +38,3 @@ int fuse_version(void)
return FUSE_VERSION;
}
#ifdef __SOLARIS__
#undef fuse_main
int fuse_main(void);
int fuse_main(void)
{
fprintf(stderr, "fuse_main(): This function does not exist\n");
return -1;
}
#endif /* __SOLARIS__ */

View File

@ -12,7 +12,6 @@
#include "mount_util.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
@ -24,21 +23,6 @@
#include <sys/wait.h>
#include <sys/mount.h>
#ifdef __SOLARIS__
#define FUSERMOUNT_PROG "fusermount"
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
#ifndef FUSERMOUNT_DIR
#define FUSERMOUNT_DIR "/usr"
#endif /* FUSERMOUNT_DIR */
#ifndef HAVE_FORK
#define fork() vfork()
#endif
#endif /* __SOLARIS__ */
#ifndef MS_DIRSYNC
#define MS_DIRSYNC 128
#endif
@ -60,16 +44,8 @@ struct mount_opts {
int allow_root;
int ishelp;
int flags;
#ifdef __SOLARIS__
int nonempty;
int blkdev;
char *fsname;
char *subtype;
char *subtype_opt;
#else
int blkdev;
char *fsname;
#endif
char *mtab_opts;
char *fusermount_opts;
char *kernel_opts;
@ -78,42 +54,6 @@ struct mount_opts {
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
static const struct fuse_opt fuse_mount_opts[] = {
#ifdef __SOLARIS__
FUSE_MOUNT_OPT("allow_other", allow_other),
FUSE_MOUNT_OPT("allow_root", allow_root),
FUSE_MOUNT_OPT("nonempty", nonempty),
FUSE_MOUNT_OPT("blkdev", blkdev),
FUSE_MOUNT_OPT("fsname=%s", fsname),
FUSE_MOUNT_OPT("subtype=%s", subtype),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
FUSE_OPT_KEY("-r", KEY_RO),
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
FUSE_OPT_KEY("-g", KEY_KERN_FLAG),
FUSE_OPT_KEY("-m", KEY_KERN_FLAG),
FUSE_OPT_KEY("-O", KEY_KERN_FLAG),
FUSE_OPT_KEY("setuid", KEY_KERN_OPT),
FUSE_OPT_KEY("nosetuid", KEY_KERN_OPT),
FUSE_OPT_KEY("devices", KEY_KERN_OPT),
FUSE_OPT_KEY("nodevices", KEY_KERN_OPT),
FUSE_OPT_KEY("exec", KEY_KERN_OPT),
FUSE_OPT_KEY("noexec", KEY_KERN_OPT),
FUSE_OPT_KEY("nbmand", KEY_KERN_OPT),
FUSE_OPT_KEY("nonbmand", KEY_KERN_OPT),
#else /* __SOLARIS__ */
FUSE_MOUNT_OPT("allow_other", allow_other),
FUSE_MOUNT_OPT("allow_root", allow_root),
FUSE_MOUNT_OPT("blkdev", blkdev),
@ -125,7 +65,6 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
FUSE_OPT_KEY("context=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
@ -143,7 +82,6 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
#endif /* __SOLARIS__ */
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
FUSE_OPT_KEY("-V", KEY_VERSION),
@ -151,42 +89,6 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_OPT_END
};
#ifdef __SOLARIS__
static void mount_help(void)
{
fprintf(stderr,
" -o allow_other allow access to other users\n"
" -o allow_root allow access to root\n"
" -o nonempty allow mounts over non-empty file/dir\n"
" -o default_permissions enable permission checking by kernel\n"
" -o fsname=NAME set filesystem name\n"
" -o subtype=NAME set filesystem type\n"
" -o large_read issue large read requests (2.4 only)\n"
" -o max_read=N set maximum size of read requests\n"
"\n"
);
}
static void exec_fusermount(const char *argv[])
{
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
execvp(FUSERMOUNT_PROG, (char **) argv);
}
static void mount_version(void)
{
int pid = fork();
if (!pid) {
const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL };
exec_fusermount(argv);
_exit(1);
} else if (pid != -1)
waitpid(pid, NULL, 0);
}
#endif /* __SOLARIS__ */
struct mount_flags {
const char *opt;
unsigned long flag;
@ -198,7 +100,6 @@ static struct mount_flags mount_flags[] = {
{"ro", MS_RDONLY, 1},
{"suid", MS_NOSUID, 0},
{"nosuid", MS_NOSUID, 1},
#ifndef __SOLARIS__
{"dev", MS_NODEV, 0},
{"nodev", MS_NODEV, 1},
{"exec", MS_NOEXEC, 0},
@ -208,42 +109,9 @@ static struct mount_flags mount_flags[] = {
{"atime", MS_NOATIME, 0},
{"noatime", MS_NOATIME, 1},
{"dirsync", MS_DIRSYNC, 1},
#else /* __SOLARIS__ */
{"-g", MS_GLOBAL, 1}, /* 1eaf4 */
{"-m", MS_NOMNTTAB, 1}, /* 1eb00 */
{"-O", MS_OVERLAY, 1}, /* 1eb0c */
#endif /* __SOLARIS__ */
{NULL, 0, 0}
};
#ifdef __SOLARIS__
/*
* See comments in fuse_kern_mount()
*/
struct solaris_mount_opts {
int nosuid;
int setuid;
int nosetuid;
int devices;
int nodevices;
};
#define SOLARIS_MOUNT_OPT(t, p, n) \
{ t, offsetof(struct solaris_mount_opts, p), n }
static const struct fuse_opt solaris_mnt_opts[] = {
SOLARIS_MOUNT_OPT("suid", setuid, 1),
SOLARIS_MOUNT_OPT("suid", devices, 1),
SOLARIS_MOUNT_OPT("nosuid", nosuid, 1),
SOLARIS_MOUNT_OPT("setuid", setuid, 1),
SOLARIS_MOUNT_OPT("nosetuid", nosetuid, 1),
SOLARIS_MOUNT_OPT("devices", devices, 1),
SOLARIS_MOUNT_OPT("nodevices", nodevices, 1),
FUSE_OPT_END
};
#endif /* __SOLARIS__ */
static void set_mount_flag(const char *s, int *flags)
{
int i;
@ -287,85 +155,23 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key,
case KEY_FUSERMOUNT_OPT:
return fuse_opt_add_opt(&mo->fusermount_opts, arg);
#ifdef __SOLARIS__
case KEY_SUBTYPE_OPT:
return fuse_opt_add_opt(&mo->subtype_opt, arg);
#endif /* __SOLARIS__ */
case KEY_MTAB_OPT:
return fuse_opt_add_opt(&mo->mtab_opts, arg);
case KEY_HELP:
#ifdef __SOLARIS__
mount_help();
#endif /* __SOLARIS__ */
mo->ishelp = 1;
break;
case KEY_VERSION:
#ifdef __SOLARIS__
mount_version();
#endif /* __SOLARIS__ */
mo->ishelp = 1;
break;
}
return 1;
}
#ifdef __SOLARIS__
/* return value:
* >= 0 => fd
* -1 => error
*/
static int receive_fd(int fd)
{
struct msghdr msg;
struct iovec iov;
char buf[1];
int rv;
size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
struct cmsghdr *cmsg;
iov.iov_base = buf;
iov.iov_len = 1;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
/* old BSD implementations should use msg_accrights instead of
* msg_control; the interface is different. */
msg.msg_control = ccmsg;
msg.msg_controllen = sizeof(ccmsg);
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
if (rv == -1) {
perror("recvmsg");
return -1;
}
if(!rv) {
/* EOF */
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
if (cmsg->cmsg_type != SCM_RIGHTS) {
fprintf(stderr, "got control message of unknown type %d\n",
cmsg->cmsg_type);
return -1;
}
return *(int*)CMSG_DATA(cmsg);
}
#endif /* __SOLARIS__ */
void fuse_kern_unmount(const char *mountpoint, int fd)
{
int res;
#ifdef __SOLARIS__
int pid;
#endif /* __SOLARIS__ */
if (!mountpoint)
return;
@ -380,217 +186,11 @@ 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__
fusermount(1, 0, 1, "", mountpoint);
#else /* __SOLARIS__ */
if (geteuid() == 0) {
fuse_mnt_umount("fuse", mountpoint, 1);
return;
}
res = umount2(mountpoint, 2);
if (res == 0)
return;
pid = fork();
if(pid == -1)
return;
if(pid == 0) {
const char *argv[] =
{ FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL };
exec_fusermount(argv);
_exit(1);
}
waitpid(pid, NULL, 0);
#endif /* __SOLARIS__ */
}
#ifdef __SOLARIS__
static int fuse_mount_fusermount(const char *mountpoint, const char *opts,
int quiet)
{
int fds[2], pid;
int res;
int rv;
if (!mountpoint) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
if(res == -1) {
perror("fuse: socketpair() failed");
return -1;
}
pid = fork();
if(pid == -1) {
perror("fuse: fork() failed");
close(fds[0]);
close(fds[1]);
return -1;
}
if(pid == 0) {
char env[10];
const char *argv[32];
int a = 0;
if (quiet) {
int fd = open("/dev/null", O_RDONLY);
dup2(fd, 1);
dup2(fd, 2);
}
argv[a++] = FUSERMOUNT_PROG;
if (opts) {
argv[a++] = "-o";
argv[a++] = opts;
}
argv[a++] = "--";
argv[a++] = mountpoint;
argv[a++] = NULL;
close(fds[1]);
fcntl(fds[0], F_SETFD, 0);
snprintf(env, sizeof(env), "%i", fds[0]);
setenv(FUSE_COMMFD_ENV, env, 1);
exec_fusermount(argv);
perror("fuse: failed to exec fusermount");
_exit(1);
}
close(fds[0]);
rv = receive_fd(fds[1]);
close(fds[1]);
waitpid(pid, NULL, 0); /* bury zombie */
return rv;
}
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
const char *mnt_opts)
{
char tmp[128];
const char *devname = "/dev/fuse";
char *source = NULL;
char *type = NULL;
struct stat stbuf;
int fd;
int res;
if (!mnt) {
fprintf(stderr, "fuse: missing mountpoint\n");
return -1;
}
res = lstat(mnt, &stbuf);
if (res == -1) {
fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
mnt, strerror(errno));
return -1;
}
if (!mo->nonempty) {
res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size);
if (res == -1)
return -1;
}
fd = open(devname, O_RDWR);
if (fd == -1) {
if (errno == ENODEV || errno == ENOENT)
fprintf(stderr,
"fuse: device not found, try 'modprobe fuse' first\n");
else
fprintf(stderr, "fuse: failed to open %s: %s\n", devname,
strerror(errno));
return -1;
}
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
stbuf.st_mode & S_IFMT, getuid(), getgid());
res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
if (res == -1)
goto out_close;
source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
(mo->subtype ? strlen(mo->subtype) : 0) +
strlen(devname) + 32);
type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
if (!type || !source) {
fprintf(stderr, "fuse: failed to allocate memory\n");
goto out_close;
}
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->subtype) {
strcat(type, ".");
strcat(type, mo->subtype);
}
strcpy(source,
mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
/* JPA added two final zeroes */
res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0,
mo->kernel_opts, MAX_MNTOPT_STR, 0, 0);
if (res == -1 && errno == EINVAL && mo->subtype) {
/* Probably missing subtype support */
strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
if (mo->fsname) {
if (!mo->blkdev)
sprintf(source, "%s#%s", mo->subtype, mo->fsname);
} else {
strcpy(source, type);
}
/* JPA two null args added */
res = mount(source, mnt, MS_OPTIONSTR|mo->flags, type, NULL, 0,
mo->kernel_opts, MAX_MNTOPT_STR, 0, 0);
}
if (res == -1) {
/*
* Maybe kernel doesn't support unprivileged mounts, in this
* case try falling back to fusermount
*/
if (errno == EPERM) {
res = -2;
} else {
int errno_save = errno;
if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
fprintf(stderr, "fuse: 'fuseblk' support missing\n");
else
fprintf(stderr, "fuse: mount failed: %s\n",
strerror(errno_save));
}
goto out_close;
}
return fd;
out_umount:
umount2(mnt, 2); /* lazy umount */
out_close:
free(type);
free(source);
close(fd);
return res;
}
#endif /* __SOLARIS__ */
fusermount(1, 0, 1, "", mountpoint);
}
static int get_mnt_flag_opts(char **mnt_optsp, int flags)
{
@ -601,8 +201,8 @@ static int get_mnt_flag_opts(char **mnt_optsp, int flags)
for (i = 0; mount_flags[i].opt != NULL; i++) {
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
return -1;
fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
return -1;
}
return 0;
}
@ -612,71 +212,26 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
struct mount_opts mo;
int res = -1;
char *mnt_opts = NULL;
#ifdef __SOLARIS__
struct solaris_mount_opts smo;
struct fuse_args sa = FUSE_ARGS_INIT(0, NULL);
#endif /* __SOLARIS__ */
memset(&mo, 0, sizeof(mo));
#ifndef __SOLARIS__
if (getuid())
mo.flags = MS_NOSUID | MS_NODEV;
#else /* __SOLARIS__ */
mo.flags = 0;
memset(&smo, 0, sizeof(smo));
if (args != NULL) {
while (args->argv[sa.argc] != NULL)
fuse_opt_add_arg(&sa, args->argv[sa.argc]);
}
#endif /* __SOLARIS__ */
if (args &&
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
#ifndef __SOLARIS__
return -1;
#else /* __SOLARIS__ */
goto out; /* if SOLARIS, clean up 'sa' */
/*
* In Solaris, nosuid is equivalent to nosetuid + nodevices. We only
* have MS_NOSUID for mount flags (no MS_(NO)SETUID, etc.). But if
* we set that as a default, it restricts specifying just nosetuid
* or nodevices; there is no way for the user to specify setuid +
* nodevices or vice-verse. So we parse the existing options, then
* add restrictive defaults if needed.
*/
if (fuse_opt_parse(&sa, &smo, solaris_mnt_opts, NULL) == -1)
goto out;
if (smo.nosuid || (!smo.nodevices && !smo.devices
&& !smo.nosetuid && !smo.setuid)) {
mo.flags |= MS_NOSUID;
} else {
/*
* Defaults; if neither nodevices|devices,nosetuid|setuid has
* been specified, add the default negative option string. If
* both have been specified (i.e., -osuid,nosuid), leave them
* alone; the last option will have precedence.
*/
if (!smo.nodevices && !smo.devices)
if (fuse_opt_add_opt(&mo.kernel_opts, "nodevices") == -1)
goto out;
if (!smo.nosetuid && !smo.setuid)
if (fuse_opt_add_opt(&mo.kernel_opts, "nosetuid") == -1)
goto out;
}
#endif /* __SOLARIS__ */
if (mo.allow_other && mo.allow_root) {
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
goto out;
}
res = -1;
res = 0;
if (mo.ishelp)
goto out;
res = -1;
if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
goto out;
#ifndef __SOLARIS__
if (!(mo.flags & MS_NODEV) && fuse_opt_add_opt(&mnt_opts, "dev") == -1)
goto out;
if (!(mo.flags & MS_NOSUID) && fuse_opt_add_opt(&mnt_opts, "suid") == -1)
@ -687,48 +242,15 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
goto out;
if (mo.fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) < 0)
goto out;
res = fusermount(0, 0, 0, mnt_opts ? mnt_opts : "", mountpoint);
#else /* __SOLARIS__ */
if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
goto out;
if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
goto out;
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
if (res == -2) {
if (mo.fusermount_opts &&
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
goto out;
if (mo.subtype) {
char *tmp_opts = NULL;
res = -1;
if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
free(tmp_opts);
goto out;
}
res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
free(tmp_opts);
if (res == -1)
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
} else {
res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
}
}
#endif /* __SOLARIS__ */
out:
free(mnt_opts);
#ifdef __SOLARIS__
fuse_opt_free_args(&sa);
free(mo.subtype);
free(mo.subtype_opt);
#endif /* __SOLARIS__ */
free(mo.fsname);
free(mo.fusermount_opts);
free(mo.kernel_opts);
free(mo.mtab_opts);
return res;
}

View File

@ -15,254 +15,11 @@
#include <dirent.h>
#include <errno.h>
#include <limits.h>
#include <paths.h>
#include <mntent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#ifdef __SOLARIS__
#else /* __SOLARIS__ */
#include <mntent.h>
#include <sys/mount.h>
#include <sys/param.h>
#endif /* __SOLARIS__ */
#ifdef __SOLARIS__
char *mkdtemp(char *template);
#ifndef _PATH_MOUNTED
#define _PATH_MOUNTED "/etc/mnttab"
#endif /* _PATH_MOUNTED */
#ifndef IGNORE_MTAB
static int mtab_needs_update(const char *mnt)
{
struct stat stbuf;
/* If mtab is within new mount, don't touch it */
if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
_PATH_MOUNTED[strlen(mnt)] == '/')
return 0;
if (lstat(_PATH_MOUNTED, &stbuf) != -1 && S_ISLNK(stbuf.st_mode))
return 0;
return 1;
}
#endif /* IGNORE_MTAB */
int fuse_mnt_add_mount(const char *progname, const char *fsname,
const char *mnt, const char *type, const char *opts)
{
int res;
int status;
#ifndef IGNORE_MTAB
if (!mtab_needs_update(mnt))
return 0;
#endif /* IGNORE_MTAB */
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
char *env = NULL;
char templ[] = "/tmp/fusermountXXXXXX";
char *tmp;
setuid(geteuid());
/*
* hide in a directory, where mount isn't able to resolve
* fsname as a valid path
*/
tmp = mkdtemp(templ);
if (!tmp) {
fprintf(stderr, "%s: failed to create temporary directory\n",
progname);
exit(1);
}
if (chdir(tmp)) {
fprintf(stderr, "%s: failed to chdir to %s: %s\n",
progname, tmp, strerror(errno));
exit(1);
}
rmdir(tmp);
execle("/sbin/mount", "/sbin/mount", "-F", type, "-o", opts,
fsname, mnt, NULL, &env);
fprintf(stderr, "%s: failed to execute /sbin/mount: %s\n", progname,
strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
return 0;
}
int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
{
int res;
int status;
#ifndef IGNORE_MTAB
if (!mtab_needs_update(mnt))
return 0;
#endif /* IGNORE_MTAB */
res = fork();
if (res == -1) {
fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
return -1;
}
if (res == 0) {
char *env = NULL;
setuid(geteuid());
if (lazy) {
execle("/sbin/umount", "/sbin/umount", mnt,
NULL, &env);
} else {
execle("/sbin/umount", "/sbin/umount", "-f", mnt,
NULL, &env);
}
fprintf(stderr, "%s: failed to execute /sbin/umount: %s\n", progname,
strerror(errno));
exit(1);
}
res = waitpid(res, &status, 0);
if (res == -1) {
fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
return -1;
}
if (status != 0)
return -1;
return 0;
}
char *fuse_mnt_resolve_path(const char *progname, const char *orig)
{
char buf[PATH_MAX];
char *copy;
char *dst;
char *end;
char *lastcomp;
const char *toresolv;
if (!orig[0]) {
fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
return NULL;
}
copy = strdup(orig);
if (copy == NULL) {
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return NULL;
}
toresolv = copy;
lastcomp = NULL;
for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
if (end[0] != '/') {
char *tmp;
end[1] = '\0';
tmp = strrchr(copy, '/');
if (tmp == NULL) {
lastcomp = copy;
toresolv = ".";
} else {
lastcomp = tmp + 1;
if (tmp == copy)
toresolv = "/";
}
if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
lastcomp = NULL;
toresolv = copy;
}
else if (tmp)
tmp[0] = '\0';
}
if (realpath(toresolv, buf) == NULL) {
fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
strerror(errno));
free(copy);
return NULL;
}
if (lastcomp == NULL)
dst = strdup(buf);
else {
dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
if (dst) {
unsigned buflen = strlen(buf);
if (buflen && buf[buflen-1] == '/')
sprintf(dst, "%s%s", buf, lastcomp);
else
sprintf(dst, "%s/%s", buf, lastcomp);
}
}
free(copy);
if (dst == NULL)
fprintf(stderr, "%s: failed to allocate memory\n", progname);
return dst;
}
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize)
{
int isempty = 1;
if (S_ISDIR(rootmode)) {
struct dirent *ent;
DIR *dp = opendir(mnt);
if (dp == NULL) {
fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n",
progname, strerror(errno));
return -1;
}
while ((ent = readdir(dp)) != NULL) {
if (strcmp(ent->d_name, ".") != 0 &&
strcmp(ent->d_name, "..") != 0) {
isempty = 0;
break;
}
}
closedir(dp);
} else if (rootsize)
isempty = 0;
if (!isempty) {
fprintf(stderr, "%s: mountpoint is not empty\n", progname);
fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
return -1;
}
return 0;
}
int fuse_mnt_check_fuseblk(void)
{
char buf[256];
FILE *f = fopen("/proc/filesystems", "r");
if (!f)
return 1;
while (fgets(buf, sizeof(buf), f))
if (strstr(buf, "fuseblk\n")) {
fclose(f);
return 1;
}
fclose(f);
return 0;
}
#else /* __SOLARIS__ */
static int mtab_needs_update(const char *mnt)
{
@ -311,13 +68,10 @@ int fuse_mnt_add_mount(const char *progname, const char *fsname,
return 0;
}
if (res == 0) {
char *env = NULL;
char templ[] = "/tmp/fusermountXXXXXX";
char *tmp;
if (setuid(geteuid()))
fprintf(stderr, "%s: failed to setuid : %s\n", progname,
strerror(errno));
setuid(geteuid());
/*
* hide in a directory, where mount isn't able to resolve
@ -335,8 +89,8 @@ int fuse_mnt_add_mount(const char *progname, const char *fsname,
exit(1);
}
rmdir(tmp);
execle("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
fsname, mnt, NULL, &env);
execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
fsname, mnt, NULL);
fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname,
strerror(errno));
exit(1);
@ -363,18 +117,9 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
return -1;
}
if (res == 0) {
char *env = NULL;
if (setuid(geteuid()))
fprintf(stderr, "%s: failed to setuid : %s\n", progname,
strerror(errno));
if (lazy) {
execle("/bin/umount", "/bin/umount", "-i", mnt, "-l",
NULL, &env);
} else {
execle("/bin/umount", "/bin/umount", "-i", mnt,
NULL, &env);
}
setuid(geteuid());
execl("/bin/umount", "/bin/umount", "-i", mnt, lazy ? "-l" : NULL,
NULL);
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n", progname,
strerror(errno));
exit(1);
@ -472,5 +217,3 @@ int fuse_mnt_check_fuseblk(void)
fclose(f);
return 0;
}
#endif /* __SOLARIS__ */

View File

@ -14,14 +14,6 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy);
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
int fuse_mnt_check_fuseblk(void);
#ifdef __SOLARIS__
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize);
#else /* __SOLARIS__ */
int fusermount(int unmount, int quiet, int lazy, const char *opts,
const char *origmnt);
#endif /* __SOLARIS__ */

View File

@ -9,43 +9,40 @@ else
noinst_LTLIBRARIES = libntfs-3g.la
endif
libntfs_3g_la_CFLAGS = $(AM_CFLAGS)
libntfs_3g_la_CPPFLAGS= $(AM_CPPFLAGS) $(LIBNTFS_CPPFLAGS) -I$(top_srcdir)/include/ntfs-3g
libntfs_3g_la_LIBADD = $(LIBNTFS_LIBS)
libntfs_3g_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g
libntfs_3g_la_LDFLAGS = -version-info $(LIBNTFS_3G_VERSION) -no-undefined
if FUSE_INTERNAL
libntfs_3g_la_LIBADD = $(top_builddir)/libfuse-lite/libfuse-lite.la
endif
libntfs_3g_la_SOURCES = \
acls.c \
attrib.c \
attrlist.c \
bitmap.c \
bootsect.c \
cache.c \
collate.c \
compat.c \
compress.c \
debug.c \
device.c \
dir.c \
ea.c \
efs.c \
index.c \
inode.c \
ioctl.c \
lcnalloc.c \
logfile.c \
logging.c \
mft.c \
misc.c \
mst.c \
object_id.c \
realpath.c \
reparse.c \
runlist.c \
security.c \
unistr.c \
volume.c \
xattrs.c
volume.c
if NTFS_DEVICE_DEFAULT_IO_OPS
if WINDOWS
@ -78,7 +75,3 @@ if INSTALL_LIBRARY
$(RM) -f "$(DESTDIR)/$(rootlibdir)"/libntfs-3g.so*
endif
if ENABLE_NTFSPROGS
libs: $(lib_LTLIBRARIES)
endif

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-2017 Jean-Pierre Andre
* Copyright (c) 2007-2009 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,6 +22,10 @@
* 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
@ -54,6 +58,55 @@
#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
@ -85,19 +138,6 @@ static const char worldsidbytes[] = {
const SID *worldsid = (const SID*)worldsidbytes;
/*
* SID for authenticated user (S-1-5-11)
*/
static const char authsidbytes[] = {
1, /* revision */
1, /* auth count */
0, 0, 0, 0, 0, 5, /* base */
11, 0, 0, 0 /* 1st level */
};
static const SID *authsid = (const SID*)authsidbytes;
/*
* SID for administrator
*/
@ -177,11 +217,7 @@ BOOL ntfs_same_sid(const SID *first, const SID *second)
/*
* Test whether a SID means "world user"
* Local users group recognized as world
* Also interactive users so that /Users/Public is world accessible,
* but only if Posix ACLs are not enabled (if Posix ACLs are enabled,
* access to /Users/Public should be done by defining interactive users
* as a mapped group.)
* Local users group also recognized as world
*/
static int is_world_sid(const SID * usid)
@ -199,20 +235,6 @@ static int is_world_sid(const SID * usid)
&& (usid->identifier_authority.low_part == const_cpu_to_be32(5))
&& (usid->sub_authority[0] == const_cpu_to_le32(32))
&& (usid->sub_authority[1] == const_cpu_to_le32(545)))
/* check whether S-1-5-11 : authenticated user */
|| ((usid->sub_authority_count == 1)
&& (usid->identifier_authority.high_part == const_cpu_to_be16(0))
&& (usid->identifier_authority.low_part == const_cpu_to_be32(5))
&& (usid->sub_authority[0] == const_cpu_to_le32(11)))
#if !POSIXACLS
/* check whether S-1-5-4 : interactive user */
|| ((usid->sub_authority_count == 1)
&& (usid->identifier_authority.high_part == const_cpu_to_be16(0))
&& (usid->identifier_authority.low_part == const_cpu_to_be32(5))
&& (usid->sub_authority[0] == const_cpu_to_le32(4)))
#endif /* !POSIXACLS */
);
}
@ -230,25 +252,6 @@ BOOL ntfs_is_user_sid(const SID *usid)
&& (usid->sub_authority[0] == const_cpu_to_le32(21)));
}
/*
* Test whether a SID means "some special group"
* Currently we only check for a few S-1-5-n but we should
* probably test for other configurations.
*
* This is useful for granting access to /Users/Public for
* specific users when the Posix ACLs are enabled.
*/
static BOOL ntfs_known_group_sid(const SID *usid)
{
/* count == 1 excludes S-1-5-5-X-Y (logon) */
return ((usid->sub_authority_count == 1)
&& (usid->identifier_authority.high_part == const_cpu_to_be16(0))
&& (usid->identifier_authority.low_part == const_cpu_to_be32(5))
&& (le32_to_cpu(usid->sub_authority[0]) >= 1)
&& (le32_to_cpu(usid->sub_authority[0]) <= 6));
}
/*
* Determine the size of a security attribute
* whatever the order of fields
@ -309,18 +312,16 @@ unsigned int ntfs_attr_size(const char *attr)
return (attrsz);
}
/**
* ntfs_valid_sid - determine if a SID is valid
* @sid: SID for which to determine if it is valid
*
* Determine if the SID pointed to by @sid is valid.
*
* Return TRUE if it is valid and FALSE otherwise.
/*
* Do sanity checks on a SID read from storage
* (just check revision and number of authorities)
*/
BOOL ntfs_valid_sid(const SID *sid)
{
return sid && sid->revision == SID_REVISION &&
sid->sub_authority_count <= SID_MAX_SUB_AUTHORITIES;
return ((sid->revision == SID_REVISION)
&& (sid->sub_authority_count >= 1)
&& (sid->sub_authority_count <= 8));
}
/*
@ -521,7 +522,9 @@ gid_t ntfs_find_group(const struct MAPPING* groupmapping, const SID * gsid)
{
gid_t gid;
const struct MAPPING *p;
int gsidsz;
gsidsz = ntfs_sid_size(gsid);
p = groupmapping;
while (p && p->xid && !ntfs_same_sid(gsid, p->sid))
p = p->next;
@ -546,7 +549,6 @@ 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;
@ -560,35 +562,9 @@ static BOOL valid_acl(const ACL *pacl, unsigned int end)
pace = (const ACCESS_ALLOWED_ACE*)
&((const char*)pacl)[offace];
acesz = le16_to_cpu(pace->size);
switch (pace->type) {
case ACCESS_ALLOWED_ACE_TYPE :
case ACCESS_DENIED_ACE_TYPE :
wantsz = ntfs_sid_size(&pace->sid) + 8;
if (((offace + acesz) > end)
|| !ntfs_valid_sid(&pace->sid)
|| (wantsz != acesz))
ok = FALSE;
break;
case SYSTEM_AUDIT_ACE_TYPE :
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE :
case ACCESS_DENIED_CALLBACK_ACE_TYPE :
case SYSTEM_AUDIT_CALLBACK_ACE_TYPE :
case SYSTEM_MANDATORY_LABEL_ACE_TYPE :
case SYSTEM_RESOURCE_ATTRIBUTE_ACE_TYPE :
case SYSTEM_SCOPED_POLICY_ID_ACE_TYPE :
/* Extra data after the SID */
wantsz = ntfs_sid_size(&pace->sid) + 8;
if (((offace + acesz) > end)
|| !ntfs_valid_sid(&pace->sid)
|| (wantsz > acesz))
ok = FALSE;
break;
default :
/* SID at a different location */
if ((offace + acesz) > end)
ok = FALSE;
break;
}
if (((offace + acesz) > end)
|| !ntfs_valid_sid(&pace->sid))
ok = FALSE;
offace += acesz;
}
}
@ -638,6 +614,7 @@ BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz)
* old revision and no DACL though SE_DACL_PRESENT is set
*/
if ((attrsz >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
&& (ntfs_attr_size(securattr) <= attrsz)
&& (phead->revision == SECURITY_DESCRIPTOR_REVISION)
&& (offowner >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
&& ((offowner + 2) < attrsz)
@ -645,15 +622,14 @@ BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz)
&& ((offgroup + 2) < attrsz)
&& (!offdacl
|| ((offdacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
&& (offdacl+sizeof(ACL) <= attrsz)))
&& (offdacl < attrsz)))
&& (!offsacl
|| ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
&& (offsacl+sizeof(ACL) <= attrsz)))
&& (offsacl < attrsz)))
&& !(phead->owner & const_cpu_to_le32(3))
&& !(phead->group & const_cpu_to_le32(3))
&& !(phead->dacl & const_cpu_to_le32(3))
&& !(phead->sacl & const_cpu_to_le32(3))
&& (ntfs_attr_size(securattr) <= attrsz)
&& ntfs_valid_sid((const SID*)&securattr[offowner])
&& ntfs_valid_sid((const SID*)&securattr[offgroup])
/*
@ -689,8 +665,7 @@ BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz)
*/
int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
const SID *usid, const SID *gsid, BOOL fordir,
le16 inherited)
const SID *usid, const SID *gsid, BOOL fordir)
{
unsigned int src;
unsigned int dst;
@ -701,14 +676,9 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
int acesz;
int usidsz;
int gsidsz;
BOOL acceptable;
const ACCESS_ALLOWED_ACE *poldace;
ACCESS_ALLOWED_ACE *pnewace;
ACCESS_ALLOWED_ACE *pauthace;
ACCESS_ALLOWED_ACE *pownerace;
pauthace = (ACCESS_ALLOWED_ACE*)NULL;
pownerace = (ACCESS_ALLOWED_ACE*)NULL;
usidsz = ntfs_sid_size(usid);
gsidsz = ntfs_sid_size(gsid);
@ -725,46 +695,23 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
for (nace = 0; nace < oldcnt; nace++) {
poldace = (const ACCESS_ALLOWED_ACE*)((const char*)oldacl + src);
acesz = le16_to_cpu(poldace->size);
src += acesz;
/*
* Currently only ACE for file or directory access are
* processed. More information needed about what to do
* for other types (whose SID may be at a different location)
*/
switch (poldace->type) {
case ACCESS_ALLOWED_ACE_TYPE :
case ACCESS_DENIED_ACE_TYPE :
acceptable = TRUE;
break;
default :
acceptable = FALSE;
break;
}
/*
* Extract inheritance for access, including inheritance for
* access from an ACE with is both applied and inheritable.
*
* must not output OBJECT_INHERIT_ACE or CONTAINER_INHERIT_ACE
*
* According to MSDN :
* "For a case in which a container object inherits an ACE
* "that is both effective on the container and inheritable
* "by its descendants, the container may inherit two ACEs.
* "This occurs if the inheritable ACE contains generic
* "information."
*/
if ((poldace->flags & selection)
&& acceptable
&& (!fordir
|| (poldace->flags & NO_PROPAGATE_INHERIT_ACE)
|| (poldace->mask & (GENERIC_ALL | GENERIC_READ
| GENERIC_WRITE | GENERIC_EXECUTE)))
&& !ntfs_same_sid(&poldace->sid, ownersid)
&& !ntfs_same_sid(&poldace->sid, groupsid)) {
/* inheritance for access */
if (poldace->flags & selection) {
pnewace = (ACCESS_ALLOWED_ACE*)
((char*)newacl + dst);
memcpy(pnewace,poldace,acesz);
/* reencode GENERIC_ALL */
/*
* Replace generic creator-owner and
* creator-group by owner and group
*/
if (ntfs_same_sid(&pnewace->sid, ownersid)) {
memcpy(&pnewace->sid, usid, usidsz);
acesz = usidsz + 8;
}
if (ntfs_same_sid(&pnewace->sid, groupsid)) {
memcpy(&pnewace->sid, gsid, gsidsz);
acesz = gsidsz + 8;
}
if (pnewace->mask & GENERIC_ALL) {
pnewace->mask &= ~GENERIC_ALL;
if (fordir)
@ -781,163 +728,38 @@ int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl,
| FILE_READ
| FILE_WRITE
| FILE_EXEC
| const_cpu_to_le32(0x40);
}
/* reencode GENERIC_READ (+ EXECUTE) */
if (pnewace->mask & GENERIC_READ) {
if (fordir)
pnewace->mask |= OWNER_RIGHTS
| DIR_READ
| DIR_EXEC;
else
pnewace->mask |= OWNER_RIGHTS
| FILE_READ
| FILE_EXEC;
pnewace->mask &= ~(GENERIC_READ
| GENERIC_EXECUTE
| WRITE_DAC
| WRITE_OWNER
| DELETE | FILE_WRITE_EA
| FILE_WRITE_ATTRIBUTES);
}
/* reencode GENERIC_WRITE */
if (pnewace->mask & GENERIC_WRITE) {
if (fordir)
pnewace->mask |= OWNER_RIGHTS
| DIR_WRITE;
else
pnewace->mask |= OWNER_RIGHTS
| FILE_WRITE;
pnewace->mask &= ~(GENERIC_WRITE
| WRITE_DAC
| WRITE_OWNER
| FILE_DELETE_CHILD);
| cpu_to_le32(0x40);
}
/* remove inheritance flags */
pnewace->flags &= ~(OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE);
/*
* Group similar ACE for authenticated users
* (should probably be done for other SIDs)
*/
if ((poldace->type == ACCESS_ALLOWED_ACE_TYPE)
&& ntfs_same_sid(&poldace->sid, authsid)) {
if (pauthace) {
pauthace->flags |= pnewace->flags;
pauthace->mask |= pnewace->mask;
} else {
pauthace = pnewace;
if (inherited)
pnewace->flags |= INHERITED_ACE;
dst += acesz;
newcnt++;
}
} else {
if (inherited)
pnewace->flags |= INHERITED_ACE;
dst += acesz;
newcnt++;
}
dst += acesz;
newcnt++;
}
/*
* Inheritance for access, specific to
* creator-owner (and creator-group)
*/
if ((fordir || !inherited
|| (poldace->flags
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE)))
&& acceptable) {
pnewace = (ACCESS_ALLOWED_ACE*)
((char*)newacl + dst);
memcpy(pnewace,poldace,acesz);
/*
* Replace generic creator-owner and
* creator-group by owner and group
* (but keep for further inheritance)
*/
if (ntfs_same_sid(&pnewace->sid, ownersid)) {
memcpy(&pnewace->sid, usid, usidsz);
pnewace->size = cpu_to_le16(usidsz + 8);
/* remove inheritance flags */
pnewace->flags &= ~(OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE);
if (inherited)
pnewace->flags |= INHERITED_ACE;
if ((pnewace->type == ACCESS_ALLOWED_ACE_TYPE)
&& pownerace
&& !(pnewace->flags & ~pownerace->flags)) {
pownerace->mask |= pnewace->mask;
} else {
dst += usidsz + 8;
newcnt++;
}
}
if (ntfs_same_sid(&pnewace->sid, groupsid)) {
memcpy(&pnewace->sid, gsid, gsidsz);
pnewace->size = cpu_to_le16(gsidsz + 8);
/* remove inheritance flags */
pnewace->flags &= ~(OBJECT_INHERIT_ACE
| CONTAINER_INHERIT_ACE
| INHERIT_ONLY_ACE);
if (inherited)
pnewace->flags |= INHERITED_ACE;
dst += gsidsz + 8;
newcnt++;
}
}
/*
* inheritance for further inheritance
*
* Situations leading to output CONTAINER_INHERIT_ACE
* or OBJECT_INHERIT_ACE
*/
/* inheritance for further inheritance */
if (fordir
&& (poldace->flags
& (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE))) {
pnewace = (ACCESS_ALLOWED_ACE*)
((char*)newacl + dst);
memcpy(pnewace,poldace,acesz);
if ((poldace->flags & OBJECT_INHERIT_ACE)
&& !(poldace->flags & (CONTAINER_INHERIT_ACE
| NO_PROPAGATE_INHERIT_ACE)))
pnewace->flags |= INHERIT_ONLY_ACE;
if (acceptable
&& (poldace->flags & CONTAINER_INHERIT_ACE)
&& !(poldace->flags & NO_PROPAGATE_INHERIT_ACE)
&& !ntfs_same_sid(&poldace->sid, ownersid)
&& !ntfs_same_sid(&poldace->sid, groupsid)) {
if ((poldace->mask & (GENERIC_ALL | GENERIC_READ
| GENERIC_WRITE | GENERIC_EXECUTE)))
pnewace->flags |= INHERIT_ONLY_ACE;
else
pnewace->flags &= ~INHERIT_ONLY_ACE;
/*
* Replace generic creator-owner and
* creator-group by owner and group
*/
if (ntfs_same_sid(&pnewace->sid, ownersid)) {
memcpy(&pnewace->sid, usid, usidsz);
acesz = usidsz + 8;
}
if (inherited)
pnewace->flags |= INHERITED_ACE;
/*
* Prepare grouping similar ACE for authenticated users
*/
if ((poldace->type == ACCESS_ALLOWED_ACE_TYPE)
&& !pauthace
&& !(pnewace->flags & INHERIT_ONLY_ACE)
&& ntfs_same_sid(&poldace->sid, authsid)) {
pauthace = pnewace;
}
/*
* Prepare grouping similar ACE for owner
*/
if ((poldace->type == ACCESS_ALLOWED_ACE_TYPE)
&& !pownerace
&& !(pnewace->flags & INHERIT_ONLY_ACE)
&& ntfs_same_sid(&poldace->sid, usid)) {
pownerace = pnewace;
if (ntfs_same_sid(&pnewace->sid, groupsid)) {
memcpy(&pnewace->sid, gsid, gsidsz);
acesz = gsidsz + 8;
}
dst += acesz;
newcnt++;
}
src += acesz;
}
/*
* Adjust header if something was inherited
@ -1296,49 +1118,6 @@ struct POSIX_SECURITY *ntfs_replace_acl(const struct POSIX_SECURITY *oldpxdesc,
return (newpxdesc);
}
/*
* Build a basic Posix ACL from a mode and umask,
* ignoring inheritance from the parent directory
*/
struct POSIX_SECURITY *ntfs_build_basic_posix(
const struct POSIX_SECURITY *pxdesc __attribute__((unused)),
mode_t mode, mode_t mask, BOOL isdir __attribute__((unused)))
{
struct POSIX_SECURITY *pydesc;
struct POSIX_ACE *pyace;
pydesc = (struct POSIX_SECURITY*)malloc(
sizeof(struct POSIX_SECURITY) + 3*sizeof(struct POSIX_ACE));
if (pydesc) {
pyace = &pydesc->acl.ace[0];
pyace->tag = POSIX_ACL_USER_OBJ;
pyace->perms = ((mode & ~mask) >> 6) & 7;
pyace->id = -1;
pyace = &pydesc->acl.ace[1];
pyace->tag = POSIX_ACL_GROUP_OBJ;
pyace->perms = ((mode & ~mask) >> 3) & 7;
pyace->id = -1;
pyace = &pydesc->acl.ace[2];
pyace->tag = POSIX_ACL_OTHER;
pyace->perms = (mode & ~mask) & 7;
pyace->id = -1;
pydesc->mode = mode;
pydesc->tagsset = POSIX_ACL_USER_OBJ
| POSIX_ACL_GROUP_OBJ
| POSIX_ACL_OTHER;
pydesc->acccnt = 3;
pydesc->defcnt = 0;
pydesc->firstdef = 6;
pydesc->filler = 0;
pydesc->acl.version = POSIX_VERSION;
pydesc->acl.flags = 0;
pydesc->acl.filler = 0;
} else
errno = ENOMEM;
return (pydesc);
}
/*
* Build an inherited Posix descriptor from parent
* descriptor (if any) restricted to creation mode
@ -1633,7 +1412,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 {
@ -1789,7 +1568,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);
@ -1875,7 +1654,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;
@ -2119,6 +1898,7 @@ static int buildacls_posix(struct MAPPING* const mapping[],
const SID *sid;
int acecnt;
int usidsz;
int gsidsz;
int wsidsz;
int asidsz;
int ssidsz;
@ -2126,6 +1906,7 @@ static int buildacls_posix(struct MAPPING* const mapping[],
le32 grants;
usidsz = ntfs_sid_size(usid);
gsidsz = ntfs_sid_size(gsid);
wsidsz = ntfs_sid_size(worldsid);
asidsz = ntfs_sid_size(adminsid);
ssidsz = ntfs_sid_size(systemsid);
@ -2180,7 +1961,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;
@ -2191,7 +1972,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;
@ -2311,21 +2092,10 @@ return (0);
mapping,flags,pxace,pset);
break;
case POSIX_ACL_GROUP_OBJ :
/* denials and grants for group when needed */
if (pset->groupowns && !pset->adminowns
&& (pset->grpperms == pset->othperms)
&& !pset->designates && !pset->withmask) {
ok = TRUE;
} else {
ok = build_group_denials_grant(pacl,gsid,
mapping,flags,pxace,pset);
}
break;
case POSIX_ACL_GROUP :
case POSIX_ACL_GROUP_OBJ :
/* denials and grants for designated groups */
/* denials and grants for groups */
ok = build_group_denials_grant(pacl,gsid,
mapping,flags,pxace,pset);
@ -2582,6 +2352,7 @@ static int buildacls(char *secattr, int offs, mode_t mode, int isdir,
/* this ACE will be inserted after denials for group */
if (adminowns
|| groupowns
|| (((mode >> 3) ^ mode) & 7)) {
grants = WORLD_RIGHTS;
if (isdir) {
@ -2785,10 +2556,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*MAX_SID_SIZE;
newattrsz += 3*40; /* fixme : maximum size */
}
/* account for default ACE's */
newattrsz += 2*MAX_SID_SIZE*pxdesc->defcnt;
newattrsz += 2*40*pxdesc->defcnt; /* fixme : maximum size */
newattr = (char*)ntfs_malloc(newattrsz);
if (newattr) {
/* build the main header part */
@ -3214,10 +2985,8 @@ static int build_std_permissions(const char *securattr,
if (offdacl) {
acecnt = le16_to_cpu(pacl->ace_count);
offace = offdacl + sizeof(ACL);
} else {
} else
acecnt = 0;
offace = 0;
}
for (nace = 0; nace < acecnt; nace++) {
pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace];
if (!(pace->flags & INHERIT_ONLY_ACE)) {
@ -3289,7 +3058,6 @@ static int build_owngrp_permissions(const char *securattr,
int nace;
le32 special;
BOOL grppresent;
BOOL ownpresent;
le32 allowown, allowgrp, allowall;
le32 denyown, denygrp, denyall;
@ -3299,26 +3067,21 @@ static int build_owngrp_permissions(const char *securattr,
special = const_cpu_to_le32(0);
allowown = allowgrp = allowall = const_cpu_to_le32(0);
denyown = denygrp = denyall = const_cpu_to_le32(0);
ownpresent = FALSE;
grppresent = FALSE;
if (offdacl) {
acecnt = le16_to_cpu(pacl->ace_count);
offace = offdacl + sizeof(ACL);
} else {
} else
acecnt = 0;
offace = 0;
}
for (nace = 0; nace < acecnt; nace++) {
pace = (const ACCESS_ALLOWED_ACE*)&securattr[offace];
if (!(pace->flags & INHERIT_ONLY_ACE)) {
if ((ntfs_same_sid(usid, &pace->sid)
|| ntfs_same_sid(ownersid, &pace->sid))
&& (pace->mask & WRITE_OWNER)) {
if (pace->type == ACCESS_ALLOWED_ACE_TYPE) {
if (pace->type == ACCESS_ALLOWED_ACE_TYPE)
allowown |= pace->mask;
ownpresent = TRUE;
}
} else
} else
if (ntfs_same_sid(usid, &pace->sid)
&& (!(pace->mask & WRITE_OWNER))) {
if (pace->type == ACCESS_ALLOWED_ACE_TYPE) {
@ -3339,8 +3102,6 @@ static int build_owngrp_permissions(const char *securattr,
}
offace += le16_to_cpu(pace->size);
}
if (!ownpresent)
allowown = allowall;
if (!grppresent)
allowgrp = allowall;
return (merge_permissions(isdir,
@ -3366,6 +3127,7 @@ static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc,
u16 tag;
u16 tagsset;
struct POSIX_ACE *pxace;
int acccnt;
mode_t denywrld;
mode_t allow;
mode_t deny;
@ -3374,6 +3136,7 @@ static int norm_ownadmin_permissions_posix(struct POSIX_SECURITY *posix_desc,
mode = 0;
pxace = posix_desc->acl.ace;
acccnt = posix_desc->acccnt;
tagsset = 0;
denywrld = 0;
/*
@ -3492,10 +3255,8 @@ static int build_ownadmin_permissions(const char *securattr,
if (offdacl) {
acecnt = le16_to_cpu(pacl->ace_count);
offace = offdacl + sizeof(ACL);
} else {
} else
acecnt = 0;
offace = 0;
}
firstapply = TRUE;
isforeign = 3;
for (nace = 0; nace < acecnt; nace++) {
@ -3642,7 +3403,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);
@ -3777,13 +3538,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;
@ -3806,7 +3567,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
@ -3838,7 +3599,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;
@ -3872,7 +3633,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)
@ -3885,7 +3646,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)
@ -3907,9 +3668,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
}
}
}
if (((pace->type == ACCESS_ALLOWED_ACE_TYPE)
|| (pace->type == ACCESS_DENIED_ACE_TYPE))
&& !ignore) {
if (!ignore) {
pxace->perms = 0;
/* specific decoding for vtx/uid/gid */
if (pxace->tag == POSIX_ACL_SPECIAL) {
@ -3945,7 +3704,7 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
pxace->perms |= POSIX_PERM_DENIAL;
else
if (pxace->tag == POSIX_ACL_OTHER)
pctx->permswrld |= pxace->perms;
pctx->permswrld = pxace->perms;
pctx->tagsset |= pxace->tag;
if (pace->flags & INHERIT_ONLY_ACE) {
l--;
@ -4115,10 +3874,12 @@ struct POSIX_SECURITY *ntfs_build_permissions_posix(
int ntfs_build_permissions(const char *securattr,
const SID *usid, const SID *gsid, BOOL isdir)
{
const SECURITY_DESCRIPTOR_RELATIVE *phead;
int perm;
BOOL adminowns;
BOOL groupowns;
phead = (const SECURITY_DESCRIPTOR_RELATIVE*)securattr;
adminowns = ntfs_same_sid(usid,adminsid)
|| ntfs_same_sid(gsid,adminsid);
groupowns = !adminowns && ntfs_same_sid(gsid,usid);
@ -4179,8 +3940,7 @@ static SID *encodesid(const char *sidstr)
cnt++;
}
bsid->sub_authority_count = cnt;
if ((cnt > 0) && ntfs_valid_sid(bsid)
&& (ntfs_is_user_sid(bsid) || ntfs_known_group_sid(bsid))) {
if ((cnt > 0) && ntfs_valid_sid(bsid) && ntfs_is_user_sid(bsid)) {
sid = (SID*) ntfs_malloc(4 * cnt + 8);
if (sid)
memcpy(sid, bsid, 4 * cnt + 8);
@ -4189,6 +3949,33 @@ static SID *encodesid(const char *sidstr)
return (sid);
}
/*
* Early logging before the logs are redirected
*
* (not quite satisfactory : this appears before the ntfs-g banner,
* and with a different pid)
*/
static void log_early_error(const char *format, ...)
__attribute__((format(printf, 1, 2)));
static void log_early_error(const char *format, ...)
{
va_list args;
va_start(args, format);
#ifdef HAVE_SYSLOG_H
openlog("ntfs-3g", LOG_PID, LOG_USER);
ntfs_log_handler_syslog(NULL, NULL, 0,
NTFS_LOG_LEVEL_ERROR, NULL,
format, args);
#else
vfprintf(stderr,format,args);
#endif
va_end(args);
}
/*
* Get a single mapping item from buffer
*
@ -4202,6 +3989,7 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid,
{
int src;
int dst;
char *p;
char *q;
char *pu;
char *pg;
@ -4235,6 +4023,7 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid,
if (gotend) {
pu = pg = (char*)NULL;
/* decompose into uid, gid and sid */
p = item->maptext;
item->uidstr = item->maptext;
item->gidstr = strchr(item->uidstr, ':');
if (item->gidstr) {
@ -4249,7 +4038,7 @@ static struct MAPLIST *getmappingitem(FILEREADER reader, void *fileid,
if (pu && pg)
*pu = *pg = '\0';
else {
ntfs_log_early_error("Bad mapping item \"%s\"\n",
log_early_error("Bad mapping item \"%s\"\n",
item->maptext);
free(item);
item = (struct MAPLIST*)NULL;
@ -4378,7 +4167,7 @@ struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem)
if (pwd)
uid = pwd->pw_uid;
else
ntfs_log_early_error("Invalid user \"%s\"\n",
log_early_error("Invalid user \"%s\"\n",
item->uidstr);
}
}
@ -4389,12 +4178,6 @@ struct MAPPING *ntfs_do_user_mapping(struct MAPLIST *firstitem)
if (uid
|| (!item->uidstr[0] && !item->gidstr[0])) {
sid = encodesid(item->sidstr);
if (sid && ntfs_known_group_sid(sid)) {
ntfs_log_error("Bad user SID %s\n",
item->sidstr);
free(sid);
sid = (SID*)NULL;
}
if (sid && !item->uidstr[0] && !item->gidstr[0]
&& !ntfs_valid_pattern(sid)) {
ntfs_log_error("Bad implicit SID pattern %s\n",
@ -4464,7 +4247,7 @@ struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem)
if (grp)
gid = grp->gr_gid;
else
ntfs_log_early_error("Invalid group \"%s\"\n",
log_early_error("Invalid group \"%s\"\n",
item->gidstr);
}
}
@ -4487,15 +4270,7 @@ struct MAPPING *ntfs_do_group_mapping(struct MAPLIST *firstitem)
if (mapping) {
mapping->sid = sid;
mapping->xid = gid;
/* special groups point to themselves */
if (ntfs_known_group_sid(sid)) {
mapping->groups =
(gid_t*)&mapping->xid;
mapping->grcnt = 1;
} else
mapping->grcnt = 0;
mapping->grcnt = 0;
mapping->next = (struct MAPPING*)NULL;
if (lastmapping)
lastmapping->next = mapping;

File diff suppressed because it is too large Load Diff

View File

@ -107,7 +107,7 @@ int ntfs_attrlist_need(ntfs_inode *ni)
int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
{
ATTR_LIST_ENTRY *ale;
leMFT_REF mref;
MFT_REF mref;
ntfs_attr *na = NULL;
ntfs_attr_search_ctx *ctx;
u8 *new_al;
@ -150,7 +150,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
if (!ntfs_attr_lookup(attr->type, (attr->name_length) ? (ntfschar*)
((u8*)attr + le16_to_cpu(attr->name_offset)) :
AT_UNNAMED, attr->name_length, CASE_SENSITIVE,
(attr->non_resident) ? sle64_to_cpu(attr->lowest_vcn) :
(attr->non_resident) ? le64_to_cpu(attr->lowest_vcn) :
0, (attr->non_resident) ? NULL : ((u8*)attr +
le16_to_cpu(attr->value_offset)), (attr->non_resident) ?
0 : le32_to_cpu(attr->value_length), ctx)) {
@ -193,7 +193,7 @@ int ntfs_attrlist_entry_add(ntfs_inode *ni, ATTR_RECORD *attr)
if (attr->non_resident)
ale->lowest_vcn = attr->lowest_vcn;
else
ale->lowest_vcn = const_cpu_to_sle64(0);
ale->lowest_vcn = 0;
ale->mft_reference = mref;
ale->instance = attr->instance;
memcpy(ale->name, (u8 *)attr + le16_to_cpu(attr->name_offset),
@ -265,7 +265,7 @@ int ntfs_attrlist_entry_rm(ntfs_attr_search_ctx *ctx)
ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld.\n",
(long long) ctx->ntfs_ino->mft_no,
(unsigned) le32_to_cpu(ctx->al_entry->type),
(long long) sle64_to_cpu(ctx->al_entry->lowest_vcn));
(long long) le64_to_cpu(ctx->al_entry->lowest_vcn));
if (!NInoAttrList(base_ni)) {
ntfs_log_trace("Attribute list isn't present.\n");

View File

@ -38,7 +38,6 @@
#include <errno.h>
#endif
#include "param.h"
#include "compat.h"
#include "bootsect.h"
#include "debug.h"
@ -62,12 +61,11 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
{
u32 i;
BOOL ret = FALSE;
u16 sectors_per_cluster;
ntfs_log_debug("Beginning bootsector check.\n");
ntfs_log_debug("Checking OEMid, NTFS signature.\n");
if (b->oem_id != const_cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
if (b->oem_id != cpu_to_le64(0x202020205346544eULL)) { /* "NTFS " */
ntfs_log_error("NTFS signature is missing.\n");
goto not_ntfs;
}
@ -85,27 +83,15 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128:
break;
default:
if ((b->bpb.sectors_per_cluster < 240)
|| (b->bpb.sectors_per_cluster > 253)) {
if (b->bpb.sectors_per_cluster > 128)
ntfs_log_error("Unexpected sectors"
" per cluster value (code 0x%x)\n",
b->bpb.sectors_per_cluster);
else
ntfs_log_error("Unexpected sectors"
" per cluster value (%d).\n",
b->bpb.sectors_per_cluster);
goto not_ntfs;
}
ntfs_log_error("Unexpected sectors per cluster value (%d).\n",
b->bpb.sectors_per_cluster);
goto not_ntfs;
}
ntfs_log_debug("Checking cluster size.\n");
if (b->bpb.sectors_per_cluster > 128)
sectors_per_cluster = 1 << (256 - b->bpb.sectors_per_cluster);
else
sectors_per_cluster = b->bpb.sectors_per_cluster;
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) * sectors_per_cluster;
if (i > NTFS_MAX_CLUSTER_SIZE) {
i = (u32)le16_to_cpu(b->bpb.bytes_per_sector) *
b->bpb.sectors_per_cluster;
if (i > 65536) {
ntfs_log_error("Unexpected cluster size (%d).\n", i);
goto not_ntfs;
}
@ -154,15 +140,7 @@ BOOL ntfs_boot_sector_is_ntfs(NTFS_BOOT_SECTOR *b)
}
}
/* MFT and MFTMirr may not overlap the boot sector or be the same */
if (((s64)sle64_to_cpu(b->mft_lcn) <= 0)
|| ((s64)sle64_to_cpu(b->mftmirr_lcn) <= 0)
|| (b->mft_lcn == b->mftmirr_lcn)) {
ntfs_log_error("Invalid location of MFT or MFTMirr.\n");
goto not_ntfs;
}
if (b->end_of_sector_marker != const_cpu_to_le16(0xaa55))
if (b->end_of_sector_marker != cpu_to_le16(0xaa55))
ntfs_log_debug("Warning: Bootsector has invalid end of sector "
"marker.\n");
@ -193,7 +171,7 @@ static const char *last_sector_error =
int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
{
s64 sectors;
u16 sectors_per_cluster;
u8 sectors_per_cluster;
s8 c;
/* We return -1 with errno = EINVAL on error. */
@ -208,10 +186,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
* below or equal the number_of_clusters) really belong in the
* ntfs_boot_sector_is_ntfs but in this way we can just do this once.
*/
if (bs->bpb.sectors_per_cluster > 128)
sectors_per_cluster = 1 << (256 - bs->bpb.sectors_per_cluster);
else
sectors_per_cluster = bs->bpb.sectors_per_cluster;
sectors_per_cluster = bs->bpb.sectors_per_cluster;
ntfs_log_debug("SectorsPerCluster = 0x%x\n", sectors_per_cluster);
if (sectors_per_cluster & (sectors_per_cluster - 1)) {
ntfs_log_error("sectors_per_cluster (%d) is not a power of 2."
@ -229,7 +204,7 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
(sectors - 1) << vol->sector_size_bits,
SEEK_SET) == -1) {
ntfs_log_perror("Failed to read last sector (%lld)",
(long long)(sectors - 1));
(long long)sectors);
ntfs_log_error("%s", last_sector_error);
return -1;
}
@ -240,8 +215,8 @@ int ntfs_boot_sector_parse(ntfs_volume *vol, const NTFS_BOOT_SECTOR *bs)
vol->mftmirr_lcn = sle64_to_cpu(bs->mftmirr_lcn);
ntfs_log_debug("MFT LCN = %lld\n", (long long)vol->mft_lcn);
ntfs_log_debug("MFTMirr LCN = %lld\n", (long long)vol->mftmirr_lcn);
if ((vol->mft_lcn < 0 || vol->mft_lcn > vol->nr_clusters) ||
(vol->mftmirr_lcn < 0 || vol->mftmirr_lcn > vol->nr_clusters)) {
if (vol->mft_lcn > vol->nr_clusters ||
vol->mftmirr_lcn > vol->nr_clusters) {
ntfs_log_error("$MFT LCN (%lld) or $MFTMirr LCN (%lld) is "
"greater than the number of clusters (%lld).\n",
(long long)vol->mft_lcn, (long long)vol->mftmirr_lcn,

View File

@ -1,606 +0,0 @@
/**
* cache.c : deal with LRU caches
*
* Copyright (c) 2008-2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "types.h"
#include "security.h"
#include "cache.h"
#include "misc.h"
#include "logging.h"
/*
* General functions to deal with LRU caches
*
* The cached data have to be organized in a structure in which
* the first fields must follow a mandatory pattern and further
* fields may contain any fixed size data. They are stored in an
* LRU list.
*
* A compare function must be provided for finding a wanted entry
* in the cache. Another function may be provided for invalidating
* an entry to facilitate multiple invalidation.
*
* These functions never return error codes. When there is a
* shortage of memory, data is simply not cached.
* When there is a hashing bug, hashing is dropped, and sequential
* searches are used.
*/
/*
* Enter a new hash index, after a new record has been inserted
*
* Do not call when a record has been modified (with no key change)
*/
static void inserthashindex(struct CACHE_HEADER *cache,
struct CACHED_GENERIC *current)
{
int h;
struct HASH_ENTRY *link;
struct HASH_ENTRY *first;
if (cache->dohash) {
h = cache->dohash(current);
if ((h >= 0) && (h < cache->max_hash)) {
/* get a free link and insert at top of hash list */
link = cache->free_hash;
if (link) {
cache->free_hash = link->next;
first = cache->first_hash[h];
if (first)
link->next = first;
else
link->next = NULL;
link->entry = current;
cache->first_hash[h] = link;
} else {
ntfs_log_error("No more hash entries,"
" cache %s hashing dropped\n",
cache->name);
cache->dohash = (cache_hash)NULL;
}
} else {
ntfs_log_error("Illegal hash value,"
" cache %s hashing dropped\n",
cache->name);
cache->dohash = (cache_hash)NULL;
}
}
}
/*
* Drop a hash index when a record is about to be deleted
*/
static void drophashindex(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *current, int hash)
{
struct HASH_ENTRY *link;
struct HASH_ENTRY *previous;
if (cache->dohash) {
if ((hash >= 0) && (hash < cache->max_hash)) {
/* find the link and unlink */
link = cache->first_hash[hash];
previous = (struct HASH_ENTRY*)NULL;
while (link && (link->entry != current)) {
previous = link;
link = link->next;
}
if (link) {
if (previous)
previous->next = link->next;
else
cache->first_hash[hash] = link->next;
link->next = cache->free_hash;
cache->free_hash = link;
} else {
ntfs_log_error("Bad hash list,"
" cache %s hashing dropped\n",
cache->name);
cache->dohash = (cache_hash)NULL;
}
} else {
ntfs_log_error("Illegal hash value,"
" cache %s hashing dropped\n",
cache->name);
cache->dohash = (cache_hash)NULL;
}
}
}
/*
* Fetch an entry from cache
*
* returns the cache entry, or NULL if not available
* The returned entry may be modified, but not freed
*/
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *wanted, cache_compare compare)
{
struct CACHED_GENERIC *current;
struct CACHED_GENERIC *previous;
struct HASH_ENTRY *link;
int h;
current = (struct CACHED_GENERIC*)NULL;
if (cache) {
if (cache->dohash) {
/*
* When possible, use the hash table to
* locate the entry if present
*/
h = cache->dohash(wanted);
link = cache->first_hash[h];
while (link && compare(link->entry, wanted))
link = link->next;
if (link)
current = link->entry;
}
if (!cache->dohash) {
/*
* Search sequentially in LRU list if no hash table
* or if hashing has just failed
*/
current = cache->most_recent_entry;
while (current
&& compare(current, wanted)) {
current = current->next;
}
}
if (current) {
previous = current->previous;
cache->hits++;
if (previous) {
/*
* found and not at head of list, unlink from current
* position and relink as head of list
*/
previous->next = current->next;
if (current->next)
current->next->previous
= current->previous;
else
cache->oldest_entry
= current->previous;
current->next = cache->most_recent_entry;
current->previous
= (struct CACHED_GENERIC*)NULL;
cache->most_recent_entry->previous = current;
cache->most_recent_entry = current;
}
}
cache->reads++;
}
return (current);
}
/*
* Enter an inode number into cache
* returns the cache entry or NULL if not possible
*/
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item,
cache_compare compare)
{
struct CACHED_GENERIC *current;
struct CACHED_GENERIC *before;
struct HASH_ENTRY *link;
int h;
current = (struct CACHED_GENERIC*)NULL;
if (cache) {
if (cache->dohash) {
/*
* When possible, use the hash table to
* find out whether the entry if present
*/
h = cache->dohash(item);
link = cache->first_hash[h];
while (link && compare(link->entry, item))
link = link->next;
if (link) {
current = link->entry;
}
}
if (!cache->dohash) {
/*
* Search sequentially in LRU list to locate the end,
* and find out whether the entry is already in list
* As we normally go to the end, no statistics is
* kept.
*/
current = cache->most_recent_entry;
while (current
&& compare(current, item)) {
current = current->next;
}
}
if (!current) {
/*
* Not in list, get a free entry or reuse the
* last entry, and relink as head of list
* Note : we assume at least three entries, so
* before, previous and first are different when
* an entry is reused.
*/
if (cache->free_entry) {
current = cache->free_entry;
cache->free_entry = cache->free_entry->next;
if (item->varsize) {
current->variable = ntfs_malloc(
item->varsize);
} else
current->variable = (void*)NULL;
current->varsize = item->varsize;
if (!cache->oldest_entry)
cache->oldest_entry = current;
} else {
/* reusing the oldest entry */
current = cache->oldest_entry;
before = current->previous;
before->next = (struct CACHED_GENERIC*)NULL;
if (cache->dohash)
drophashindex(cache,current,
cache->dohash(current));
if (cache->dofree)
cache->dofree(current);
cache->oldest_entry = current->previous;
if (item->varsize) {
if (current->varsize)
current->variable = realloc(
current->variable,
item->varsize);
else
current->variable = ntfs_malloc(
item->varsize);
} else {
if (current->varsize)
free(current->variable);
current->variable = (void*)NULL;
}
current->varsize = item->varsize;
}
current->next = cache->most_recent_entry;
current->previous = (struct CACHED_GENERIC*)NULL;
if (cache->most_recent_entry)
cache->most_recent_entry->previous = current;
cache->most_recent_entry = current;
memcpy(current->payload, item->payload, cache->fixed_size);
if (item->varsize) {
if (current->variable) {
memcpy(current->variable,
item->variable, item->varsize);
} else {
/*
* no more memory for variable part
* recycle entry in free list
* not an error, just uncacheable
*/
cache->most_recent_entry = current->next;
current->next = cache->free_entry;
cache->free_entry = current;
current = (struct CACHED_GENERIC*)NULL;
}
} else {
current->variable = (void*)NULL;
current->varsize = 0;
}
if (cache->dohash && current)
inserthashindex(cache,current);
}
cache->writes++;
}
return (current);
}
/*
* Invalidate a cache entry
* The entry is moved to the free entry list
* A specific function may be called for entry deletion
*/
static void do_invalidate(struct CACHE_HEADER *cache,
struct CACHED_GENERIC *current, int flags)
{
struct CACHED_GENERIC *previous;
previous = current->previous;
if ((flags & CACHE_FREE) && cache->dofree)
cache->dofree(current);
/*
* Relink into free list
*/
if (current->next)
current->next->previous = current->previous;
else
cache->oldest_entry = current->previous;
if (previous)
previous->next = current->next;
else
cache->most_recent_entry = current->next;
current->next = cache->free_entry;
cache->free_entry = current;
if (current->variable)
free(current->variable);
current->varsize = 0;
}
/*
* Invalidate entries in cache
*
* Several entries may have to be invalidated (at least for inodes
* associated to directories which have been renamed), a different
* compare function may be provided to select entries to invalidate
*
* Returns the number of deleted entries, this can be used by
* the caller to signal a cache corruption if the entry was
* supposed to be found.
*/
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item, cache_compare compare,
int flags)
{
struct CACHED_GENERIC *current;
struct CACHED_GENERIC *next;
struct HASH_ENTRY *link;
int count;
int h;
current = (struct CACHED_GENERIC*)NULL;
count = 0;
if (cache) {
if (!(flags & CACHE_NOHASH) && cache->dohash) {
/*
* When possible, use the hash table to
* find out whether the entry if present
*/
h = cache->dohash(item);
link = cache->first_hash[h];
while (link) {
if (compare(link->entry, item))
link = link->next;
else {
current = link->entry;
link = link->next;
if (current) {
drophashindex(cache,current,h);
do_invalidate(cache,
current,flags);
count++;
}
}
}
}
if ((flags & CACHE_NOHASH) || !cache->dohash) {
/*
* Search sequentially in LRU list
*/
current = cache->most_recent_entry;
while (current) {
if (!compare(current, item)) {
next = current->next;
if (cache->dohash)
drophashindex(cache,current,
cache->dohash(current));
do_invalidate(cache,current,flags);
current = next;
count++;
} else {
current = current->next;
}
}
}
}
return (count);
}
int ntfs_remove_cache(struct CACHE_HEADER *cache,
struct CACHED_GENERIC *item, int flags)
{
int count;
count = 0;
if (cache) {
if (cache->dohash)
drophashindex(cache,item,cache->dohash(item));
do_invalidate(cache,item,flags);
count++;
}
return (count);
}
/*
* Free memory allocated to a cache
*/
static void ntfs_free_cache(struct CACHE_HEADER *cache)
{
struct CACHED_GENERIC *entry;
if (cache) {
for (entry=cache->most_recent_entry; entry; entry=entry->next) {
if (cache->dofree)
cache->dofree(entry);
if (entry->variable)
free(entry->variable);
}
free(cache);
}
}
/*
* Create a cache
*
* Returns the cache header, or NULL if the cache could not be created
*/
static struct CACHE_HEADER *ntfs_create_cache(const char *name,
cache_free dofree, cache_hash dohash,
int full_item_size,
int item_count, int max_hash)
{
struct CACHE_HEADER *cache;
struct CACHED_GENERIC *pc;
struct CACHED_GENERIC *qc;
struct HASH_ENTRY *ph;
struct HASH_ENTRY *qh;
struct HASH_ENTRY **px;
size_t size;
int i;
size = sizeof(struct CACHE_HEADER) + item_count*full_item_size;
if (max_hash)
size += item_count*sizeof(struct HASH_ENTRY)
+ max_hash*sizeof(struct HASH_ENTRY*);
cache = (struct CACHE_HEADER*)ntfs_malloc(size);
if (cache) {
/* header */
cache->name = name;
cache->dofree = dofree;
if (dohash && max_hash) {
cache->dohash = dohash;
cache->max_hash = max_hash;
} else {
cache->dohash = (cache_hash)NULL;
cache->max_hash = 0;
}
cache->fixed_size = full_item_size - sizeof(struct CACHED_GENERIC);
cache->reads = 0;
cache->writes = 0;
cache->hits = 0;
/* chain the data entries, and mark an invalid entry */
cache->most_recent_entry = (struct CACHED_GENERIC*)NULL;
cache->oldest_entry = (struct CACHED_GENERIC*)NULL;
cache->free_entry = &cache->entry[0];
pc = &cache->entry[0];
for (i=0; i<(item_count - 1); i++) {
qc = (struct CACHED_GENERIC*)((char*)pc
+ full_item_size);
pc->next = qc;
pc->variable = (void*)NULL;
pc->varsize = 0;
pc = qc;
}
/* special for the last entry */
pc->next = (struct CACHED_GENERIC*)NULL;
pc->variable = (void*)NULL;
pc->varsize = 0;
if (max_hash) {
/* chain the hash entries */
ph = (struct HASH_ENTRY*)(((char*)pc) + full_item_size);
cache->free_hash = ph;
for (i=0; i<(item_count - 1); i++) {
qh = &ph[1];
ph->next = qh;
ph = qh;
}
/* special for the last entry */
if (item_count) {
ph->next = (struct HASH_ENTRY*)NULL;
}
/* create and initialize the hash indexes */
px = (struct HASH_ENTRY**)&ph[1];
cache->first_hash = px;
for (i=0; i<max_hash; i++)
px[i] = (struct HASH_ENTRY*)NULL;
} else {
cache->free_hash = (struct HASH_ENTRY*)NULL;
cache->first_hash = (struct HASH_ENTRY**)NULL;
}
}
return (cache);
}
/*
* Create all LRU caches
*
* No error return, if creation is not possible, cacheing will
* just be not available
*/
void ntfs_create_lru_caches(ntfs_volume *vol)
{
#if CACHE_INODE_SIZE
/* inode cache */
vol->xinode_cache = ntfs_create_cache("inode",(cache_free)NULL,
ntfs_dir_inode_hash, sizeof(struct CACHED_INODE),
CACHE_INODE_SIZE, 2*CACHE_INODE_SIZE);
#endif
#if CACHE_NIDATA_SIZE
/* idata cache */
vol->nidata_cache = ntfs_create_cache("nidata",
ntfs_inode_nidata_free, ntfs_inode_nidata_hash,
sizeof(struct CACHED_NIDATA),
CACHE_NIDATA_SIZE, 2*CACHE_NIDATA_SIZE);
#endif
#if CACHE_LOOKUP_SIZE
/* lookup cache */
vol->lookup_cache = ntfs_create_cache("lookup",
(cache_free)NULL, ntfs_dir_lookup_hash,
sizeof(struct CACHED_LOOKUP),
CACHE_LOOKUP_SIZE, 2*CACHE_LOOKUP_SIZE);
#endif
vol->securid_cache = ntfs_create_cache("securid",(cache_free)NULL,
(cache_hash)NULL,sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE, 0);
#if CACHE_LEGACY_SIZE
vol->legacy_cache = ntfs_create_cache("legacy",(cache_free)NULL,
(cache_hash)NULL, sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE, 0);
#endif
}
/*
* Free all LRU caches
*/
void ntfs_free_lru_caches(ntfs_volume *vol)
{
#if CACHE_INODE_SIZE
ntfs_free_cache(vol->xinode_cache);
#endif
#if CACHE_NIDATA_SIZE
ntfs_free_cache(vol->nidata_cache);
#endif
#if CACHE_LOOKUP_SIZE
ntfs_free_cache(vol->lookup_cache);
#endif
ntfs_free_cache(vol->securid_cache);
#if CACHE_LEGACY_SIZE
ntfs_free_cache(vol->legacy_cache);
#endif
}

View File

@ -23,23 +23,32 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include "attrib.h"
#include "index.h"
#include "collate.h"
#include "debug.h"
#include "unistr.h"
#include "logging.h"
BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr)
{
/*
* FIXME: At the moment we only support COLLATION_BINARY,
* COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return false
* for everything else.
* JPA added COLLATION_NTOFS_SECURITY_HASH
*/
if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG
&& cr != COLLATION_FILE_NAME
&& cr != COLLATION_NTOFS_SECURITY_HASH
&& cr != COLLATION_NTOFS_ULONGS)
return FALSE;
return TRUE;
}
/**
* ntfs_collate_binary - Which of two binary objects should be listed first
* @vol: unused
@ -168,15 +177,15 @@ static int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unus
{
int rc;
u32 d1, d2;
const le32 *p1, *p2;
const u32 *p1, *p2;
ntfs_log_trace("Entering.\n");
if (data1_len != data2_len || data1_len != 8) {
ntfs_log_error("data1_len or/and data2_len not equal to 8.\n");
return NTFS_COLLATION_ERROR;
}
p1 = (const le32*)data1;
p2 = (const le32*)data2;
p1 = (const u32*)data1;
p2 = (const u32*)data2;
d1 = le32_to_cpup(p1);
d2 = le32_to_cpup(p2);
if (d1 < d2)
@ -219,53 +228,89 @@ static int ntfs_collate_file_name(ntfs_volume *vol,
const void *data1, const int data1_len __attribute__((unused)),
const void *data2, const int data2_len __attribute__((unused)))
{
const FILE_NAME_ATTR *file_name_attr1;
const FILE_NAME_ATTR *file_name_attr2;
int rc;
ntfs_log_trace("Entering.\n");
file_name_attr1 = (const FILE_NAME_ATTR*)data1;
file_name_attr2 = (const FILE_NAME_ATTR*)data2;
rc = ntfs_names_full_collate(
(ntfschar*)&file_name_attr1->file_name,
file_name_attr1->file_name_length,
(ntfschar*)&file_name_attr2->file_name,
file_name_attr2->file_name_length,
CASE_SENSITIVE, vol->upcase, vol->upcase_len);
rc = ntfs_file_values_compare(data1, data2, NTFS_COLLATION_ERROR,
IGNORE_CASE, vol->upcase, vol->upcase_len);
if (!rc)
rc = ntfs_file_values_compare(data1, data2,
NTFS_COLLATION_ERROR, CASE_SENSITIVE,
vol->upcase, vol->upcase_len);
ntfs_log_trace("Done, returning %i.\n", rc);
return rc;
}
/*
* Get a pointer to appropriate collation function.
typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, const int,
const void *, const int);
static ntfs_collate_func_t ntfs_do_collate0x0[3] = {
ntfs_collate_binary,
ntfs_collate_file_name,
NULL/*ntfs_collate_unicode_string*/,
};
static ntfs_collate_func_t ntfs_do_collate0x1[4] = {
ntfs_collate_ntofs_ulong,
NULL/*ntfs_collate_ntofs_sid*/,
ntfs_collate_ntofs_security_hash,
ntfs_collate_ntofs_ulongs
};
/**
* ntfs_collate - collate two data items using a specified collation rule
* @vol: ntfs volume to which the data items belong
* @cr: collation rule to use when comparing the items
* @data1: first data item to collate
* @data1_len: length in bytes of @data1
* @data2: second data item to collate
* @data2_len: length in bytes of @data2
*
* Returns NULL if the needed function is not implemented
* Collate the two data items @data1 and @data2 using the collation rule @cr
* and return -1, 0, or 1 if @data1 is found, respectively, to collate before,
* to match, or to collate after @data2.
*
* For speed we use the collation rule @cr as an index into two tables of
* function pointers to call the appropriate collation function.
*
* Return NTFS_COLLATION_ERROR if error occurred.
*/
COLLATE ntfs_get_collate_function(COLLATION_RULES cr)
int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr,
const void *data1, const int data1_len,
const void *data2, const int data2_len)
{
COLLATE collate;
int i;
switch (cr) {
case COLLATION_BINARY :
collate = ntfs_collate_binary;
break;
case COLLATION_FILE_NAME :
collate = ntfs_collate_file_name;
break;
case COLLATION_NTOFS_SECURITY_HASH :
collate = ntfs_collate_ntofs_security_hash;
break;
case COLLATION_NTOFS_ULONG :
collate = ntfs_collate_ntofs_ulong;
break;
case COLLATION_NTOFS_ULONGS :
collate = ntfs_collate_ntofs_ulongs;
break;
default :
errno = EOPNOTSUPP;
collate = (COLLATE)NULL;
break;
ntfs_log_trace("Entering.\n");
if (!vol || !data1 || !data2 || data1_len < 0 || data2_len < 0) {
ntfs_log_error("Invalid arguments passed.\n");
return NTFS_COLLATION_ERROR;
}
return (collate);
/*
* FIXME: At the moment we only support COLLATION_BINARY,
* COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME so we return error
* for everything else.
* JPA added COLLATION_NTOFS_SECURITY_HASH
* JPA added COLLATION_NTOFS_ULONGS
*/
if (cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG
&& cr != COLLATION_FILE_NAME
&& cr != COLLATION_NTOFS_SECURITY_HASH
&& cr != COLLATION_NTOFS_ULONGS)
goto err;
i = le32_to_cpu(cr);
if (i < 0)
goto err;
if (i <= 0x02)
return ntfs_do_collate0x0[i](vol, data1, data1_len,
data2, data2_len);
if (i < 0x10)
goto err;
i -= 0x10;
if (i <= 3)
return ntfs_do_collate0x1[i](vol, data1, data1_len,
data2, data2_len);
err:
ntfs_log_debug("Unknown collation rule.\n");
return NTFS_COLLATION_ERROR;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,8 @@
/**
* device.c - Low level device io functions. Originated from the Linux-NTFS project.
*
* Copyright (c) 2004-2013 Anton Altaparmakov
* Copyright (c) 2004-2006 Anton Altaparmakov
* Copyright (c) 2004-2006 Szabolcs Szakacsits
* Copyright (c) 2010 Jean-Pierre Andre
* Copyright (c) 2008-2013 Tuxera Inc.
*
* 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
@ -59,18 +57,12 @@
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_DISK_H
#include <sys/disk.h>
#endif
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
#ifdef HAVE_LINUX_HDREG_H
#include <linux/hdreg.h>
#endif
#ifdef ENABLE_HD
#include <hd.h>
#endif
#include "types.h"
#include "mst.h"
@ -132,8 +124,6 @@ struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
dev->d_ops = dops;
dev->d_state = state;
dev->d_private = priv_data;
dev->d_heads = -1;
dev->d_sectors_per_track = -1;
}
return dev;
}
@ -164,25 +154,6 @@ int ntfs_device_free(struct ntfs_device *dev)
return 0;
}
/*
* Sync the device
*
* returns zero if successful.
*/
int ntfs_device_sync(struct ntfs_device *dev)
{
int ret;
struct ntfs_device_operations *dops;
if (NDevDirty(dev)) {
dops = dev->d_ops;
ret = dops->sync(dev);
} else
ret = 0;
return ret;
}
/**
* ntfs_pread - positioned read from disk
* @dev: device to read from
@ -289,9 +260,6 @@ s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
total = written;
break;
}
if (NDevSync(dev) && total && dops->sync(dev)) {
total--; /* on sync error, return partially written */
}
ret = total;
out:
return ret;
@ -565,36 +533,6 @@ s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
return (s64)this_floppy.size * 512 / block_size;
}
}
#endif
#ifdef DIOCGMEDIASIZE
{
/* FreeBSD */
off_t size;
if (dev->d_ops->ioctl(dev, DIOCGMEDIASIZE, &size) >= 0) {
ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n",
(unsigned long long)size,
(unsigned long long)size);
return (s64)size / block_size;
}
}
#endif
#ifdef DKIOCGETBLOCKCOUNT
{
/* Mac OS X */
uint64_t blocks;
int sector_size;
sector_size = ntfs_device_sector_size_get(dev);
if (sector_size >= 0 && dev->d_ops->ioctl(dev,
DKIOCGETBLOCKCOUNT, &blocks) >= 0)
{
ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n",
(unsigned long long) blocks,
(unsigned long long) blocks);
return blocks * sector_size / block_size;
}
}
#endif
/*
* We couldn't figure it out by using a specialized ioctl,
@ -648,132 +586,6 @@ s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
return -1;
}
static int ntfs_device_get_geo(struct ntfs_device *dev)
{
int err;
if (!dev) {
errno = EINVAL;
return -1;
}
err = EOPNOTSUPP;
#ifdef ENABLE_HD
{
hd_data_t *hddata;
hd_t *hd, *devlist, *partlist = NULL;
str_list_t *names;
hd_res_t *res;
const int d_name_len = strlen(dev->d_name) + 1;
int done = 0;
hddata = calloc(1, sizeof(*hddata));
if (!hddata) {
err = ENOMEM;
goto skip_hd;
}
/* List all "disk" class devices on the system. */
devlist = hd_list(hddata, hw_disk, 1, NULL);
if (!devlist) {
free(hddata);
err = ENOMEM;
goto skip_hd;
}
/*
* Loop over each disk device looking for the device with the
* same unix name as @dev.
*/
for (hd = devlist; hd; hd = hd->next) {
if (hd->unix_dev_name && !strncmp(dev->d_name,
hd->unix_dev_name, d_name_len))
goto got_hd;
if (hd->unix_dev_name2 && !strncmp(dev->d_name,
hd->unix_dev_name2, d_name_len))
goto got_hd;
for (names = hd->unix_dev_names; names;
names = names->next) {
if (names->str && !strncmp(dev->d_name,
names->str, d_name_len))
goto got_hd;
}
}
/*
* Device was not a whole disk device. Unless it is a file it
* is likely to be a partition device. List all "partition"
* class devices on the system.
*/
partlist = hd_list(hddata, hw_partition, 1, NULL);
for (hd = partlist; hd; hd = hd->next) {
if (hd->unix_dev_name && !strncmp(dev->d_name,
hd->unix_dev_name, d_name_len))
goto got_part_hd;
if (hd->unix_dev_name2 && !strncmp(dev->d_name,
hd->unix_dev_name2, d_name_len))
goto got_part_hd;
for (names = hd->unix_dev_names; names;
names = names->next) {
if (names->str && !strncmp(dev->d_name,
names->str, d_name_len))
goto got_part_hd;
}
}
/* Failed to find the device. Stop trying and clean up. */
goto end_hd;
got_part_hd:
/* Get the whole block device the partition device is on. */
hd = hd_get_device_by_idx(hddata, hd->attached_to);
if (!hd)
goto end_hd;
got_hd:
/*
* @hd is now the whole block device either being formatted or
* that the partition being formatted is on.
*
* Loop over each resource of the disk device looking for the
* BIOS legacy geometry obtained from EDD which is what Windows
* needs to boot.
*/
for (res = hd->res; res; res = res->next) {
/* geotype 3 is BIOS legacy. */
if (res->any.type != res_disk_geo ||
res->disk_geo.geotype != 3)
continue;
dev->d_heads = res->disk_geo.heads;
dev->d_sectors_per_track = res->disk_geo.sectors;
done = 1;
}
end_hd:
if (partlist)
hd_free_hd_list(partlist);
hd_free_hd_list(devlist);
hd_free_hd_data(hddata);
free(hddata);
if (done) {
ntfs_log_debug("EDD/BIOD legacy heads = %u, sectors "
"per track = %u\n", dev->d_heads,
dev->d_sectors_per_track);
return 0;
}
}
skip_hd:
#endif
#ifdef HDIO_GETGEO
{ struct hd_geometry geo;
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
dev->d_heads = geo.heads;
dev->d_sectors_per_track = geo.sectors;
ntfs_log_debug("HDIO_GETGEO heads = %u, sectors per "
"track = %u\n", dev->d_heads,
dev->d_sectors_per_track);
return 0;
}
err = errno;
}
#endif
errno = err;
return -1;
}
/**
* ntfs_device_heads_get - get number of heads of device
* @dev: open device
@ -785,7 +597,6 @@ skip_hd:
* EINVAL Input parameter error
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
* ENOMEM Not enough memory to complete the request
*/
int ntfs_device_heads_get(struct ntfs_device *dev)
{
@ -793,15 +604,20 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
errno = EINVAL;
return -1;
}
if (dev->d_heads == -1) {
if (ntfs_device_get_geo(dev) == -1)
return -1;
if (dev->d_heads == -1) {
errno = EINVAL;
return -1;
#ifdef HDIO_GETGEO
{ struct hd_geometry geo;
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
(unsigned)geo.heads,
(unsigned)geo.heads);
return geo.heads;
}
}
return dev->d_heads;
#else
errno = EOPNOTSUPP;
#endif
return -1;
}
/**
@ -815,7 +631,6 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
* EINVAL Input parameter error
* EOPNOTSUPP System does not support HDIO_GETGEO ioctl
* ENOTTY @dev is a file or a device not supporting HDIO_GETGEO
* ENOMEM Not enough memory to complete the request
*/
int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
{
@ -823,15 +638,20 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
errno = EINVAL;
return -1;
}
if (dev->d_sectors_per_track == -1) {
if (ntfs_device_get_geo(dev) == -1)
return -1;
if (dev->d_sectors_per_track == -1) {
errno = EINVAL;
return -1;
#ifdef HDIO_GETGEO
{ struct hd_geometry geo;
if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
(unsigned)geo.sectors,
(unsigned)geo.sectors);
return geo.sectors;
}
}
return dev->d_sectors_per_track;
#else
errno = EOPNOTSUPP;
#endif
return -1;
}
/**
@ -862,28 +682,6 @@ int ntfs_device_sector_size_get(struct ntfs_device *dev)
return sect_size;
}
}
#elif defined(DIOCGSECTORSIZE)
{
/* FreeBSD */
size_t sect_size = 0;
if (!dev->d_ops->ioctl(dev, DIOCGSECTORSIZE, &sect_size)) {
ntfs_log_debug("DIOCGSECTORSIZE sector size = %d bytes\n",
(int) sect_size);
return sect_size;
}
}
#elif defined(DKIOCGETBLOCKSIZE)
{
/* Mac OS X */
uint32_t sect_size = 0;
if (!dev->d_ops->ioctl(dev, DKIOCGETBLOCKSIZE, &sect_size)) {
ntfs_log_debug("DKIOCGETBLOCKSIZE sector size = %d bytes\n",
(int) sect_size);
return sect_size;
}
}
#else
errno = EOPNOTSUPP;
#endif

View File

@ -0,0 +1,38 @@
/*
* device_io.c - Default device io operations. Originated from the Linux-NTFS project.
*
* Copyright (c) 2003 Anton Altaparmakov
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
#ifndef __CYGWIN32__
/* Not on Cygwin; use standard Unix style low level device operations. */
#include "unix_io.c"
#else /* __CYGWIN32__ */
/* On Cygwin; use Win32 low level device operations. */
#include "win32_io.c"
#endif /* __CYGWIN32__ */
#endif /* NO_NTFS_DEVICE_DEFAULT_IO_OPS */

File diff suppressed because it is too large Load Diff

View File

@ -1,519 +0,0 @@
/**
* ea.c - Processing of EA's
*
* This module is part of ntfs-3g library
*
* Copyright (c) 2014-2021 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
#ifdef MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#endif
#include "types.h"
#include "param.h"
#include "layout.h"
#include "attrib.h"
#include "index.h"
#include "dir.h"
#include "ea.h"
#include "misc.h"
#include "logging.h"
#include "xattrs.h"
static const char lxdev[] = "$LXDEV";
static const char lxmod[] = "$LXMOD";
/*
* Create a needed attribute (EA or EA_INFORMATION)
*
* Returns 0 if successful,
* -1 otherwise, with errno indicating why it failed.
*/
static int ntfs_need_ea(ntfs_inode *ni, ATTR_TYPES type, int size, int flags)
{
u8 dummy;
int res;
res = 0;
if (!ntfs_attr_exist(ni,type, AT_UNNAMED,0)) {
if (!(flags & XATTR_REPLACE)) {
/*
* no needed attribute : add one,
* apparently, this does not feed the new value in
* Note : NTFS version must be >= 3
*/
if (ni->vol->major_ver >= 3) {
res = ntfs_attr_add(ni, type,
AT_UNNAMED,0,&dummy,(s64)size);
if (!res) {
NInoFileNameSetDirty(ni);
}
NInoSetDirty(ni);
} else {
errno = EOPNOTSUPP;
res = -1;
}
} else {
errno = ENODATA;
res = -1;
}
}
return (res);
}
/*
* Restore the old EA_INFORMATION or delete the current one,
* when EA cannot be updated.
*
* As this is used in the context of some other error, the caller
* is responsible for returning the proper error, and errno is
* left unchanged.
* Only double errors are logged here.
*/
static void restore_ea_info(ntfs_attr *nai, const EA_INFORMATION *old_ea_info)
{
s64 written;
int olderrno;
olderrno = errno;
if (old_ea_info) {
written = ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
old_ea_info);
if ((size_t)written != sizeof(EA_INFORMATION)) {
ntfs_log_error("Could not restore the EA_INFORMATION,"
" possible inconsistency in inode %lld\n",
(long long)nai->ni->mft_no);
}
} else {
if (ntfs_attr_rm(nai)) {
ntfs_log_error("Could not delete the EA_INFORMATION,"
" possible inconsistency in inode %lld\n",
(long long)nai->ni->mft_no);
}
}
errno = olderrno;
}
/*
* Update both EA and EA_INFORMATION
*/
static int ntfs_update_ea(ntfs_inode *ni, const char *value, size_t size,
const EA_INFORMATION *ea_info,
const EA_INFORMATION *old_ea_info)
{
ntfs_attr *na;
ntfs_attr *nai;
int res;
res = 0;
nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
if (nai) {
na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
if (na) {
/*
* Set EA_INFORMATION first, it is easier to
* restore the old value, if setting EA fails.
*/
if (ntfs_attr_pwrite(nai, 0, sizeof(EA_INFORMATION),
ea_info)
!= (s64)sizeof(EA_INFORMATION)) {
res = -errno;
} else {
if (((na->data_size > (s64)size)
&& ntfs_attr_truncate(na, size))
|| (ntfs_attr_pwrite(na, 0, size, value)
!= (s64)size)) {
res = -errno;
if (old_ea_info)
restore_ea_info(nai,
old_ea_info);
}
}
ntfs_attr_close(na);
}
ntfs_attr_close(nai);
} else {
res = -errno;
}
return (res);
}
/*
* Return the existing EA
*
* The EA_INFORMATION is not examined and the consistency of the
* existing EA is not checked.
*
* If successful, the full attribute is returned unchanged
* and its size is returned.
* If the designated buffer is too small, the needed size is
* returned, and the buffer is left unchanged.
* If there is an error, a negative value is returned and errno
* is set according to the error.
*/
int ntfs_get_ntfs_ea(ntfs_inode *ni, char *value, size_t size)
{
s64 ea_size;
void *ea_buf;
int res = 0;
if (ntfs_attr_exist(ni, AT_EA, AT_UNNAMED, 0)) {
ea_buf = ntfs_attr_readall(ni, AT_EA, (ntfschar*)NULL, 0,
&ea_size);
if (ea_buf) {
if (value && (ea_size <= (s64)size))
memcpy(value, ea_buf, ea_size);
free(ea_buf);
res = ea_size;
} else {
ntfs_log_error("Failed to read EA from inode %lld\n",
(long long)ni->mft_no);
errno = ENODATA;
res = -errno;
}
} else {
errno = ENODATA;
res = -errno;
}
return (res);
}
/*
* Set a new EA, and set EA_INFORMATION accordingly
*
* This is roughly the same as ZwSetEaFile() on Windows, however
* the "offset to next" of the last EA should not be cleared.
*
* Consistency of the new EA is first checked.
*
* EA_INFORMATION is set first, and it is restored to its former
* state if setting EA fails.
*
* Returns 0 if successful
* a negative value if an error occurred.
*/
int ntfs_set_ntfs_ea(ntfs_inode *ni, const char *value, size_t size, int flags)
{
EA_INFORMATION ea_info;
EA_INFORMATION *old_ea_info;
s64 old_ea_size;
int res;
size_t offs;
size_t nextoffs;
BOOL ok;
int ea_count;
int ea_packed;
const EA_ATTR *p_ea;
res = -1;
if (value && (size > 0)) {
/* do consistency checks */
offs = 0;
ok = TRUE;
ea_count = 0;
ea_packed = 0;
nextoffs = 0;
while (ok && (offs < size)) {
p_ea = (const EA_ATTR*)&value[offs];
nextoffs = offs + le32_to_cpu(p_ea->next_entry_offset);
/* null offset to next not allowed */
ok = (nextoffs > offs)
&& (nextoffs <= size)
&& !(nextoffs & 3)
&& p_ea->name_length
/* zero sized value are allowed */
&& ((offs + offsetof(EA_ATTR,name)
+ p_ea->name_length + 1
+ le16_to_cpu(p_ea->value_length))
<= nextoffs)
&& ((offs + offsetof(EA_ATTR,name)
+ p_ea->name_length + 1
+ le16_to_cpu(p_ea->value_length))
>= (nextoffs - 3))
&& !p_ea->name[p_ea->name_length];
/* name not checked, as chkdsk accepts any chars */
if (ok) {
if (p_ea->flags & NEED_EA)
ea_count++;
/*
* Assume ea_packed includes :
* 4 bytes for header (flags and lengths)
* + name length + 1
* + value length
*/
ea_packed += 5 + p_ea->name_length
+ le16_to_cpu(p_ea->value_length);
offs = nextoffs;
}
}
/*
* EA and REPARSE_POINT compatibility not checked any more,
* required by Windows 10, but having both may lead to
* problems with earlier versions.
*/
if (ok) {
ea_info.ea_length = cpu_to_le16(ea_packed);
ea_info.need_ea_count = cpu_to_le16(ea_count);
ea_info.ea_query_length = cpu_to_le32(nextoffs);
old_ea_size = 0;
old_ea_info = NULL;
/* Try to save the old EA_INFORMATION */
if (ntfs_attr_exist(ni, AT_EA_INFORMATION,
AT_UNNAMED, 0)) {
old_ea_info = ntfs_attr_readall(ni,
AT_EA_INFORMATION,
(ntfschar*)NULL, 0, &old_ea_size);
}
/*
* no EA or EA_INFORMATION : add them
*/
if (!ntfs_need_ea(ni, AT_EA_INFORMATION,
sizeof(EA_INFORMATION), flags)
&& !ntfs_need_ea(ni, AT_EA, 0, flags)) {
res = ntfs_update_ea(ni, value, size,
&ea_info, old_ea_info);
} else {
res = -errno;
}
if (old_ea_info)
free(old_ea_info);
} else {
errno = EINVAL;
res = -errno;
}
} else {
errno = EINVAL;
res = -errno;
}
return (res);
}
/*
* Remove the EA (including EA_INFORMATION)
*
* EA_INFORMATION is removed first, and it is restored to its former
* state if removing EA fails.
*
* Returns 0, or -1 if there is a problem
*/
int ntfs_remove_ntfs_ea(ntfs_inode *ni)
{
EA_INFORMATION *old_ea_info;
s64 old_ea_size;
int res;
ntfs_attr *na;
ntfs_attr *nai;
res = 0;
if (ni) {
/*
* open and delete the EA_INFORMATION and the EA
*/
nai = ntfs_attr_open(ni, AT_EA_INFORMATION, AT_UNNAMED, 0);
if (nai) {
na = ntfs_attr_open(ni, AT_EA, AT_UNNAMED, 0);
if (na) {
/* Try to save the old EA_INFORMATION */
old_ea_info = ntfs_attr_readall(ni,
AT_EA_INFORMATION,
(ntfschar*)NULL, 0, &old_ea_size);
res = ntfs_attr_rm(na);
NInoFileNameSetDirty(ni);
if (!res) {
res = ntfs_attr_rm(nai);
if (res && old_ea_info) {
/*
* Failed to remove the EA, try to
* restore the EA_INFORMATION
*/
restore_ea_info(nai,
old_ea_info);
}
} else {
ntfs_log_error("Failed to remove the"
" EA_INFORMATION from inode %lld\n",
(long long)ni->mft_no);
}
free(old_ea_info);
ntfs_attr_close(na);
} else {
/* EA_INFORMATION present, but no EA */
res = ntfs_attr_rm(nai);
NInoFileNameSetDirty(ni);
}
ntfs_attr_close(nai);
} else {
errno = ENODATA;
res = -1;
}
NInoSetDirty(ni);
} else {
errno = EINVAL;
res = -1;
}
return (res ? -1 : 0);
}
/*
* Check for the presence of an EA "$LXDEV" (used by WSL)
* and return its value as a device address
*
* Returns zero if successful
* -1 if failed, with errno set
*/
int ntfs_ea_check_wsldev(ntfs_inode *ni, dev_t *rdevp)
{
const EA_ATTR *p_ea;
int bufsize;
char *buf;
int lth;
int res;
int offset;
int next;
BOOL found;
struct {
le32 major;
le32 minor;
} device;
res = -EOPNOTSUPP;
bufsize = 256; /* expected to be enough */
buf = (char*)malloc(bufsize);
if (buf) {
lth = ntfs_get_ntfs_ea(ni, buf, bufsize);
/* retry if short buf */
if (lth > bufsize) {
free(buf);
bufsize = lth;
buf = (char*)malloc(bufsize);
if (buf)
lth = ntfs_get_ntfs_ea(ni, buf, bufsize);
}
}
if (buf && (lth > 0) && (lth <= bufsize)) {
offset = 0;
found = FALSE;
do {
p_ea = (const EA_ATTR*)&buf[offset];
next = le32_to_cpu(p_ea->next_entry_offset);
found = ((next > (int)(sizeof(lxdev) + sizeof(device)))
&& (p_ea->name_length == (sizeof(lxdev) - 1))
&& (p_ea->value_length
== const_cpu_to_le16(sizeof(device)))
&& !memcmp(p_ea->name, lxdev, sizeof(lxdev)));
if (!found)
offset += next;
} while (!found && (next > 0) && (offset < lth));
if (found) {
/* beware of alignment */
memcpy(&device, &p_ea->name[p_ea->name_length + 1],
sizeof(device));
*rdevp = makedev(le32_to_cpu(device.major),
le32_to_cpu(device.minor));
res = 0;
}
}
free(buf);
return (res);
}
int ntfs_ea_set_wsl_not_symlink(ntfs_inode *ni, mode_t type, dev_t dev)
{
le32 mode;
struct {
le32 major;
le32 minor;
} device;
struct EA_WSL {
struct EA_LXMOD { /* always inserted */
EA_ATTR base;
char name[sizeof(lxmod)];
char value[sizeof(mode)];
char stuff[3 & -(sizeof(lxmod) + sizeof(mode))];
} mod;
struct EA_LXDEV { /* char or block devices only */
EA_ATTR base;
char name[sizeof(lxdev)];
char value[sizeof(device)];
char stuff[3 & -(sizeof(lxdev) + sizeof(device))];
} dev;
} attr;
int len;
int res;
memset(&attr, 0, sizeof(attr));
mode = cpu_to_le32((u32)(type | 0644));
attr.mod.base.next_entry_offset
= const_cpu_to_le32(sizeof(attr.mod));
attr.mod.base.flags = 0;
attr.mod.base.name_length = sizeof(lxmod) - 1;
attr.mod.base.value_length = const_cpu_to_le16(sizeof(mode));
memcpy(attr.mod.name, lxmod, sizeof(lxmod));
memcpy(attr.mod.value, &mode, sizeof(mode));
len = sizeof(attr.mod);
if (S_ISCHR(type) || S_ISBLK(type)) {
device.major = cpu_to_le32(major(dev));
device.minor = cpu_to_le32(minor(dev));
attr.dev.base.next_entry_offset
= const_cpu_to_le32(sizeof(attr.dev));
attr.dev.base.flags = 0;
attr.dev.base.name_length = sizeof(lxdev) - 1;
attr.dev.base.value_length = const_cpu_to_le16(sizeof(device));
memcpy(attr.dev.name, lxdev, sizeof(lxdev));
memcpy(attr.dev.value, &device, sizeof(device));
len += sizeof(attr.dev);
}
res = ntfs_set_ntfs_ea(ni, (char*)&attr, len, 0);
return (res);
}

View File

@ -4,7 +4,7 @@
* This module is part of ntfs-3g library
*
* Copyright (c) 2009 Martin Bene
* Copyright (c) 2009-2010 Jean-Pierre Andre
* Copyright (c) 2009 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
@ -39,6 +39,10 @@
#include <sys/stat.h>
#endif
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
@ -53,7 +57,8 @@
#include "logging.h"
#include "misc.h"
#include "efs.h"
#include "xattrs.h"
#ifdef HAVE_SETXATTR /* extended attributes interface required */
static ntfschar logged_utility_stream_name[] = {
const_cpu_to_le16('$'),
@ -68,7 +73,8 @@ static ntfschar logged_utility_stream_name[] = {
* Get the ntfs EFS info into an extended attribute
*/
int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
int ntfs_get_efs_info(const char *path,
char *value, size_t size, ntfs_inode *ni)
{
EFS_ATTR_HEADER *efs_info;
s64 attr_size = 0;
@ -96,131 +102,43 @@ int ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
} else {
if (efs_info) {
free(efs_info);
ntfs_log_error("Bad efs_info for inode %lld\n",
(long long)ni->mft_no);
ntfs_log_info("Bad efs_info for file %s\n",path);
} else {
ntfs_log_error("Could not get efsinfo"
" for inode %lld\n",
(long long)ni->mft_no);
ntfs_log_info("Could not get efsinfo"
" for file %s\n", path);
}
errno = EIO;
attr_size = 0;
}
} else {
errno = ENODATA;
ntfs_log_trace("Inode %lld is not encrypted\n",
(long long)ni->mft_no);
ntfs_log_info("File %s is not encrypted",path);
}
}
return (attr_size ? (int)attr_size : -errno);
}
/*
* Fix all encrypted AT_DATA attributes of an inode
*
* The fix may require making an attribute non resident, which
* requires more space in the MFT record, and may cause some
* attribute to be expelled and the full record to be reorganized.
* When this happens, the search for data attributes has to be
* reinitialized.
*
* Returns zero if successful.
* -1 if there is a problem.
*/
static int fixup_loop(ntfs_inode *ni)
{
ntfs_attr_search_ctx *ctx;
ntfs_attr *na;
ATTR_RECORD *a;
BOOL restart;
int cnt;
int maxcnt;
int res = 0;
maxcnt = 0;
do {
restart = FALSE;
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) {
ntfs_log_error("Failed to get ctx for efs\n");
res = -1;
}
cnt = 0;
while (!restart && !res
&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
cnt++;
a = ctx->attr;
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
a->name_length);
if (!na) {
ntfs_log_error("can't open DATA Attribute\n");
res = -1;
}
if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
if (!NAttrNonResident(na)
&& ntfs_attr_make_non_resident(na, ctx)) {
/*
* ntfs_attr_make_non_resident fails if there
* is not enough space in the MFT record.
* When this happens, force making non-resident
* so that some other attribute is expelled.
*/
if (ntfs_attr_force_non_resident(na)) {
res = -1;
} else {
/* make sure there is some progress */
if (cnt <= maxcnt) {
errno = EIO;
ntfs_log_error("Multiple failure"
" making non resident\n");
res = -1;
} else {
ntfs_attr_put_search_ctx(ctx);
ctx = (ntfs_attr_search_ctx*)NULL;
restart = TRUE;
maxcnt = cnt;
}
}
}
if (!restart && !res
&& ntfs_efs_fixup_attribute(ctx, na)) {
ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
res = -1;
}
}
if (na)
ntfs_attr_close(na);
}
} while (restart && !res);
if (ctx)
ntfs_attr_put_search_ctx(ctx);
return (res);
}
/*
* Set the efs data from an extended attribute
* Warning : the new data is not checked
* Returns 0, or -1 if there is a problem
*/
int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
int flags)
int ntfs_set_efs_info(const char *path __attribute__((unused)),
const char *value, size_t size, int flags,
ntfs_inode *ni)
{
int res;
int written;
ntfs_attr *na;
const EFS_ATTR_HEADER *info_header;
ntfs_attr_search_ctx *ctx;
res = 0;
if (ni && value && size) {
if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
if (ni->flags & FILE_ATTR_ENCRYPTED) {
ntfs_log_trace("Inode %lld already encrypted\n",
(long long)ni->mft_no);
ntfs_log_info("File %s already encrypted",path);
errno = EEXIST;
} else {
/*
@ -229,8 +147,8 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
* restored as compressed.
* TODO : decompress first.
*/
ntfs_log_error("Inode %lld cannot be encrypted and compressed\n",
(long long)ni->mft_no);
ntfs_log_error("File %s cannot be encrypted and compressed\n",
path);
errno = EIO;
}
return -1;
@ -289,8 +207,20 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
/* iterate over AT_DATA attributes */
/* set encrypted flag, truncate attribute to match padding bytes */
if (fixup_loop(ni))
return -1;
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) {
ntfs_log_error("Failed to get ctx for efs\n");
return (-1);
}
while (!ntfs_attr_lookup(AT_DATA, NULL, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
if (ntfs_efs_fixup_attribute(ctx, NULL)) {
ntfs_log_error("Error in efs fixup of AT_DATA Attribute");
ntfs_attr_put_search_ctx(ctx);
return(-1);
}
}
ntfs_attr_put_search_ctx(ctx);
}
ni->flags |= FILE_ATTR_ENCRYPTED;
NInoSetDirty(ni);
@ -316,15 +246,16 @@ int ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
{
s64 newsize;
s64 oldsize;
u64 newsize;
le16 appended_bytes;
u16 padding_length;
ATTR_RECORD *a;
ntfs_inode *ni;
BOOL close_na = FALSE;
BOOL close_ctx = FALSE;
if (!na) {
ntfs_log_error("no na specified for efs_fixup_attribute\n");
if (!ctx && !na) {
ntfs_log_error("neither ctx nor na specified for efs_fixup_attribute\n");
goto err_out;
}
if (!ctx) {
@ -333,79 +264,55 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
ntfs_log_error("Failed to get ctx for efs\n");
goto err_out;
}
close_ctx = TRUE;
close_ctx=TRUE;
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
goto err_out;
}
} else {
if (!NAttrNonResident(na)) {
ntfs_log_error("Cannot make non resident"
" when a context has been allocated\n");
goto err_out;
}
}
/* no extra bytes are added to void attributes */
oldsize = na->data_size;
if (oldsize) {
a = ctx->attr;
if (!na) {
na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
a->name_length);
if (!na) {
ntfs_log_error("can't open DATA Attribute\n");
return (-1);
}
close_na = TRUE;
}
/* make sure size is valid for a raw encrypted stream */
if ((oldsize & 511) != 2) {
ntfs_log_error("Bad raw encrypted stream\n");
goto err_out;
}
/* read padding length from last two bytes of attribute */
if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
ntfs_log_error("Error reading padding length\n");
goto err_out;
}
padding_length = le16_to_cpu(appended_bytes);
if (padding_length > 511 || padding_length > na->data_size-2) {
errno = EINVAL;
ntfs_log_error("invalid padding length %d for data_size %lld\n",
padding_length, (long long)oldsize);
goto err_out;
}
newsize = oldsize - padding_length - 2;
/*
* truncate attribute to possibly free clusters allocated
* for the last two bytes, but do not truncate to new size
* to avoid losing useful data
*/
if (ntfs_attr_truncate(na, oldsize - 2)) {
ntfs_log_error("Error truncating attribute\n");
goto err_out;
}
} else
newsize = 0;
if ((na->data_size & 511) != 2) {
ntfs_log_error("Bad raw encrypted stream");
goto err_out;
}
/* read padding length from last two bytes of attribute */
if (ntfs_attr_pread(na, na->data_size-2, 2, &appended_bytes) != 2) {
ntfs_log_error("Error reading padding length\n");
goto err_out;
}
padding_length = le16_to_cpu(appended_bytes);
if (padding_length > 511 || padding_length > na->data_size-2) {
errno = EINVAL;
ntfs_log_error("invalid padding length %d for data_size %lld\n",
padding_length, (long long)na->data_size);
goto err_out;
}
newsize = na->data_size - padding_length - 2;
/* truncate attribute to possibly free clusters allocated
for the last two bytes */
if (ntfs_attr_truncate(na, na->data_size-2)) {
ntfs_log_error("Error truncating attribute\n");
goto err_out;
}
/*
* Encrypted AT_DATA Attributes MUST be non-resident
* This has to be done after the attribute is resized, as
* resizing down to zero may cause the attribute to be made
* resident.
*/
/* Encrypted AT_DATA Attributes MUST be non-resident */
if (!NAttrNonResident(na)
&& ntfs_attr_make_non_resident(na, ctx)) {
if (!close_ctx
|| ntfs_attr_force_non_resident(na)) {
ntfs_log_error("Error making DATA attribute non-resident\n");
goto err_out;
} else {
/*
* must reinitialize context after forcing
* non-resident. We need a context for updating
* the state, and at this point, we are sure
* the context is not used elsewhere.
*/
ntfs_attr_reinit_search_ctx(ctx);
if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
goto err_out;
}
}
&& ntfs_attr_make_non_resident(na, ctx)) {
ntfs_log_error("Error making DATA attribute non-resident\n");
goto err_out;
}
ni = na->ni;
if (!na->name_len) {
@ -414,9 +321,11 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
}
NInoSetDirty(ni);
NInoFileNameSetDirty(ni);
if (close_na)
ntfs_attr_close(na);
ctx->attr->data_size = cpu_to_sle64(newsize);
if (sle64_to_cpu(ctx->attr->initialized_size) > newsize)
ctx->attr->data_size = cpu_to_le64(newsize);
if (le64_to_cpu(ctx->attr->initialized_size) > newsize)
ctx->attr->initialized_size = ctx->attr->data_size;
ctx->attr->flags |= ATTR_IS_ENCRYPTED;
if (close_ctx)
@ -424,7 +333,11 @@ int ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
return (0);
err_out:
if (close_na && na)
ntfs_attr_close(na);
if (close_ctx && ctx)
ntfs_attr_put_search_ctx(ctx);
return (-1);
}
#endif /* HAVE_SETXATTR */

View File

@ -5,7 +5,7 @@
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2005-2006 Yura Pakhuchiy
* Copyright (c) 2005-2008 Szabolcs Szakacsits
* Copyright (c) 2007-2021 Jean-Pierre Andre
* Copyright (c) 2007 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
@ -38,9 +38,9 @@
#endif
#include "attrib.h"
#include "collate.h"
#include "debug.h"
#include "index.h"
#include "collate.h"
#include "mst.h"
#include "dir.h"
#include "logging.h"
@ -66,9 +66,8 @@ void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
{
if (ictx->is_in_root)
ntfs_inode_mark_dirty(ictx->actx->ntfs_ino);
else if (ictx->ib != NULL) {
else
ictx->ib_dirty = TRUE;
}
}
static s64 ntfs_ib_vcn_to_pos(ntfs_index_context *icx, VCN vcn)
@ -144,7 +143,7 @@ static void ntfs_index_ctx_free(ntfs_index_context *icx)
{
ntfs_log_trace("Entering\n");
if (!icx->bad_index && !icx->entry)
if (!icx->entry)
return;
if (icx->actx)
@ -192,9 +191,9 @@ void ntfs_index_ctx_reinit(ntfs_index_context *icx)
};
}
static leVCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie)
static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie)
{
return (leVCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(leVCN));
return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN));
}
/**
@ -339,7 +338,7 @@ static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie)
static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn)
{
*ntfs_ie_get_vcn_addr(ie) = cpu_to_sle64(vcn);
*ntfs_ie_get_vcn_addr(ie) = cpu_to_le64(vcn);
}
/**
@ -389,6 +388,42 @@ static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
return dup;
}
static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
{
u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18;
ntfs_log_trace("Entering\n");
if (!ntfs_is_indx_record(ib->magic)) {
ntfs_log_error("Corrupt index block signature: vcn %lld inode "
"%llu\n", (long long)vcn,
(unsigned long long)icx->ni->mft_no);
return -1;
}
if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
ntfs_log_error("Corrupt index block: VCN (%lld) is different "
"from expected VCN (%lld) in inode %llu\n",
(long long)sle64_to_cpu(ib->index_block_vcn),
(long long)vcn,
(unsigned long long)icx->ni->mft_no);
return -1;
}
if (ib_size != icx->block_size) {
ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu "
"has a size (%u) differing from the index "
"specified size (%u)\n", (long long)vcn,
(unsigned long long)icx->ni->mft_no, ib_size,
icx->block_size);
return -1;
}
return 0;
}
static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
u32 name_len, ntfs_attr_search_ctx **ctx)
{
@ -434,133 +469,6 @@ static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len)
return ir;
}
/*
* Check the consistency of an index block
*
* Make sure the index block does not overflow from the index record.
* The size of block is assumed to have been checked to be what is
* defined in the index root.
*
* Returns 0 if no error was found
* -1 otherwise (with errno unchanged)
*
* |<--->| offsetof(INDEX_BLOCK, index)
* | |<--->| sizeof(INDEX_HEADER)
* | | |
* | | | seq index entries unused
* |=====|=====|=====|===========================|==============|
* | | | | |
* | |<--------->| entries_offset | |
* | |<---------------- index_length ------->| |
* | |<--------------------- allocated_size --------------->|
* |<--------------------------- block_size ------------------->|
*
* size(INDEX_HEADER) <= ent_offset < ind_length <= alloc_size < bk_size
*/
int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size,
u64 inum, VCN vcn)
{
u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size)
+ offsetof(INDEX_BLOCK, index);
if (!ntfs_is_indx_record(ib->magic)) {
ntfs_log_error("Corrupt index block signature: vcn %lld inode "
"%llu\n", (long long)vcn,
(unsigned long long)inum);
return -1;
}
if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
ntfs_log_error("Corrupt index block: VCN (%lld) is different "
"from expected VCN (%lld) in inode %llu\n",
(long long)sle64_to_cpu(ib->index_block_vcn),
(long long)vcn,
(unsigned long long)inum);
return -1;
}
if (ib_size != block_size) {
ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu "
"has a size (%u) differing from the index "
"specified size (%u)\n", (long long)vcn,
(unsigned long long)inum, ib_size,
(unsigned int)block_size);
return -1;
}
if (le32_to_cpu(ib->index.entries_offset) < sizeof(INDEX_HEADER)) {
ntfs_log_error("Invalid index entry offset in inode %lld\n",
(unsigned long long)inum);
return -1;
}
if (le32_to_cpu(ib->index.index_length)
<= le32_to_cpu(ib->index.entries_offset)) {
ntfs_log_error("No space for index entries in inode %lld\n",
(unsigned long long)inum);
return -1;
}
if (le32_to_cpu(ib->index.allocated_size)
< le32_to_cpu(ib->index.index_length)) {
ntfs_log_error("Index entries overflow in inode %lld\n",
(unsigned long long)inum);
return -1;
}
return (0);
}
/*
* Check the consistency of an index entry
*
* Make sure data and key do not overflow from entry.
* As a side effect, an entry with zero length is rejected.
* This entry must be a full one (no INDEX_ENTRY_END flag), and its
* length must have been checked beforehand to not overflow from the
* index record.
*
* Returns 0 if no error was found
* -1 otherwise (with errno unchanged)
*/
int ntfs_index_entry_inconsistent(const INDEX_ENTRY *ie,
COLLATION_RULES collation_rule, u64 inum)
{
int ret;
ret = 0;
if (ie->key_length
&& ((le16_to_cpu(ie->key_length) + offsetof(INDEX_ENTRY, key))
> le16_to_cpu(ie->length))) {
ntfs_log_error("Overflow from index entry in inode %lld\n",
(long long)inum);
ret = -1;
} else
if (collation_rule == COLLATION_FILE_NAME) {
if ((offsetof(INDEX_ENTRY, key.file_name.file_name)
+ ie->key.file_name.file_name_length
* sizeof(ntfschar))
> le16_to_cpu(ie->length)) {
ntfs_log_error("File name overflow from index"
" entry in inode %lld\n",
(long long)inum);
ret = -1;
}
} else {
if (ie->data_length
&& ((le16_to_cpu(ie->data_offset)
+ le16_to_cpu(ie->data_length))
> le16_to_cpu(ie->length))) {
ntfs_log_error("Data overflow from index"
" entry in inode %lld\n",
(long long)inum);
ret = -1;
}
}
return (ret);
}
/**
* Find a key in the index block.
*
@ -609,19 +517,8 @@ static int ntfs_ie_lookup(const void *key, const int key_len,
* Not a perfect match, need to do full blown collation so we
* know which way in the B+tree we have to go.
*/
if (!icx->collate) {
ntfs_log_error("Collation function not defined\n");
errno = EOPNOTSUPP;
return STATUS_ERROR;
}
/* Make sure key and data do not overflow from entry */
if (ntfs_index_entry_inconsistent(ie, icx->ir->collation_rule,
icx->ni->mft_no)) {
errno = EIO;
return STATUS_ERROR;
}
rc = icx->collate(icx->ni->vol, key, key_len,
&ie->key, le16_to_cpu(ie->key_length));
rc = ntfs_collate(icx->ni->vol, icx->cr, key, key_len, &ie->key,
le16_to_cpu(ie->key_length));
if (rc == NTFS_COLLATION_ERROR) {
ntfs_log_error("Collation error. Perhaps a filename "
"contains invalid characters?\n");
@ -704,11 +601,8 @@ static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
return -1;
}
if (ntfs_index_block_inconsistent((INDEX_BLOCK*)dst, icx->block_size,
icx->ia_na->ni->mft_no, vcn)) {
errno = EIO;
if (ntfs_ia_check(icx, dst, vcn))
return -1;
}
return 0;
}
@ -802,22 +696,25 @@ int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *ic
if (ni->vol->cluster_size <= icx->block_size)
icx->vcn_size_bits = ni->vol->cluster_size_bits;
else
icx->vcn_size_bits = NTFS_BLOCK_SIZE_BITS;
/* get the appropriate collation function */
icx->ir = ir;
icx->collate = ntfs_get_collate_function(ir->collation_rule);
if (!icx->collate) {
icx->vcn_size_bits = ni->vol->sector_size_bits;
icx->cr = ir->collation_rule;
if (!ntfs_is_collation_rule_supported(icx->cr)) {
err = errno = EOPNOTSUPP;
ntfs_log_perror("Unknown collation rule 0x%x",
(unsigned)le32_to_cpu(ir->collation_rule));
(unsigned)le32_to_cpu(icx->cr));
goto err_out;
}
old_vcn = VCN_INDEX_ROOT_PARENT;
/*
* FIXME: check for both ir and ib that the first index entry is
* within the index block.
*/
ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
if (ret == STATUS_ERROR) {
err = errno;
goto err_lookup;
goto err_out;
}
icx->ir = ir;
@ -878,12 +775,6 @@ descend_into_child_node:
goto descend_into_child_node;
err_out:
icx->bad_index = TRUE; /* Force icx->* to be freed */
err_lookup:
if (icx->actx) {
ntfs_attr_put_search_ctx(icx->actx);
icx->actx = NULL;
}
free(ib);
if (!err)
err = EIO;
@ -915,17 +806,17 @@ static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size,
return NULL;
ib->magic = magic_INDX;
ib->usa_ofs = const_cpu_to_le16(sizeof(INDEX_BLOCK));
ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK));
ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1);
/* Set USN to 1 */
*(le16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = const_cpu_to_le16(1);
ib->lsn = const_cpu_to_sle64(0);
*(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1);
ib->lsn = cpu_to_le64(0);
ib->index_block_vcn = cpu_to_sle64(ib_vcn);
ib->index.entries_offset = cpu_to_le32((ih_size +
le16_to_cpu(ib->usa_count) * 2 + 7) & ~7);
ib->index.index_length = const_cpu_to_le32(0);
ib->index.index_length = 0;
ib->index.allocated_size = cpu_to_le32(ib_size -
(sizeof(INDEX_BLOCK) - ih_size));
ib->index.ih_flags = node_type;
@ -1225,7 +1116,6 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
INDEX_ENTRY *ie;
INDEX_BLOCK *ib = NULL;
VCN new_ib_vcn;
int ix_root_size;
int ret = STATUS_ERROR;
ntfs_log_trace("Entering\n");
@ -1255,7 +1145,6 @@ static int ntfs_ir_reparent(ntfs_index_context *icx)
if (ntfs_ib_write(icx, ib))
goto clear_bmp;
retry :
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
if (!ir)
goto clear_bmp;
@ -1264,37 +1153,18 @@ retry :
ie = ntfs_ie_get_first(&ir->index);
ie->ie_flags |= INDEX_ENTRY_NODE;
ie->length = const_cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
ir->index.ih_flags = LARGE_INDEX;
ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset)
+ le16_to_cpu(ie->length));
ir->index.allocated_size = ir->index.index_length;
ix_root_size = sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER)
+ le32_to_cpu(ir->index.allocated_size);
if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
ix_root_size)) {
/*
* When there is no space to build a non-resident
* index, we may have to move the root to an extent
*/
if ((errno == ENOSPC)
&& (ctx->al_entry || !ntfs_inode_add_attrlist(icx->ni))) {
ntfs_attr_put_search_ctx(ctx);
ctx = (ntfs_attr_search_ctx*)NULL;
ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len,
&ctx);
if (ir
&& !ntfs_attr_record_move_away(ctx, ix_root_size
- le32_to_cpu(ctx->attr->value_length))) {
ntfs_attr_put_search_ctx(ctx);
ctx = (ntfs_attr_search_ctx*)NULL;
goto retry;
}
}
sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) +
le32_to_cpu(ir->index.allocated_size)))
/* FIXME: revert index root */
goto clear_bmp;
}
/*
* FIXME: do it earlier if we have enough space in IR (should always),
* so in error case we wouldn't lose the IB.
@ -1665,32 +1535,19 @@ static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih,
INDEX_ENTRY *ie, INDEX_BLOCK *ib)
{
INDEX_ENTRY *ie_roam;
int freed_space;
BOOL full;
int ret = STATUS_ERROR;
ntfs_log_trace("Entering\n");
full = ih->index_length == ih->allocated_size;
ie_roam = ntfs_ie_dup_novcn(ie);
if (!ie_roam)
return STATUS_ERROR;
ntfs_ie_delete(ih, ie);
if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) {
/*
* Recover the space which may have been freed
* while deleting an entry from root index
*/
freed_space = le32_to_cpu(ih->allocated_size)
- le32_to_cpu(ih->index_length);
if (full && (freed_space > 0) && !(freed_space & 7)) {
ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));
/* do nothing if truncation fails */
}
if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
} else
else
if (ntfs_ib_write(icx, ib))
goto out;
@ -1958,8 +1815,7 @@ err_out:
goto out;
}
int ntfs_index_remove(ntfs_inode *dir_ni,
ntfs_inode *ni __attribute__((unused)),
int ntfs_index_remove(ntfs_inode *dir_ni, ntfs_inode *ni,
const void *key, const int keylen)
{
int ret = STATUS_ERROR;
@ -1974,6 +1830,13 @@ int ntfs_index_remove(ntfs_inode *dir_ni,
if (ntfs_index_lookup(key, keylen, icx))
goto err_out;
if ((((FILE_NAME_ATTR *)icx->data)->file_attributes &
FILE_ATTR_REPARSE_POINT)
&& !ntfs_possible_symlink(ni)) {
errno = EOPNOTSUPP;
goto err_out;
}
ret = ntfs_index_rm(icx);
if (ret == STATUS_ERROR)
goto err_out;
@ -2152,7 +2015,7 @@ static INDEX_ENTRY *ntfs_index_walk_up(INDEX_ENTRY *ie,
INDEX_ENTRY *ntfs_index_next(INDEX_ENTRY *ie, ntfs_index_context *ictx)
{
INDEX_ENTRY *next;
le16 flags;
int flags;
/*
* lookup() may have returned an invalid node

View File

@ -5,7 +5,6 @@
* Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2009-2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -36,14 +35,14 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
#include "param.h"
#include "compat.h"
#include "types.h"
#include "volume.h"
#include "cache.h"
#include "inode.h"
#include "attrib.h"
#include "inode.h"
#include "debug.h"
#include "mft.h"
#include "attrlist.h"
@ -54,7 +53,6 @@
#include "ntfstime.h"
#include "logging.h"
#include "misc.h"
#include "xattrs.h"
ntfs_inode *ntfs_inode_base(ntfs_inode *ni)
{
@ -154,7 +152,7 @@ static void __ntfs_inode_release(ntfs_inode *ni)
* Return a pointer to the ntfs_inode structure on success or NULL on error,
* with errno set to the error code.
*/
static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
{
s64 l;
ntfs_inode *ni = NULL;
@ -189,23 +187,17 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
" %lld", (long long)MREF(mref));
goto put_err_out;
}
lthle = ctx->attr->value_length;
if (le32_to_cpu(lthle) < offsetof(STANDARD_INFORMATION, owner_id)) {
ntfs_log_error("Corrupt STANDARD_INFORMATION in base"
" record %lld\n",
(long long)MREF(mref));
goto put_err_out;
}
std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
le16_to_cpu(ctx->attr->value_offset));
ni->flags = std_info->file_attributes;
ni->creation_time = std_info->creation_time;
ni->last_data_change_time = std_info->last_data_change_time;
ni->last_mft_change_time = std_info->last_mft_change_time;
ni->last_access_time = std_info->last_access_time;
/* Insert v3 extensions if present */
/* length may be seen as 48 (v1.x) or 72 (v3.x) */
if (le32_to_cpu(lthle) >= offsetof(STANDARD_INFORMATION, v3_end)) {
ni->creation_time = ntfs2utc(std_info->creation_time);
ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time);
ni->last_mft_change_time = ntfs2utc(std_info->last_mft_change_time);
ni->last_access_time = ntfs2utc(std_info->last_access_time);
/* JPA insert v3 extensions if present */
/* length may be seen as 72 (v1.x) or 96 (v3.x) */
lthle = ctx->attr->length;
if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) {
set_nino_flag(ni, v3_Extensions);
ni->owner_id = std_info->owner_id;
ni->security_id = std_info->security_id;
@ -213,13 +205,13 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
ni->usn = std_info->usn;
} else {
clear_nino_flag(ni, v3_Extensions);
ni->owner_id = const_cpu_to_le32(0);
ni->security_id = const_cpu_to_le32(0);
ni->owner_id = 0;
ni->security_id = 0;
}
/* Set attribute list information. */
olderrno = errno;
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0,
CASE_SENSITIVE, 0, NULL, 0, ctx)) {
if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
ctx)) {
if (errno != ENOENT)
goto put_err_out;
/* Attribute list attribute does not present. */
@ -231,9 +223,9 @@ static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref)
l = ntfs_get_attribute_value_length(ctx->attr);
if (!l)
goto put_err_out;
if ((u64)l > 0x40000) {
if (l > 0x40000) {
errno = EIO;
ntfs_log_perror("Too large attrlist attribute (%llu), inode "
ntfs_log_perror("Too large attrlist attribute (%lld), inode "
"%lld", (long long)l, (long long)MREF(mref));
goto put_err_out;
}
@ -274,7 +266,6 @@ get_size:
ni->data_size = le32_to_cpu(ctx->attr->value_length);
ni->allocated_size = (ni->data_size + 7) & ~7;
}
set_nino_flag(ni,KnownSize);
}
ntfs_attr_put_search_ctx(ctx);
out:
@ -313,8 +304,7 @@ err_out:
* EINVAL @ni is invalid (probably it is an extent inode).
* EIO I/O error while trying to write inode to disk.
*/
int ntfs_inode_real_close(ntfs_inode *ni)
int ntfs_inode_close(ntfs_inode *ni)
{
int ret = -1;
@ -334,7 +324,7 @@ int ntfs_inode_real_close(ntfs_inode *ni)
/* Is this a base inode with mapped extent inodes? */
if (ni->nr_extents > 0) {
while (ni->nr_extents > 0) {
if (ntfs_inode_real_close(ni->extent_nis[0])) {
if (ntfs_inode_close(ni->extent_nis[0])) {
if (errno != EIO)
errno = EBUSY;
goto err;
@ -374,10 +364,8 @@ int ntfs_inode_real_close(ntfs_inode *ni)
/* Ignore errors, they don't really matter. */
if (tmp_nis)
base_ni->extent_nis = tmp_nis;
} else if (tmp_nis) {
} else if (tmp_nis)
free(tmp_nis);
base_ni->extent_nis = (ntfs_inode**)NULL;
}
/* Allow for error checking. */
i = -1;
break;
@ -399,156 +387,6 @@ err:
return ret;
}
#if CACHE_NIDATA_SIZE
/*
* Free an inode structure when there is not more space
* in the cache
*/
void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached)
{
ntfs_inode_real_close(((const struct CACHED_NIDATA*)cached)->ni);
}
/*
* Compute a hash value for an inode entry
*/
int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item)
{
return (((const struct CACHED_NIDATA*)item)->inum
% (2*CACHE_NIDATA_SIZE));
}
/*
* inum comparing for entering/fetching from cache
*/
static int idata_cache_compare(const struct CACHED_GENERIC *cached,
const struct CACHED_GENERIC *wanted)
{
return (((const struct CACHED_NIDATA*)cached)->inum
!= ((const struct CACHED_NIDATA*)wanted)->inum);
}
/*
* Invalidate an inode entry when not needed anymore.
* The entry should have been synced, it may be reused later,
* if it is requested before it is dropped from cache.
*/
void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref)
{
struct CACHED_NIDATA item;
item.inum = MREF(mref);
item.ni = (ntfs_inode*)NULL;
item.pathname = (const char*)NULL;
item.varsize = 0;
ntfs_invalidate_cache(vol->nidata_cache,
GENERIC(&item),idata_cache_compare,CACHE_FREE);
}
#endif
/*
* Open an inode
*
* When possible, an entry recorded in the cache is reused
*
* **NEVER REOPEN** an inode, this can lead to a duplicated
* cache entry (hard to detect), and to an obsolete one being
* reused. System files are however protected from being cached.
*/
ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
{
ntfs_inode *ni;
#if CACHE_NIDATA_SIZE
struct CACHED_NIDATA item;
struct CACHED_NIDATA *cached;
/* fetch idata from cache */
item.inum = MREF(mref);
debug_double_inode(item.inum,1);
item.pathname = (const char*)NULL;
item.varsize = 0;
cached = (struct CACHED_NIDATA*)ntfs_fetch_cache(vol->nidata_cache,
GENERIC(&item),idata_cache_compare);
if (cached) {
ni = cached->ni;
/* do not keep open entries in cache */
ntfs_remove_cache(vol->nidata_cache,
(struct CACHED_GENERIC*)cached,0);
} else {
ni = ntfs_inode_real_open(vol, mref);
}
if (!ni) {
debug_double_inode(item.inum, 0);
}
#else
ni = ntfs_inode_real_open(vol, mref);
#endif
return (ni);
}
/*
* Close an inode entry
*
* If cacheing is in use, the entry is synced and kept available
* in cache for further use.
*
* System files (inode < 16 or having the IS_4 flag) are protected
* against being cached.
*/
int ntfs_inode_close(ntfs_inode *ni)
{
int res;
#if CACHE_NIDATA_SIZE
BOOL dirty;
struct CACHED_NIDATA item;
if (ni) {
debug_double_inode(ni->mft_no,0);
/* do not cache system files : could lead to double entries */
if (ni->vol && ni->vol->nidata_cache
&& ((ni->mft_no == FILE_root)
|| ((ni->mft_no >= FILE_first_user)
&& !(ni->mrec->flags & MFT_RECORD_IS_4)))) {
/* If we have dirty metadata, write it out. */
dirty = NInoDirty(ni) || NInoAttrListDirty(ni);
if (dirty) {
res = ntfs_inode_sync(ni);
/* do a real close if sync failed */
if (res)
ntfs_inode_real_close(ni);
} else
res = 0;
if (!res) {
/* feed idata into cache */
item.inum = ni->mft_no;
item.ni = ni;
item.pathname = (const char*)NULL;
item.varsize = 0;
debug_cached_inode(ni);
ntfs_enter_cache(ni->vol->nidata_cache,
GENERIC(&item), idata_cache_compare);
}
} else {
/* cache not ready or system file, really close */
res = ntfs_inode_real_close(ni);
}
} else
res = 0;
#else
res = ntfs_inode_real_close(ni);
#endif
return (res);
}
/**
* ntfs_extent_inode_open - load an extent inode and attach it to its base
* @base_ni: base ntfs inode
@ -574,12 +412,9 @@ int ntfs_inode_close(ntfs_inode *ni)
* Note, extent inodes are never closed directly. They are automatically
* disposed off by the closing of the base inode.
*/
ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const leMFT_REF mref)
ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
{
u64 mft_no = MREF_LE(mref);
VCN extent_vcn;
runlist_element *rl;
ntfs_volume *vol;
ntfs_inode *ni = NULL;
ntfs_inode **extent_nis;
int i;
@ -594,37 +429,6 @@ ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const leMFT_REF mref)
(unsigned long long)mft_no,
(unsigned long long)base_ni->mft_no);
if (!base_ni->mft_no) {
/*
* When getting extents of MFT, we must be sure
* they are in the MFT part which has already
* been mapped, otherwise we fall into an endless
* recursion.
* Situations have been met where extents locations
* are described in themselves.
* This is a severe error which chkdsk cannot fix.
*/
vol = base_ni->vol;
extent_vcn = mft_no << vol->mft_record_size_bits
>> vol->cluster_size_bits;
rl = vol->mft_na->rl;
if (rl) {
while (rl->length
&& ((rl->vcn + rl->length) <= extent_vcn))
rl++;
}
if (!rl || (rl->lcn < 0)) {
ntfs_log_error("MFT is corrupt, cannot read"
" its unmapped extent record %lld\n",
(long long)mft_no);
ntfs_log_error("Note : chkdsk cannot fix this,"
" try ntfsfix\n");
errno = EIO;
ni = (ntfs_inode*)NULL;
goto out;
}
}
/* Is the extent inode already open and attached to the base inode? */
if (base_ni->nr_extents > 0) {
extent_nis = base_ni->extent_nis;
@ -757,22 +561,22 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
le16_to_cpu(ctx->attr->value_offset));
std_info->file_attributes = ni->flags;
if (!test_nino_flag(ni, TimesSet)) {
std_info->creation_time = ni->creation_time;
std_info->last_data_change_time = ni->last_data_change_time;
std_info->last_mft_change_time = ni->last_mft_change_time;
std_info->last_access_time = ni->last_access_time;
if (test_nino_flag(ni, TimesDirty)) {
std_info->creation_time = utc2ntfs(ni->creation_time);
std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time);
std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
std_info->last_access_time = utc2ntfs(ni->last_access_time);
}
/* JPA update v3.x extensions, ensuring consistency */
lthle = ctx->attr->value_length;
lthle = ctx->attr->length;
lth = le32_to_cpu(lthle);
if (test_nino_flag(ni, v3_Extensions)
&& (lth < offsetof(STANDARD_INFORMATION, v3_end)))
&& (lth <= sizeof(STANDARD_INFORMATION)))
ntfs_log_error("bad sync of standard information\n");
if (lth >= offsetof(STANDARD_INFORMATION, v3_end)) {
if (lth > sizeof(STANDARD_INFORMATION)) {
std_info->owner_id = ni->owner_id;
std_info->security_id = ni->security_id;
std_info->quota_charged = ni->quota_charged;
@ -791,15 +595,12 @@ static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
*
* Return 0 on success or -1 on error with errno set to the error code.
*/
static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
static int ntfs_inode_sync_file_name(ntfs_inode *ni)
{
ntfs_attr_search_ctx *ctx = NULL;
ntfs_index_context *ictx;
ntfs_inode *index_ni;
FILE_NAME_ATTR *fn;
FILE_NAME_ATTR *fnx;
REPARSE_POINT *rpp;
le32 reparse_tag;
int err = 0;
ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no);
@ -809,17 +610,6 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
err = errno;
goto err_out;
}
/* Collect the reparse tag, if any */
reparse_tag = const_cpu_to_le32(0);
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
if (!ntfs_attr_lookup(AT_REPARSE_POINT, NULL,
0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
rpp = (REPARSE_POINT*)((u8 *)ctx->attr +
le16_to_cpu(ctx->attr->value_offset));
reparse_tag = rpp->reparse_tag;
}
ntfs_attr_reinit_search_ctx(ctx);
}
/* Walk through all FILE_NAME attributes and update them. */
while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) {
fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr +
@ -834,16 +624,13 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
*/
index_ni = ni;
} else
if (dir_ni)
index_ni = dir_ni;
else
index_ni = ntfs_inode_open(ni->vol,
index_ni = ntfs_inode_open(ni->vol,
le64_to_cpu(fn->parent_directory));
if (!index_ni) {
if (!err)
err = errno;
ntfs_log_perror("Failed to open inode %lld with index",
(long long)MREF_LE(fn->parent_directory));
(long long)le64_to_cpu(fn->parent_directory));
continue;
}
ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4);
@ -852,8 +639,7 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
err = errno;
ntfs_log_perror("Failed to get index ctx, inode %lld",
(long long)index_ni->mft_no);
if ((ni != index_ni) && !dir_ni
&& ntfs_inode_close(index_ni) && !err)
if (ni != index_ni && ntfs_inode_close(index_ni) && !err)
err = errno;
continue;
}
@ -872,40 +658,21 @@ static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni)
continue;
}
/* Update flags and file size. */
fnx = (FILE_NAME_ATTR *)ictx->data;
fnx->file_attributes =
(fnx->file_attributes & ~FILE_ATTR_VALID_FLAGS) |
fn = (FILE_NAME_ATTR *)ictx->data;
fn->file_attributes =
(fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) |
(ni->flags & FILE_ATTR_VALID_FLAGS);
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
fnx->data_size = fnx->allocated_size
= const_cpu_to_sle64(0);
else {
fnx->allocated_size = cpu_to_sle64(ni->allocated_size);
fnx->data_size = cpu_to_sle64(ni->data_size);
/*
* The file name record has also to be fixed if some
* attribute update implied the unnamed data to be
* made non-resident
*/
fn->allocated_size = fnx->allocated_size;
}
/* update or clear the reparse tag in the index */
fnx->reparse_point_tag = reparse_tag;
if (!test_nino_flag(ni, TimesSet)) {
fnx->creation_time = ni->creation_time;
fnx->last_data_change_time = ni->last_data_change_time;
fnx->last_mft_change_time = ni->last_mft_change_time;
fnx->last_access_time = ni->last_access_time;
} else {
fnx->creation_time = fn->creation_time;
fnx->last_data_change_time = fn->last_data_change_time;
fnx->last_mft_change_time = fn->last_mft_change_time;
fnx->last_access_time = fn->last_access_time;
fn->allocated_size = cpu_to_sle64(ni->allocated_size);
fn->data_size = cpu_to_sle64(ni->data_size);
if (test_nino_flag(ni, TimesDirty)) {
fn->creation_time = utc2ntfs(ni->creation_time);
fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
fn->last_access_time = utc2ntfs(ni->last_access_time);
}
ntfs_index_entry_mark_dirty(ictx);
ntfs_index_ctx_put(ictx);
if ((ni != index_ni) && !dir_ni
&& ntfs_inode_close(index_ni) && !err)
if ((ni != index_ni) && ntfs_inode_close(index_ni) && !err)
err = errno;
}
/* Check for real error occurred. */
@ -947,10 +714,11 @@ err_out:
* EBUSY - Inode and/or one of its extents is busy, try again later.
* EIO - I/O error while writing the inode (or one of its extents).
*/
static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
int ntfs_inode_sync(ntfs_inode *ni)
{
int ret = 0;
int err = 0;
if (!ni) {
errno = EINVAL;
ntfs_log_error("Failed to sync NULL inode\n");
@ -972,7 +740,7 @@ static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
/* Update FILE_NAME's in the index. */
if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
NInoFileNameTestAndClearDirty(ni) &&
ntfs_inode_sync_file_name(ni, dir_ni)) {
ntfs_inode_sync_file_name(ni)) {
if (!err || errno == EIO) {
err = errno;
if (err != EIO)
@ -1075,28 +843,6 @@ sync_inode:
return ret;
}
int ntfs_inode_sync(ntfs_inode *ni)
{
return (ntfs_inode_sync_in_dir(ni, (ntfs_inode*)NULL));
}
/*
* Close an inode with an open parent inode
*/
int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni)
{
int res;
res = ntfs_inode_sync_in_dir(ni, dir_ni);
if (res) {
if (errno != EIO)
errno = EBUSY;
} else
res = ntfs_inode_close(ni);
return (res);
}
/**
* ntfs_inode_add_attrlist - add attribute list to inode and fill it
* @ni: opened ntfs inode to which add attribute list
@ -1172,7 +918,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
if (ctx->attr->non_resident)
ale->lowest_vcn = ctx->attr->lowest_vcn;
else
ale->lowest_vcn = const_cpu_to_sle64(0);
ale->lowest_vcn = 0;
ale->mft_reference = MK_LE_MREF(ni->mft_no,
le16_to_cpu(ni->mrec->sequence_number));
ale->instance = ctx->attr->instance;
@ -1210,7 +956,7 @@ int ntfs_inode_add_attrlist(ntfs_inode *ni)
/* Add $ATTRIBUTE_LIST to mft record. */
if (ntfs_resident_attr_record_add(ni,
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, const_cpu_to_le16(0)) < 0) {
AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
err = errno;
ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT");
goto rollback;
@ -1383,7 +1129,7 @@ put_err_out:
*/
void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
{
ntfs_time now;
time_t now;
if (!ni) {
ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__);
@ -1394,7 +1140,7 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
NVolReadOnly(ni->vol) || !mask)
return;
now = ntfs_current_time();
now = time(NULL);
if (mask & NTFS_UPDATE_ATIME)
ni->last_access_time = now;
if (mask & NTFS_UPDATE_MTIME)
@ -1402,6 +1148,7 @@ void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
if (mask & NTFS_UPDATE_CTIME)
ni->last_mft_change_time = now;
set_nino_flag(ni, TimesDirty);
NInoFileNameSetDirty(ni);
NInoSetDirty(ni);
}
@ -1450,6 +1197,8 @@ 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
*
@ -1460,7 +1209,8 @@ int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
* -errno if failed
*/
int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size)
int ntfs_inode_get_times(const char *path __attribute__((unused)),
char *value, size_t size, ntfs_inode *ni)
{
ntfs_attr_search_ctx *ctx;
STANDARD_INFORMATION *std_info;
@ -1479,18 +1229,18 @@ int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size)
le16_to_cpu(ctx->attr->value_offset));
if (value && (size >= 8)) {
times = (u64*)value;
times[0] = sle64_to_cpu(std_info->creation_time);
times[0] = le64_to_cpu(std_info->creation_time);
ret = 8;
if (size >= 16) {
times[1] = sle64_to_cpu(std_info->last_data_change_time);
times[1] = le64_to_cpu(std_info->last_data_change_time);
ret = 16;
}
if (size >= 24) {
times[2] = sle64_to_cpu(std_info->last_access_time);
times[2] = le64_to_cpu(std_info->last_access_time);
ret = 24;
}
if (size >= 32) {
times[3] = sle64_to_cpu(std_info->last_mft_change_time);
times[3] = le64_to_cpu(std_info->last_mft_change_time);
ret = 32;
}
} else
@ -1518,23 +1268,22 @@ int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size)
* -1 if there were an error (described by errno)
*/
int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
int flags)
int ntfs_inode_set_times(const char *path __attribute__((unused)),
const char *value, size_t size,
int flags, ntfs_inode *ni)
{
ntfs_attr_search_ctx *ctx;
STANDARD_INFORMATION *std_info;
FILE_NAME_ATTR *fn;
u64 times[4];
ntfs_time now;
const u64 *times;
le64 now;
int cnt;
int ret;
ret = -1;
if ((size >= 8) && !(flags & XATTR_CREATE)) {
/* Copy, to avoid alignment issue encountered on ARM */
memcpy(times, value,
(size < sizeof(times) ? size : sizeof(times)));
now = ntfs_current_time();
times = (const u64*)value;
now = utc2ntfs(time((time_t*)NULL));
/* update the standard information attribute */
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (ctx) {
@ -1547,31 +1296,16 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
le16_to_cpu(ctx->attr->value_offset));
/*
* Mark times set to avoid overwriting
* them when the inode is closed.
* The inode structure must also be updated
* (with loss of precision) because of cacheing.
* TODO : use NTFS precision in inode, and
* return sub-second times in getattr()
* Do not mark times dirty to avoid
* overwriting them when the inode is closed.
*/
set_nino_flag(ni, TimesSet);
std_info->creation_time = cpu_to_sle64(times[0]);
ni->creation_time
= std_info->creation_time;
if (size >= 16) {
std_info->last_data_change_time = cpu_to_sle64(times[1]);
ni->last_data_change_time
= std_info->last_data_change_time;
}
if (size >= 24) {
std_info->last_access_time = cpu_to_sle64(times[2]);
ni->last_access_time
= std_info->last_access_time;
}
std_info->creation_time = cpu_to_le64(times[0]);
if (size >= 16)
std_info->last_data_change_time = cpu_to_le64(times[1]);
if (size >= 24)
std_info->last_access_time = cpu_to_le64(times[2]);
std_info->last_mft_change_time = now;
ni->last_mft_change_time = now;
ntfs_inode_mark_dirty(ctx->ntfs_ino);
NInoFileNameSetDirty(ni);
/* update the file names attributes */
ntfs_attr_reinit_search_ctx(ctx);
@ -1581,14 +1315,18 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
0, NULL, 0, ctx)) {
fn = (FILE_NAME_ATTR*)((u8 *)ctx->attr +
le16_to_cpu(ctx->attr->value_offset));
/*
* Do not mark times dirty to avoid
* overwriting them when the inode is closed.
*/
fn->creation_time
= cpu_to_sle64(times[0]);
= cpu_to_le64(times[0]);
if (size >= 16)
fn->last_data_change_time
= cpu_to_sle64(times[1]);
= cpu_to_le64(times[1]);
if (size >= 24)
fn->last_access_time
= cpu_to_sle64(times[2]);
= cpu_to_le64(times[2]);
fn->last_mft_change_time = now;
cnt++;
}
@ -1600,7 +1338,7 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
}
}
ntfs_attr_put_search_ctx(ctx);
}
}
} else
if (size < 8)
errno = ERANGE;
@ -1608,3 +1346,5 @@ int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size,
errno = EEXIST;
return (ret);
}
#endif /* HAVE_SETXATTR */

View File

@ -1,419 +0,0 @@
/**
* ioctl.c - Processing of ioctls
*
* This module is part of ntfs-3g library
*
* Copyright (c) 2014-2019 Jean-Pierre Andre
* Copyright (c) 2014 Red Hat, Inc.
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <syslog.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
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h>
#endif
#include "compat.h"
#include "debug.h"
#include "bitmap.h"
#include "attrib.h"
#include "inode.h"
#include "layout.h"
#include "volume.h"
#include "index.h"
#include "logging.h"
#include "ntfstime.h"
#include "unistr.h"
#include "dir.h"
#include "security.h"
#include "ioctl.h"
#include "misc.h"
#if defined(FITRIM) && defined(BLKDISCARD)
/* Issue a TRIM request to the underlying device for the given clusters. */
static int fstrim_clusters(ntfs_volume *vol, LCN lcn, s64 length)
{
struct ntfs_device *dev = vol->dev;
uint64_t range[2];
ntfs_log_debug("fstrim_clusters: %lld length %lld\n",
(long long) lcn, (long long) length);
range[0] = lcn << vol->cluster_size_bits;
range[1] = length << vol->cluster_size_bits;
if (dev->d_ops->ioctl(dev, BLKDISCARD, range) == -1) {
ntfs_log_debug("fstrim_one_cluster: ioctl failed: %m\n");
return -errno;
}
return 0;
}
static int read_line(const char *path, char *line, size_t max_bytes)
{
FILE *fp;
fp = fopen(path, "r");
if (fp == NULL)
return -errno;
if (fgets(line, max_bytes, fp) == NULL) {
int ret = -EIO; /* fgets doesn't set errno */
fclose(fp);
return ret;
}
fclose (fp);
return 0;
}
static int read_u64(const char *path, u64 *n)
{
char line[64];
int ret;
ret = read_line(path, line, sizeof line);
if (ret)
return ret;
if (sscanf(line, "%" SCNu64, n) != 1)
return -EINVAL;
return 0;
}
/* Find discard limits for current backing device.
*/
static int fstrim_limits(ntfs_volume *vol,
u64 *discard_alignment,
u64 *discard_granularity,
u64 *discard_max_bytes)
{
struct stat statbuf;
char path1[40]; /* holds "/sys/dev/block/%d:%d" */
char path2[40 + sizeof(path1)]; /* less than 40 bytes more than path1 */
int ret;
/* Stat the backing device. Caller has ensured it is a block device. */
if (stat(vol->dev->d_name, &statbuf) == -1) {
ntfs_log_debug("fstrim_limits: could not stat %s\n",
vol->dev->d_name);
return -errno;
}
/* For whole devices,
* /sys/dev/block/MAJOR:MINOR/discard_alignment
* /sys/dev/block/MAJOR:MINOR/queue/discard_granularity
* /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes
* will exist.
* For partitions, we also need to check the parent device:
* /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity
* /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes
*/
snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d",
major(statbuf.st_rdev), minor(statbuf.st_rdev));
snprintf(path2, sizeof path2, "%s/discard_alignment", path1);
ret = read_u64(path2, discard_alignment);
if (ret) {
if (ret != -ENOENT)
return ret;
else
/* We would expect this file to exist on all
* modern kernels. But for the sake of very
* old kernels:
*/
goto not_found;
}
snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1);
ret = read_u64(path2, discard_granularity);
if (ret) {
if (ret != -ENOENT)
return ret;
else {
snprintf(path2, sizeof path2,
"%s/../queue/discard_granularity", path1);
ret = read_u64(path2, discard_granularity);
if (ret) {
if (ret != -ENOENT)
return ret;
else
goto not_found;
}
}
}
snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1);
ret = read_u64(path2, discard_max_bytes);
if (ret) {
if (ret != -ENOENT)
return ret;
else {
snprintf(path2, sizeof path2,
"%s/../queue/discard_max_bytes", path1);
ret = read_u64(path2, discard_max_bytes);
if (ret) {
if (ret != -ENOENT)
return ret;
else
goto not_found;
}
}
}
return 0;
not_found:
/* If we reach here then we didn't find the device. This is
* not an error, but set discard_max_bytes = 0 to indicate
* that discard is not available.
*/
*discard_alignment = 0;
*discard_granularity = 0;
*discard_max_bytes = 0;
return 0;
}
static inline LCN align_up(ntfs_volume *vol, LCN lcn, u64 granularity)
{
u64 aligned;
aligned = (lcn << vol->cluster_size_bits) + granularity - 1;
aligned -= aligned % granularity;
return (aligned >> vol->cluster_size_bits);
}
static inline u64 align_down(ntfs_volume *vol, u64 count, u64 granularity)
{
u64 aligned;
aligned = count << vol->cluster_size_bits;
aligned -= aligned % granularity;
return (aligned >> vol->cluster_size_bits);
}
#define FSTRIM_BUFSIZ 4096
/* Trim the filesystem.
*
* Free blocks between 'start' and 'start+len-1' (both byte offsets)
* are found and TRIM requests are sent to the block device. 'minlen'
* is the minimum continguous free range to discard.
*/
static int fstrim(ntfs_volume *vol, void *data, u64 *trimmed)
{
struct fstrim_range *range = data;
u64 start = range->start;
u64 len = range->len;
u64 minlen = range->minlen;
u64 discard_alignment, discard_granularity, discard_max_bytes;
u8 *buf = NULL;
LCN start_buf;
int ret;
ntfs_log_debug("fstrim: start=%llu len=%llu minlen=%llu\n",
(unsigned long long) start,
(unsigned long long) len,
(unsigned long long) minlen);
*trimmed = 0;
/* Fail if user tries to use the fstrim -o/-l/-m options.
* XXX We could fix these limitations in future.
*/
if (start != 0 || len != (uint64_t)-1) {
ntfs_log_error("fstrim: setting start or length is not supported\n");
return -EINVAL;
}
if (minlen > vol->cluster_size) {
ntfs_log_error("fstrim: minlen > cluster size is not supported\n");
return -EINVAL;
}
/* Only block devices are supported. It would be possible to
* support backing files (ie. without using loop) but the
* ioctls used to punch holes in files are completely
* different.
*/
if (!NDevBlock(vol->dev)) {
ntfs_log_error("fstrim: not supported for non-block-device\n");
return -EOPNOTSUPP;
}
ret = fstrim_limits(vol, &discard_alignment,
&discard_granularity, &discard_max_bytes);
if (ret)
return ret;
if (discard_alignment != 0) {
ntfs_log_error("fstrim: backing device is not aligned for discards\n");
return -EOPNOTSUPP;
}
if (discard_max_bytes == 0) {
ntfs_log_error("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
return -EOPNOTSUPP;
}
/* Sync the device before doing anything. */
ret = ntfs_device_sync(vol->dev);
if (ret)
return ret;
/* Read through the bitmap. */
buf = ntfs_malloc(FSTRIM_BUFSIZ);
if (buf == NULL)
return -errno;
for (start_buf = 0; start_buf < vol->nr_clusters;
start_buf += FSTRIM_BUFSIZ * 8) {
s64 count;
s64 br;
LCN end_buf, start_lcn;
/* start_buf is LCN of first cluster in the current buffer.
* end_buf is LCN of last cluster + 1 in the current buffer.
*/
end_buf = start_buf + FSTRIM_BUFSIZ*8;
if (end_buf > vol->nr_clusters)
end_buf = vol->nr_clusters;
count = (end_buf - start_buf) / 8;
br = ntfs_attr_pread(vol->lcnbmp_na, start_buf/8, count, buf);
if (br != count) {
if (br >= 0)
ret = -EIO;
else
ret = -errno;
goto free_out;
}
/* Trim the clusters in large as possible blocks, but
* not larger than discard_max_bytes, and compatible
* with the supported trim granularity.
*/
for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) {
if (!ntfs_bit_get(buf, start_lcn-start_buf)) {
LCN end_lcn;
LCN aligned_lcn;
u64 aligned_count;
/* Cluster 'start_lcn' is not in use,
* find end of this run.
*/
end_lcn = start_lcn+1;
while (end_lcn < end_buf &&
(u64) (end_lcn-start_lcn) << vol->cluster_size_bits
< discard_max_bytes &&
!ntfs_bit_get(buf, end_lcn-start_buf))
end_lcn++;
aligned_lcn = align_up(vol, start_lcn,
discard_granularity);
if (aligned_lcn >= end_lcn)
aligned_count = 0;
else {
aligned_count =
align_down(vol,
end_lcn - aligned_lcn,
discard_granularity);
}
if (aligned_count) {
ret = fstrim_clusters(vol,
aligned_lcn, aligned_count);
if (ret)
goto free_out;
*trimmed += aligned_count
<< vol->cluster_size_bits;
}
start_lcn = end_lcn-1;
}
}
}
ret = 0;
free_out:
free(buf);
return ret;
}
#endif /* FITRIM && BLKDISCARD */
int ntfs_ioctl(ntfs_inode *ni, unsigned long cmd,
void *arg __attribute__((unused)),
unsigned int flags __attribute__((unused)), void *data)
{
int ret = 0;
switch (cmd) {
#if defined(FITRIM) && defined(BLKDISCARD)
case FITRIM:
if (!ni || !data)
ret = -EINVAL;
else {
u64 trimmed;
struct fstrim_range *range = (struct fstrim_range*)data;
ret = fstrim(ni->vol, data, &trimmed);
range->len = trimmed;
}
break;
#else
#warning Trimming not supported : FITRIM or BLKDISCARD not defined
#endif
default :
ret = -EINVAL;
break;
}
return (ret);
}

View File

@ -368,14 +368,12 @@ runlist *ntfs_cluster_alloc(ntfs_volume *vol, VCN start_vcn, s64 count,
/* Allocate the bitmap bit. */
*byte |= bit;
writeback = 1;
if (NVolFreeSpaceKnown(vol)) {
if (vol->free_clusters <= 0)
ntfs_log_error("Non-positive free"
" clusters (%lld)!\n",
if (vol->free_clusters <= 0)
ntfs_log_error("Non-positive free clusters "
"(%lld)!\n",
(long long)vol->free_clusters);
else
vol->free_clusters--;
}
else
vol->free_clusters--;
/*
* Coalesce with previous run if adjacent LCNs.
@ -475,7 +473,7 @@ done_zones_check:
ntfs_log_trace("Switching zone.\n");
pass = 1;
if (rlpos) {
LCN tc = rl[rlpos - 1].lcn +
LCN tc = tc = rl[rlpos - 1].lcn +
rl[rlpos - 1].length + NTFS_LCNALLOC_SKIP;
if (used_zone_pos)
@ -604,43 +602,6 @@ int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl)
ret = 0;
out:
vol->free_clusters += nr_freed;
if (NVolFreeSpaceKnown(vol)
&& (vol->free_clusters > vol->nr_clusters))
ntfs_log_error("Too many free clusters (%lld > %lld)!",
(long long)vol->free_clusters,
(long long)vol->nr_clusters);
return ret;
}
/*
* Basic cluster run free
* Returns 0 if successful
*/
int ntfs_cluster_free_basic(ntfs_volume *vol, s64 lcn, s64 count)
{
s64 nr_freed = 0;
int ret = -1;
ntfs_log_trace("Entering.\n");
ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n",
(long long)lcn, (long long)count);
if (lcn >= 0) {
update_full_status(vol,lcn);
if (ntfs_bitmap_clear_run(vol->lcnbmp_na, lcn,
count)) {
ntfs_log_perror("Cluster deallocation failed "
"(%lld, %lld)",
(long long)lcn,
(long long)count);
goto out;
}
nr_freed += count;
}
ret = 0;
out:
vol->free_clusters += nr_freed;
if (vol->free_clusters > vol->nr_clusters)
ntfs_log_error("Too many free clusters (%lld > %lld)!",
(long long)vol->free_clusters,
@ -679,7 +640,7 @@ int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count)
ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, "
"vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no,
le32_to_cpu(na->type), (long long)count, (long long)start_vcn);
na->type, (long long)count, (long long)start_vcn);
rl = ntfs_attr_find_vcn(na, start_vcn);
if (!rl) {

View File

@ -84,21 +84,13 @@ static BOOL ntfs_check_restart_page_header(RESTART_PAGE_HEADER *rp, s64 pos)
"position in $LogFile.\n");
return FALSE;
}
/*
* We only know how to handle version 1.1 and 2.0, though
* version 2.0 is probably related to cached metadata in
* Windows 8, and we will refuse to mount.
* Nevertheless, do all the relevant checks before rejecting.
*/
if (((rp->major_ver != const_cpu_to_sle16(1))
|| (rp->minor_ver != const_cpu_to_sle16(1)))
&& ((rp->major_ver != const_cpu_to_sle16(2))
|| (rp->minor_ver != const_cpu_to_sle16(0)))) {
/* We only know how to handle version 1.1. */
if (sle16_to_cpu(rp->major_ver) != 1 ||
sle16_to_cpu(rp->minor_ver) != 1) {
ntfs_log_error("$LogFile version %i.%i is not "
"supported.\n (This driver supports version "
"1.1 and 2.0 only.)\n",
(int)sle16_to_cpu(rp->major_ver),
(int)sle16_to_cpu(rp->minor_ver));
"supported. (This driver supports version "
"1.1 only.)\n", (int)sle16_to_cpu(rp->major_ver),
(int)sle16_to_cpu(rp->minor_ver));
return FALSE;
}
/*
@ -119,7 +111,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 < offsetof(RESTART_PAGE_HEADER, usn) ||
if (usa_ofs < sizeof(RESTART_PAGE_HEADER) ||
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
ntfs_log_error("$LogFile restart page specifies "
"inconsistent update sequence array offset.\n");
@ -134,7 +126,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 < offsetof(RESTART_PAGE_HEADER, usn)) ||
ra_ofs < sizeof(RESTART_PAGE_HEADER)) ||
ra_ofs > logfile_system_page_size) {
ntfs_log_error("$LogFile restart page specifies "
"inconsistent restart area offset.\n");
@ -287,19 +279,9 @@ static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp)
LOG_CLIENT_RECORD *ca, *cr;
u16 nr_clients, idx;
BOOL in_free_list, idx_is_first;
u32 offset_clients;
ntfs_log_trace("Entering.\n");
/* The restart area must be fully within page */
if ((le16_to_cpu(rp->restart_area_offset) + sizeof(RESTART_AREA))
> le32_to_cpu(rp->system_page_size))
goto err_out;
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
offset_clients = le16_to_cpu(rp->restart_area_offset)
+ le16_to_cpu(ra->client_array_offset);
/* The clients' records must begin within page */
if (offset_clients >= le32_to_cpu(rp->system_page_size))
goto err_out;
ca = (LOG_CLIENT_RECORD*)((u8*)ra +
le16_to_cpu(ra->client_array_offset));
/*
@ -318,10 +300,6 @@ check_list:
idx = le16_to_cpu(cr->next_client)) {
if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
goto err_out;
/* The client record must be fully within page */
if ((offset_clients + (idx + 1)*sizeof(LOG_CLIENT_RECORD))
> le32_to_cpu(rp->system_page_size))
goto err_out;
/* Set @cr to the current log client record. */
cr = ca + idx;
/* The first log client record must not have a prev_client. */
@ -394,14 +372,7 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na,
/*
* Allocate a buffer to store the whole restart page so we can multi
* sector transfer deprotect it.
* For safety, make sure this is consistent with the usa_count
* and shorter than the full log size
*/
if ((le32_to_cpu(rp->system_page_size)
> (u32)(le16_to_cpu(rp->usa_count) - 1)*NTFS_BLOCK_SIZE)
|| (le32_to_cpu(rp->system_page_size)
> le64_to_cpu(log_na->data_size)))
return (EINVAL);
trp = ntfs_malloc(le32_to_cpu(rp->system_page_size));
if (!trp)
return errno;
@ -497,7 +468,7 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
u8 *kaddr = NULL;
RESTART_PAGE_HEADER *rstr1_ph = NULL;
RESTART_PAGE_HEADER *rstr2_ph = NULL;
int log_page_size, err;
int log_page_size, log_page_mask, err;
BOOL logfile_is_empty = TRUE;
u8 log_page_bits;
@ -510,6 +481,7 @@ BOOL ntfs_check_logfile(ntfs_attr *log_na, RESTART_PAGE_HEADER **rp)
if (size > (s64)MaxLogFileSize)
size = MaxLogFileSize;
log_page_size = DefaultLogPageSize;
log_page_mask = log_page_size - 1;
/*
* Use generic_ffs() instead of ffs() to enable the compiler to
* optimize log_page_size and log_page_bits into constants.

View File

@ -3,7 +3,6 @@
*
* Copyright (c) 2005 Richard Russon
* Copyright (c) 2005-2008 Szabolcs Szakacsits
* Copyright (c) 2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -389,29 +388,6 @@ out:
}
#endif
/*
* Early logging before the logs are redirected
*
* (not quite satisfactory : this appears before the ntfs-g banner,
* and with a different pid)
*/
void ntfs_log_early_error(const char *format, ...)
{
va_list args;
va_start(args, format);
#ifdef HAVE_SYSLOG_H
openlog("ntfs-3g", LOG_PID, LOG_USER);
ntfs_log_handler_syslog(NULL, NULL, 0,
NTFS_LOG_LEVEL_ERROR, NULL,
format, args);
#else
vfprintf(stderr,format,args);
#endif
va_end(args);
}
/**
* ntfs_log_handler_fprintf - Basic logging handler
* @function: Function in which the log line occurred

View File

@ -5,7 +5,6 @@
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2004-2008 Szabolcs Szakacsits
* Copyright (c) 2005 Yura Pakhuchiy
* Copyright (c) 2014-2021 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
@ -172,15 +171,6 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
cnt = vol->mftmirr_size - m;
if (cnt > count)
cnt = count;
if ((m + cnt) > vol->mftmirr_na->initialized_size >>
vol->mft_record_size_bits) {
errno = ESPIPE;
ntfs_log_perror("Trying to write non-allocated mftmirr"
" records (%lld > %lld)", (long long)m + cnt,
(long long)vol->mftmirr_na->initialized_size >>
vol->mft_record_size_bits);
return -1;
}
bmirr = ntfs_malloc(cnt * vol->mft_record_size);
if (!bmirr)
return -1;
@ -219,32 +209,15 @@ int ntfs_mft_records_write(const ntfs_volume *vol, const MFT_REF mref,
return -1;
}
/*
* Check the consistency of an MFT record
*
* Make sure its general fields are safe, then examine all its
* attributes and apply generic checks to them.
* The attribute checks are skipped when a record is being read in
* order to collect its sequence number for creating a new record.
*
* Returns 0 if the checks are successful
* -1 with errno = EIO otherwise
*/
int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
MFT_RECORD *m)
{
ATTR_RECORD *a;
ATTR_TYPES previous_type;
int ret = -1;
u32 offset;
s32 space;
if (!ntfs_is_file_record(m->magic)) {
if (!NVolNoFixupWarn(vol))
ntfs_log_error("Record %llu has no FILE magic (0x%x)\n",
(unsigned long long)MREF(mref),
(int)le32_to_cpu(*(le32*)m));
ntfs_log_error("Record %llu has no FILE magic (0x%x)\n",
(unsigned long long)MREF(mref), *(le32 *)m);
goto err_out;
}
@ -255,57 +228,13 @@ int ntfs_mft_record_check(const ntfs_volume *vol, const MFT_REF mref,
le32_to_cpu(m->bytes_allocated));
goto err_out;
}
if (!NVolNoFixupWarn(vol)
&& (le32_to_cpu(m->bytes_in_use) > vol->mft_record_size)) {
ntfs_log_error("Record %llu has corrupt in-use size "
"(%u > %u)\n", (unsigned long long)MREF(mref),
(int)le32_to_cpu(m->bytes_in_use),
(int)vol->mft_record_size);
goto err_out;
}
if (le16_to_cpu(m->attrs_offset) & 7) {
ntfs_log_error("Attributes badly aligned in record %llu\n",
(unsigned long long)MREF(mref));
goto err_out;
}
a = (ATTR_RECORD *)((char *)m + le16_to_cpu(m->attrs_offset));
if (p2n(a) < p2n(m) || (char *)a > (char *)m + vol->mft_record_size) {
ntfs_log_error("Record %llu is corrupt\n",
(unsigned long long)MREF(mref));
goto err_out;
}
if (!NVolNoFixupWarn(vol)) {
offset = le16_to_cpu(m->attrs_offset);
space = le32_to_cpu(m->bytes_in_use) - offset;
a = (ATTR_RECORD*)((char*)m + offset);
previous_type = AT_STANDARD_INFORMATION;
while ((space >= (s32)offsetof(ATTR_RECORD, resident_end))
&& (a->type != AT_END)
&& (le32_to_cpu(a->type) >= le32_to_cpu(previous_type))) {
if ((le32_to_cpu(a->length) <= (u32)space)
&& !(le32_to_cpu(a->length) & 7)) {
if (!ntfs_attr_inconsistent(a, mref)) {
previous_type = a->type;
offset += le32_to_cpu(a->length);
space -= le32_to_cpu(a->length);
a = (ATTR_RECORD*)((char*)m + offset);
} else
goto err_out;
} else {
ntfs_log_error("Corrupted MFT record %llu\n",
(unsigned long long)MREF(mref));
goto err_out;
}
}
/* We are supposed to reach an AT_END */
if ((space < 4) || (a->type != AT_END)) {
ntfs_log_error("Bad end of MFT record %llu\n",
(unsigned long long)MREF(mref));
goto err_out;
}
}
ret = 0;
err_out:
@ -423,7 +352,7 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
* Set the NTFS 3.1+ specific fields while we know that the
* volume version is 3.1+.
*/
mrec->reserved = const_cpu_to_le16(0);
mrec->reserved = cpu_to_le16(0);
mrec->mft_record_number = cpu_to_le32(MREF(mref));
}
mrec->magic = magic_FILE;
@ -431,7 +360,7 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
mrec->usa_count = cpu_to_le16(vol->mft_record_size /
NTFS_BLOCK_SIZE + 1);
else {
mrec->usa_count = const_cpu_to_le16(1);
mrec->usa_count = cpu_to_le16(1);
ntfs_log_error("Sector size is bigger than MFT record size. "
"Setting usa_count to 1. If Windows chkdsk "
"reports this as corruption, please email %s "
@ -440,14 +369,14 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
"Thank you.\n", NTFS_DEV_LIST);
}
/* Set the update sequence number to 1. */
*(le16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = const_cpu_to_le16(1);
mrec->lsn = const_cpu_to_sle64(0ll);
mrec->sequence_number = const_cpu_to_le16(1);
mrec->link_count = const_cpu_to_le16(0);
*(u16*)((u8*)mrec + le16_to_cpu(mrec->usa_ofs)) = cpu_to_le16(1);
mrec->lsn = cpu_to_le64(0ull);
mrec->sequence_number = cpu_to_le16(1);
mrec->link_count = cpu_to_le16(0);
/* Aligned to 8-byte boundary. */
mrec->attrs_offset = cpu_to_le16((le16_to_cpu(mrec->usa_ofs) +
(le16_to_cpu(mrec->usa_count) << 1) + 7) & ~7);
mrec->flags = const_cpu_to_le16(0);
mrec->flags = cpu_to_le16(0);
/*
* Using attrs_offset plus eight bytes (for the termination attribute),
* aligned to 8-byte boundary.
@ -455,11 +384,11 @@ int ntfs_mft_record_layout(const ntfs_volume *vol, const MFT_REF mref,
mrec->bytes_in_use = cpu_to_le32((le16_to_cpu(mrec->attrs_offset) + 8 +
7) & ~7);
mrec->bytes_allocated = cpu_to_le32(vol->mft_record_size);
mrec->base_mft_record = const_cpu_to_le64((MFT_REF)0);
mrec->next_attr_instance = const_cpu_to_le16(0);
mrec->base_mft_record = cpu_to_le64((MFT_REF)0);
mrec->next_attr_instance = cpu_to_le16(0);
a = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset));
a->type = AT_END;
a->length = const_cpu_to_le32(0);
a->length = cpu_to_le32(0);
/* Finally, clear the unused part of the mft record. */
memset((u8*)a + 8, 0, vol->mft_record_size - ((u8*)a + 8 - (u8*)mrec));
return 0;
@ -622,7 +551,7 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
"data_pos 0x%llx, bit 0x%llx, "
"*byte 0x%hhx, b %u.\n", size,
(long long)data_pos, (long long)bit,
(u8) (byte ? *byte : -1), b);
byte ? *byte : -1, b);
for (; bit < size && data_pos + bit < pass_end;
bit &= ~7ull, bit += 8) {
/*
@ -649,7 +578,7 @@ static int ntfs_mft_bitmap_find_free_rec(ntfs_volume *vol, ntfs_inode *base_ni)
"data_pos 0x%llx, bit 0x%llx, "
"*byte 0x%hhx, b %u.\n", size,
(long long)data_pos, (long long)bit,
(u8) (byte ? *byte : -1), b);
byte ? *byte : -1, b);
data_pos += size;
/*
* If the end of the pass has not been reached yet,
@ -978,6 +907,7 @@ static int ntfs_mft_bitmap_extend_initialized(ntfs_volume *vol)
ll = ntfs_attr_pwrite(mftbmp_na, old_initialized_size, 8, &ll);
if (ll == 8) {
ntfs_log_debug("Wrote eight initialized bytes to mft bitmap.\n");
vol->free_mft_records += (8 * 8);
ret = 0;
goto out;
}
@ -1260,7 +1190,7 @@ undo_alloc:
static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
{
int ret = -1;
ntfs_attr *mft_na;
ntfs_attr *mft_na, *mftbmp_na;
s64 old_data_initialized, old_data_size;
ntfs_attr_search_ctx *ctx;
@ -1269,6 +1199,7 @@ static int ntfs_mft_record_init(ntfs_volume *vol, s64 size)
/* NOTE: Caller must sanity check vol, vol->mft_na and vol->mftbmp_na */
mft_na = vol->mft_na;
mftbmp_na = vol->mftbmp_na;
/*
* The mft record is outside the initialized data. Extend the mft data
@ -1364,13 +1295,14 @@ undo_data_init:
static int ntfs_mft_rec_init(ntfs_volume *vol, s64 size)
{
int ret = -1;
ntfs_attr *mft_na;
ntfs_attr *mft_na, *mftbmp_na;
s64 old_data_initialized, old_data_size;
ntfs_attr_search_ctx *ctx;
ntfs_log_enter("Entering\n");
mft_na = vol->mft_na;
mftbmp_na = vol->mftbmp_na;
if (size > mft_na->allocated_size || size > mft_na->initialized_size) {
errno = EIO;
@ -1422,7 +1354,7 @@ undo_data_init:
goto out;
}
ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data)
static ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol)
{
s64 ll, bit;
ntfs_attr *mft_na, *mftbmp_na;
@ -1431,7 +1363,6 @@ ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data)
ntfs_inode *base_ni;
int err;
le16 seq_no, usn;
BOOL forced_mft_data;
ntfs_log_enter("Entering\n");
@ -1440,49 +1371,7 @@ ntfs_inode *ntfs_mft_rec_alloc(ntfs_volume *vol, BOOL mft_data)
base_ni = mft_na->ni;
/*
* The first extent containing $MFT:$AT_DATA is better located
* in record 15 to make sure it can be read at mount time.
* The record 15 is prereserved as a base inode with no
* extents and no name, and it is marked in use.
*/
forced_mft_data = FALSE;
if (mft_data) {
ntfs_inode *ext_ni = ntfs_inode_open(vol, FILE_mft_data);
/*
* If record 15 cannot be opened, it is probably in
* use as an extent. Apply standard procedure for
* further extents.
*/
if (ext_ni) {
/*
* Make sure record 15 is a base extent and it has
* no name. A base inode with no name cannot be in use.
* The test based on base_mft_record fails for
* extents of MFT, so we need a special check.
* If already used, apply standard procedure.
*/
if (!ext_ni->mrec->base_mft_record
&& !ext_ni->mrec->link_count)
forced_mft_data = TRUE;
ntfs_inode_close(ext_ni);
/* Double-check, in case it is used for MFT */
if (forced_mft_data && base_ni->nr_extents) {
int i;
for (i=0; i<base_ni->nr_extents; i++) {
if (base_ni->extent_nis[i]
&& (base_ni->extent_nis[i]->mft_no
== FILE_mft_data))
forced_mft_data = FALSE;
}
}
}
}
if (forced_mft_data)
bit = FILE_mft_data;
else
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
bit = ntfs_mft_bitmap_find_free_rec(vol, base_ni);
if (bit >= 0)
goto found_free_rec;
@ -1519,26 +1408,15 @@ found_free_rec:
goto undo_mftbmp_alloc;
}
/* Sanity check that the mft record is really not in use. */
if (!forced_mft_data
&& (ntfs_is_file_record(m->magic)
&& (m->flags & MFT_RECORD_IN_USE))) {
if (ntfs_is_file_record(m->magic) && (m->flags & MFT_RECORD_IN_USE)) {
ntfs_log_error("Inode %lld is used but it wasn't marked in "
"$MFT bitmap. Fixed.\n", (long long)bit);
free(m);
goto undo_mftbmp_alloc;
}
/*
* Retrieve the former seq_no and usn so that the new record
* cannot be mistaken for the former one.
* However the original record may just be garbage, so
* use some sensible value when they cannot be retrieved.
*/
seq_no = m->sequence_number;
if (le16_to_cpu(m->usa_ofs) <= (NTFS_BLOCK_SIZE - 2))
usn = *(le16*)((u8*)m + (le16_to_cpu(m->usa_ofs) & -2));
else
usn = const_cpu_to_le16(1);
usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs));
if (ntfs_mft_record_layout(vol, bit, m)) {
ntfs_log_error("Failed to re-format mft record.\n");
free(m);
@ -1597,10 +1475,11 @@ found_free_rec:
ntfs_inode_mark_dirty(ni);
/* Initialize time, allocated and data size in ntfs_inode struct. */
ni->data_size = ni->allocated_size = 0;
ni->flags = const_cpu_to_le32(0);
ni->flags = 0;
ni->creation_time = ni->last_data_change_time =
ni->last_mft_change_time =
ni->last_access_time = ntfs_current_time();
ni->last_access_time = time(NULL);
set_nino_flag(ni, TimesDirty);
/* Update the default mft allocation position if it was used. */
if (!base_ni)
vol->mft_data_pos = bit + 1;
@ -1646,9 +1525,8 @@ err_out:
* @base_ni is NULL we start where we last stopped and we perform wrap around
* when we reach the end. Note, we do not try to allocate mft records below
* number 24 because numbers 0 to 15 are the defined system files anyway and 16
* to 24 are used for storing extension mft records or used by chkdsk to store
* its log. However the record number 15 is dedicated to the first extent to
* the $DATA attribute of $MFT. This is required to avoid the possibility
* to 24 are special in that they are used for storing extension mft records
* for the $DATA attribute of $MFT. This is required to avoid the possibility
* of creating a run list with a circular dependence which once written to disk
* can never be read in again. Windows will only use records 16 to 24 for
* normal files if the volume is completely out of space. We never use them
@ -1714,9 +1592,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
MFT_RECORD *m;
ntfs_inode *ni = NULL;
int err;
u32 usa_ofs;
le16 seq_no, usn;
BOOL oldwarn;
if (base_ni)
ntfs_log_enter("Entering (allocating an extent mft record for "
@ -1730,7 +1606,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, ntfs_inode *base_ni)
}
if (ntfs_is_mft(base_ni)) {
ni = ntfs_mft_rec_alloc(vol, FALSE);
ni = ntfs_mft_rec_alloc(vol);
goto out;
}
@ -1775,7 +1651,6 @@ retry:
(long long)mftbmp_na->initialized_size);
if (mftbmp_na->initialized_size + 8 > mftbmp_na->allocated_size) {
const s64 old_allocated_size = mftbmp_na->allocated_size;
int ret = ntfs_mft_bitmap_extend_allocation(vol);
if (ret == STATUS_ERROR)
@ -1792,9 +1667,6 @@ retry:
(long long)mftbmp_na->allocated_size,
(long long)mftbmp_na->data_size,
(long long)mftbmp_na->initialized_size);
vol->free_mft_records +=
(mftbmp_na->allocated_size - old_allocated_size) << 3;
}
/*
* We now have sufficient allocated space, extend the initialized_size
@ -1834,22 +1706,10 @@ 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) && (m->flags & MFT_RECORD_IN_USE)) {
ntfs_log_error("Inode %lld is used but it wasn't marked in "
@ -1858,16 +1718,7 @@ found_free_rec:
goto retry;
}
seq_no = m->sequence_number;
/*
* As ntfs_mft_record_read() returns what has been read
* even when the fixups have been found bad, we have to
* check where we fetch the initial usn from.
*/
usa_ofs = le16_to_cpu(m->usa_ofs);
if (!(usa_ofs & 1) && (usa_ofs < NTFS_BLOCK_SIZE)) {
usn = *(le16*)((u8*)m + usa_ofs);
} else
usn = const_cpu_to_le16(1);
usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs));
if (ntfs_mft_record_layout(vol, bit, m)) {
ntfs_log_error("Failed to re-format mft record.\n");
free(m);
@ -1927,10 +1778,11 @@ found_free_rec:
ntfs_inode_mark_dirty(ni);
/* Initialize time, allocated and data size in ntfs_inode struct. */
ni->data_size = ni->allocated_size = 0;
ni->flags = const_cpu_to_le32(0);
ni->flags = 0;
ni->creation_time = ni->last_data_change_time =
ni->last_mft_change_time =
ni->last_access_time = ntfs_current_time();
ni->last_access_time = time(NULL);
set_nino_flag(ni, TimesDirty);
/* Update the default mft allocation position if it was used. */
if (!base_ni)
vol->mft_data_pos = bit + 1;
@ -2010,11 +1862,7 @@ int ntfs_mft_record_free(ntfs_volume *vol, ntfs_inode *ni)
}
/* Throw away the now freed inode. */
#if CACHE_NIDATA_SIZE
if (!ntfs_inode_real_close(ni)) {
#else
if (!ntfs_inode_close(ni)) {
#endif
vol->free_mft_records++;
return 0;
}

View File

@ -1,6 +1,7 @@
/**
* misc.c : miscellaneous :
* - dealing with errors in memory allocation
* - data caching
*
* Copyright (c) 2008 Jean-Pierre Andre
*
@ -32,6 +33,7 @@
#endif
#include "types.h"
#include "security.h"
#include "misc.h"
#include "logging.h"
@ -60,18 +62,303 @@ void *ntfs_malloc(size_t size)
return p;
}
void *ntfs_realloc(void *ptr, size_t size)
{
void *p;
/*
* General functions to deal with LRU caches
*
* The cached data have to be organized in a structure in which
* the first fields must follow a mandatory pattern and further
* fields may contain any fixed size data. They are stored in an
* LRU list.
*
* A compare function must be provided for finding a wanted entry
* in the cache. Another function may be provided for invalidating
* an entry to facilitate multiple invalidation.
*
* These functions never return error codes. When there is a
* shortage of memory, data is simply not cached.
*/
p = realloc(ptr, size);
if (!p)
ntfs_log_perror("Failed to realloc %lld bytes",
(long long)size);
return p;
/*
* Fetch an entry from cache
*
* returns the cache entry, or NULL if not available
*/
struct CACHED_GENERIC *ntfs_fetch_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *wanted, cache_compare compare)
{
struct CACHED_GENERIC *current;
struct CACHED_GENERIC *previous;
current = (struct CACHED_GENERIC*)NULL;
if (cache) {
/*
* Search sequentially in LRU list
*/
current = cache->most_recent_entry;
previous = (struct CACHED_GENERIC*)NULL;
while (current
&& compare(current, wanted)) {
previous = current;
current = current->next;
}
if (current)
cache->hits++;
if (current && previous) {
/*
* found and not at head of list, unlink from current
* position and relink as head of list
*/
previous->next = current->next;
current->next = cache->most_recent_entry;
cache->most_recent_entry = current;
}
cache->reads++;
}
return (current);
}
void ntfs_free(void *p)
/*
* Enter an inode number into cache
* returns the cache entry or NULL if not possible
*/
struct CACHED_GENERIC *ntfs_enter_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item, cache_compare compare)
{
free(p);
struct CACHED_GENERIC *current;
struct CACHED_GENERIC *previous;
struct CACHED_GENERIC *before;
current = (struct CACHED_GENERIC*)NULL;
if (cache) {
/*
* Search sequentially in LRU list to locate the end,
* and find out whether the entry is already in list
* As we normally go to the end, no statistics is
* kept.
*/
current = cache->most_recent_entry;
previous = (struct CACHED_GENERIC*)NULL;
before = (struct CACHED_GENERIC*)NULL;
while (current
&& compare(current, item)) {
before = previous;
previous = current;
current = current->next;
}
if (!current) {
/*
* Not in list, get a free entry or reuse the
* last entry, and relink as head of list
* Note : we assume at least three entries, so
* before, previous and first are different when
* an entry is reused.
*/
if (cache->free_entry) {
current = cache->free_entry;
cache->free_entry = cache->free_entry->next;
if (item->varsize) {
current->variable = ntfs_malloc(
item->varsize);
} else
current->variable = (void*)NULL;
current->varsize = item->varsize;
} else {
before->next = (struct CACHED_GENERIC*)NULL;
current = previous;
if (item->varsize) {
if (current->varsize)
current->variable = realloc(
current->variable,
item->varsize);
else
current->variable = ntfs_malloc(
item->varsize);
} else {
if (current->varsize)
free(current->variable);
current->variable = (void*)NULL;
}
current->varsize = item->varsize;
}
current->next = cache->most_recent_entry;
cache->most_recent_entry = current;
memcpy(current->fixed, item->fixed, cache->fixed_size);
if (item->varsize) {
if (current->variable) {
memcpy(current->variable,
item->variable, item->varsize);
} else {
/*
* no more memory for variable part
* recycle entry in free list
* not an error, just uncacheable
*/
cache->most_recent_entry = current->next;
current->next = cache->free_entry;
cache->free_entry = current;
current = (struct CACHED_GENERIC*)NULL;
}
} else {
current->variable = (void*)NULL;
current->varsize = 0;
}
}
cache->writes++;
}
return (current);
}
/*
* Invalidate entries in cache
*
* Several entries may have to be invalidated (at least for inodes
* associated to directories which have been renamed), a different
* compare function may be provided to select entries to invalidate
*
* Returns the number of deleted entries, this can be used by
* the caller to signal a cache corruption if the entry was
* supposed to be found.
*/
int ntfs_invalidate_cache(struct CACHE_HEADER *cache,
const struct CACHED_GENERIC *item, cache_compare compare)
{
struct CACHED_GENERIC *current;
struct CACHED_GENERIC *previous;
int count;
current = (struct CACHED_GENERIC*)NULL;
count = 0;
if (cache) {
/*
* Search sequentially in LRU list
*/
current = cache->most_recent_entry;
previous = (struct CACHED_GENERIC*)NULL;
while (current) {
if (!compare(current, item)) {
/*
* Relink into free list
*/
if (previous)
previous->next = current->next;
else
cache->most_recent_entry = current->next;
current->next = cache->free_entry;
cache->free_entry = current;
if (current->variable)
free(current->variable);
current->varsize = 0;
if (previous)
current = previous->next;
else
current = cache->most_recent_entry;
count++;
} else {
previous = current;
current = current->next;
}
}
}
return (count);
}
/*
* Free memory allocated to a cache
*/
static void ntfs_free_cache(struct CACHE_HEADER *cache)
{
struct CACHED_GENERIC *entry;
if (cache) {
for (entry=cache->most_recent_entry; entry; entry=entry->next)
if (entry->variable)
free(entry->variable);
free(cache);
}
}
/*
* Create a cache
*
* Returns the cache header, or NULL if the cache could not be created
*/
static struct CACHE_HEADER *ntfs_create_cache(const char *name,
int full_item_size, int item_count)
{
struct CACHE_HEADER *cache;
struct CACHED_GENERIC *p;
struct CACHED_GENERIC *q;
int i;
cache = (struct CACHE_HEADER*)
ntfs_malloc(sizeof(struct CACHE_HEADER)
+ item_count*full_item_size);
if (cache) {
cache->name = name;
cache->fixed_size = full_item_size - sizeof(struct CACHED_GENERIC);
cache->reads = 0;
cache->writes = 0;
cache->hits = 0;
/* chain the entries, and mark an invalid entry */
cache->most_recent_entry = (struct CACHED_GENERIC*)NULL;
cache->free_entry = &cache->entry[0];
p = &cache->entry[0];
for (i=0; i<(item_count - 1); i++) {
q = (struct CACHED_GENERIC*)((char*)p + full_item_size);
p->next = q;
p->variable = (void*)NULL;
p->varsize = 0;
p = q;
}
/* special for the last entry */
p->next = (struct CACHED_GENERIC*)NULL;
p->variable = (void*)NULL;
p->varsize = 0;
}
return (cache);
}
/*
* Create all LRU caches
*
* No error return, if creation is not possible, cacheing will
* just be not available
*/
void ntfs_create_lru_caches(ntfs_volume *vol)
{
#if CACHE_INODE_SIZE
/* inode cache */
vol->xinode_cache = ntfs_create_cache("inode",
sizeof(struct CACHED_INODE), CACHE_INODE_SIZE);
#endif
vol->securid_cache = ntfs_create_cache("securid",
sizeof(struct CACHED_SECURID), CACHE_SECURID_SIZE);
#if CACHE_LEGACY_SIZE
vol->legacy_cache = ntfs_create_cache("legacy",
sizeof(struct CACHED_PERMISSIONS_LEGACY), CACHE_LEGACY_SIZE);
#endif
}
/*
* Free all LRU caches
*/
void ntfs_free_lru_caches(ntfs_volume *vol)
{
#if CACHE_INODE_SIZE
ntfs_free_cache(vol->xinode_cache);
#endif
ntfs_free_cache(vol->securid_cache);
#if CACHE_LEGACY_SIZE
ntfs_free_cache(vol->legacy_cache);
#endif
}

View File

@ -31,21 +31,6 @@
#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
@ -62,8 +47,7 @@ is_valid_record(u32 size, u16 usa_ofs, u16 usa_count)
* EIO Multi sector transfer error was detected. Magic of the NTFS
* record in @b will have been set to "BAAD".
*/
int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
BOOL warn)
int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
{
u16 usa_ofs, usa_count, usn;
u16 *usa_pos, *data_pos;
@ -72,18 +56,16 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
/* Setup the variables. */
usa_ofs = le16_to_cpu(b->usa_ofs);
usa_count = le16_to_cpu(b->usa_count);
if (!is_valid_record(size, usa_ofs, usa_count)) {
/* 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) {
errno = EINVAL;
if (warn) {
ntfs_log_perror("%s: magic: 0x%08lx size: %ld "
" usa_ofs: %d usa_count: %u",
__FUNCTION__,
(long)le32_to_cpu(*(le32 *)b),
(long)size, (int)usa_ofs,
(unsigned int)usa_count);
}
ntfs_log_perror("%s: magic: 0x%08x size: %d usa_ofs: %d "
"usa_count: %d", __FUNCTION__, *(le32 *)b,
size, usa_ofs, usa_count);
return -1;
}
/* Position of usn in update sequence array. */
@ -103,7 +85,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! )-:
@ -113,7 +95,7 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
errno = EIO;
ntfs_log_perror("Incomplete multi-sector transfer: "
"magic: 0x%08x size: %d usa_ofs: %d usa_count:"
" %d data: %d usn: %d", le32_to_cpu(*(le32 *)b), size,
" %d data: %d usn: %d", *(le32 *)b, size,
usa_ofs, usa_count, *data_pos, usn);
b->magic = magic_BAAD;
return -1;
@ -121,10 +103,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);
usa_count = le16_to_cpu(b->usa_count) - 1;
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.
@ -136,16 +118,6 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
return 0;
}
/*
* Deprotect multi sector transfer protected data
* with a warning if an error is found.
*/
int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
{
return (ntfs_mst_post_read_fixup_warn(b,size,TRUE));
}
/**
* ntfs_mst_pre_write_fixup - apply multi sector transfer protection
* @b: pointer to the data to protect
@ -169,8 +141,7 @@ int ntfs_mst_post_read_fixup(NTFS_RECORD *b, const u32 size)
int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
{
u16 usa_ofs, usa_count, usn;
le16 le_usn;
le16 *usa_pos, *data_pos;
u16 *usa_pos, *data_pos;
ntfs_log_trace("Entering\n");
@ -183,15 +154,18 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
}
/* Setup the variables. */
usa_ofs = le16_to_cpu(b->usa_ofs);
usa_count = le16_to_cpu(b->usa_count);
if (!is_valid_record(size, usa_ofs, usa_count)) {
/* 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) {
errno = EINVAL;
ntfs_log_perror("%s", __FUNCTION__);
return -1;
}
/* Position of usn in update sequence array. */
usa_pos = (le16*)((u8*)b + usa_ofs);
usa_pos = (u16*)((u8*)b + usa_ofs);
/*
* Cyclically increment the update sequence number
* (skipping 0 and -1, i.e. 0xffff).
@ -199,21 +173,21 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
usn = le16_to_cpup(usa_pos) + 1;
if (usn == 0xffff || !usn)
usn = 1;
le_usn = cpu_to_le16(usn);
*usa_pos = le_usn;
/* Position in data of first le16 that needs fixing up. */
data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1;
usn = cpu_to_le16(usn);
*usa_pos = usn;
/* Position in data of first u16 that needs fixing up. */
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 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.
*/
*(++usa_pos) = *data_pos;
/* Apply fixup to data. */
*data_pos = le_usn;
*data_pos = usn;
/* Increment position in data as well. */
data_pos += NTFS_BLOCK_SIZE/sizeof(le16);
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
}
return 0;
}
@ -232,7 +206,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);
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
ntfs_log_trace("Entering\n");
@ -243,7 +217,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

@ -1,636 +0,0 @@
/**
* object_id.c - Processing of object ids
*
* This module is part of ntfs-3g library
*
* Copyright (c) 2009-2019 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#include "compat.h"
#include "types.h"
#include "debug.h"
#include "attrib.h"
#include "inode.h"
#include "dir.h"
#include "volume.h"
#include "mft.h"
#include "index.h"
#include "lcnalloc.h"
#include "object_id.h"
#include "logging.h"
#include "misc.h"
#include "xattrs.h"
/*
* Endianness considerations
*
* According to RFC 4122, GUIDs should be printed with the most
* significant byte first, and the six fields be compared individually
* for ordering. RFC 4122 does not define the internal representation.
*
* Windows apparently stores the first three fields in little endian
* order, and the last two fields in big endian order.
*
* Here we always copy disk images with no endianness change,
* and, for indexing, GUIDs are compared as if they were a sequence
* of four little-endian unsigned 32 bit integers (as Windows
* does it that way.)
*
* --------------------- begin from RFC 4122 ----------------------
* Consider each field of the UUID to be an unsigned integer as shown
* in the table in section Section 4.1.2. Then, to compare a pair of
* UUIDs, arithmetically compare the corresponding fields from each
* UUID in order of significance and according to their data type.
* Two UUIDs are equal if and only if all the corresponding fields
* are equal.
*
* UUIDs, as defined in this document, can also be ordered
* lexicographically. For a pair of UUIDs, the first one follows the
* second if the most significant field in which the UUIDs differ is
* greater for the first UUID. The second precedes the first if the
* most significant field in which the UUIDs differ is greater for
* the second UUID.
*
* The fields are encoded as 16 octets, with the sizes and order of the
* fields defined above, and with each field encoded with the Most
* Significant Byte first (known as network byte order). Note that the
* field names, particularly for multiplexed fields, follow historical
* practice.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | time_low |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | time_mid | time_hi_and_version |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |clk_seq_hi_res | clk_seq_low | node (0-1) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | node (2-5) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* ---------------------- end from RFC 4122 -----------------------
*/
typedef struct {
union {
/* alignment may be needed to evaluate collations */
u32 alignment;
GUID guid;
} object_id;
} OBJECT_ID_INDEX_KEY;
typedef struct {
le64 file_id;
GUID birth_volume_id;
GUID birth_object_id;
GUID domain_id;
} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
struct OBJECT_ID_INDEX { /* index entry in $Extend/$ObjId */
INDEX_ENTRY_HEADER header;
OBJECT_ID_INDEX_KEY key;
OBJECT_ID_INDEX_DATA data;
} ;
static ntfschar objid_index_name[] = { const_cpu_to_le16('$'),
const_cpu_to_le16('O') };
/*
* Set the index for a new object id
*
* Returns 0 if success
* -1 if failure, explained by errno
*/
static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo,
const OBJECT_ID_ATTR *object_id)
{
struct OBJECT_ID_INDEX indx;
u64 file_id_cpu;
le64 file_id;
le16 seqn;
seqn = ni->mrec->sequence_number;
file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn));
file_id = cpu_to_le64(file_id_cpu);
indx.header.data_offset = const_cpu_to_le16(
sizeof(INDEX_ENTRY_HEADER)
+ sizeof(OBJECT_ID_INDEX_KEY));
indx.header.data_length = const_cpu_to_le16(
sizeof(OBJECT_ID_INDEX_DATA));
indx.header.reservedV = const_cpu_to_le32(0);
indx.header.length = const_cpu_to_le16(
sizeof(struct OBJECT_ID_INDEX));
indx.header.key_length = const_cpu_to_le16(
sizeof(OBJECT_ID_INDEX_KEY));
indx.header.flags = const_cpu_to_le16(0);
indx.header.reserved = const_cpu_to_le16(0);
memcpy(&indx.key.object_id,object_id,sizeof(GUID));
indx.data.file_id = file_id;
memcpy(&indx.data.birth_volume_id,
&object_id->birth_volume_id,sizeof(GUID));
memcpy(&indx.data.birth_object_id,
&object_id->birth_object_id,sizeof(GUID));
memcpy(&indx.data.domain_id,
&object_id->domain_id,sizeof(GUID));
ntfs_index_ctx_reinit(xo);
return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx));
}
/*
* Open the $Extend/$ObjId file and its index
*
* Return the index context if opened
* or NULL if an error occurred (errno tells why)
*
* The index has to be freed and inode closed when not needed any more.
*/
static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
{
u64 inum;
ntfs_inode *ni;
ntfs_inode *dir_ni;
ntfs_index_context *xo;
/* do not use path_name_to inode - could reopen root */
dir_ni = ntfs_inode_open(vol, FILE_Extend);
ni = (ntfs_inode*)NULL;
if (dir_ni) {
inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$ObjId");
if (inum != (u64)-1)
ni = ntfs_inode_open(vol, inum);
ntfs_inode_close(dir_ni);
}
if (ni) {
xo = ntfs_index_ctx_get(ni, objid_index_name, 2);
if (!xo) {
ntfs_inode_close(ni);
}
} else
xo = (ntfs_index_context*)NULL;
return (xo);
}
/*
* Merge object_id data stored in the index into
* a full object_id struct.
*
* returns 0 if merging successful
* -1 if no data could be merged. This is generally not an error
*/
static int merge_index_data(ntfs_inode *ni,
const OBJECT_ID_ATTR *objectid_attr,
OBJECT_ID_ATTR *full_objectid)
{
OBJECT_ID_INDEX_KEY key;
struct OBJECT_ID_INDEX *entry;
ntfs_index_context *xo;
ntfs_inode *xoni;
int res;
res = -1;
xo = open_object_id_index(ni->vol);
if (xo) {
memcpy(&key.object_id,objectid_attr,sizeof(GUID));
if (!ntfs_index_lookup(&key,
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
entry = (struct OBJECT_ID_INDEX*)xo->entry;
/* make sure inode numbers match */
if (entry
&& (MREF(le64_to_cpu(entry->data.file_id))
== ni->mft_no)) {
memcpy(&full_objectid->birth_volume_id,
&entry->data.birth_volume_id,
sizeof(GUID));
memcpy(&full_objectid->birth_object_id,
&entry->data.birth_object_id,
sizeof(GUID));
memcpy(&full_objectid->domain_id,
&entry->data.domain_id,
sizeof(GUID));
res = 0;
}
}
xoni = xo->ni;
ntfs_index_ctx_put(xo);
ntfs_inode_close(xoni);
}
return (res);
}
/*
* Remove an object id index entry if attribute present
*
* Returns the size of existing object id
* (the existing object_d is returned)
* -1 if failure, explained by errno
*/
static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
OBJECT_ID_ATTR *old_attr)
{
OBJECT_ID_INDEX_KEY key;
struct OBJECT_ID_INDEX *entry;
s64 size;
int ret;
ret = na->data_size;
if (ret) {
/* read the existing object id attribute */
size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr);
if (size >= (s64)sizeof(GUID)) {
memcpy(&key.object_id,
&old_attr->object_id,sizeof(GUID));
if (!ntfs_index_lookup(&key,
sizeof(OBJECT_ID_INDEX_KEY), xo)) {
entry = (struct OBJECT_ID_INDEX*)xo->entry;
memcpy(&old_attr->birth_volume_id,
&entry->data.birth_volume_id,
sizeof(GUID));
memcpy(&old_attr->birth_object_id,
&entry->data.birth_object_id,
sizeof(GUID));
memcpy(&old_attr->domain_id,
&entry->data.domain_id,
sizeof(GUID));
if (ntfs_index_rm(xo))
ret = -1;
}
} else {
ret = -1;
errno = ENODATA;
}
}
return (ret);
}
/*
* Update the object id and index
*
* The object_id attribute should have been created and the
* non-duplication of the GUID should have been checked before.
*
* Returns 0 if success
* -1 if failure, explained by errno
* If could not remove the existing index, nothing is done,
* If could not write the new data, no index entry is inserted
* If failed to insert the index, data is removed
*/
static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
const OBJECT_ID_ATTR *value, size_t size)
{
OBJECT_ID_ATTR old_attr;
ntfs_attr *na;
int oldsize;
int written;
int res;
res = 0;
na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
if (na) {
memset(&old_attr, 0, sizeof(OBJECT_ID_ATTR));
/* remove the existing index entry */
oldsize = remove_object_id_index(na,xo,&old_attr);
if (oldsize < 0)
res = -1;
else {
/* resize attribute */
res = ntfs_attr_truncate(na, (s64)sizeof(GUID));
/* write the object_id in attribute */
if (!res && value) {
written = (int)ntfs_attr_pwrite(na,
(s64)0, (s64)sizeof(GUID),
&value->object_id);
if (written != (s64)sizeof(GUID)) {
ntfs_log_error("Failed to update "
"object id\n");
errno = EIO;
res = -1;
}
}
/* overwrite index data with new value */
memcpy(&old_attr, value,
(size < sizeof(OBJECT_ID_ATTR)
? size : sizeof(OBJECT_ID_ATTR)));
if (!res
&& set_object_id_index(ni,xo,&old_attr)) {
/*
* If cannot index, try to remove the object
* id and log the error. There will be an
* inconsistency if removal fails.
*/
ntfs_attr_rm(na);
ntfs_log_error("Failed to index object id."
" Possible corruption.\n");
}
}
ntfs_attr_close(na);
NInoSetDirty(ni);
} else
res = -1;
return (res);
}
/*
* Add a (dummy) object id to an inode if it does not exist
*
* returns 0 if attribute was inserted (or already present)
* -1 if adding failed (explained by errno)
*/
static int add_object_id(ntfs_inode *ni, int flags)
{
int res;
u8 dummy;
res = -1; /* default return */
if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) {
if (!(flags & XATTR_REPLACE)) {
/*
* no object id attribute : add one,
* apparently, this does not feed the new value in
* Note : NTFS version must be >= 3
*/
if (ni->vol->major_ver >= 3) {
res = ntfs_attr_add(ni, AT_OBJECT_ID,
AT_UNNAMED, 0, &dummy, (s64)0);
NInoSetDirty(ni);
} else
errno = EOPNOTSUPP;
} else
errno = ENODATA;
} else {
if (flags & XATTR_CREATE)
errno = EEXIST;
else
res = 0;
}
return (res);
}
/*
* Delete an object_id index entry
*
* Returns 0 if success
* -1 if failure, explained by errno
*/
int ntfs_delete_object_id_index(ntfs_inode *ni)
{
ntfs_index_context *xo;
ntfs_inode *xoni;
ntfs_attr *na;
OBJECT_ID_ATTR old_attr;
int res;
res = 0;
na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
if (na) {
/*
* read the existing object id
* and un-index it
*/
xo = open_object_id_index(ni->vol);
if (xo) {
if (remove_object_id_index(na,xo,&old_attr) < 0)
res = -1;
xoni = xo->ni;
ntfs_index_entry_mark_dirty(xo);
NInoSetDirty(xoni);
ntfs_index_ctx_put(xo);
ntfs_inode_close(xoni);
}
ntfs_attr_close(na);
}
return (res);
}
/*
* Get the ntfs object id into an extended attribute
*
* If present, the object_id from the attribute and the GUIDs
* from the index are returned (formatted as OBJECT_ID_ATTR)
*
* Returns the global size (can be 0, 16 or 64)
* and the buffer is updated if it is long enough
*/
int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size)
{
OBJECT_ID_ATTR full_objectid;
OBJECT_ID_ATTR *objectid_attr;
s64 attr_size;
int full_size;
full_size = 0; /* default to no data and some error to be defined */
if (ni) {
objectid_attr = (OBJECT_ID_ATTR*)ntfs_attr_readall(ni,
AT_OBJECT_ID,(ntfschar*)NULL, 0, &attr_size);
if (objectid_attr) {
/* restrict to only GUID present in attr */
if (attr_size == sizeof(GUID)) {
memcpy(&full_objectid.object_id,
objectid_attr,sizeof(GUID));
full_size = sizeof(GUID);
/* get data from index, if any */
if (!merge_index_data(ni, objectid_attr,
&full_objectid)) {
full_size = sizeof(OBJECT_ID_ATTR);
}
if (full_size <= (s64)size) {
if (value)
memcpy(value,&full_objectid,
full_size);
else
errno = EINVAL;
}
} else {
/* unexpected size, better return unsupported */
errno = EOPNOTSUPP;
full_size = 0;
}
free(objectid_attr);
} else
errno = ENODATA;
}
return (full_size ? (int)full_size : -errno);
}
/*
* Set the object id from an extended attribute
*
* The first 16 bytes are the new object id, they can be followed
* by the birth volume id, the birth object id and the domain id.
* If they are not present, their previous value is kept.
* Only the object id is stored into the attribute, all the fields
* are stored into the index.
*
* Returns 0, or -1 if there is a problem
*/
int ntfs_set_ntfs_object_id(ntfs_inode *ni,
const char *value, size_t size, int flags)
{
OBJECT_ID_INDEX_KEY key;
ntfs_inode *xoni;
ntfs_index_context *xo;
int res;
res = 0;
if (ni && value && (size >= sizeof(GUID))) {
xo = open_object_id_index(ni->vol);
if (xo) {
/* make sure the GUID was not used elsewhere */
memcpy(&key.object_id, value, sizeof(GUID));
if ((ntfs_index_lookup(&key,
sizeof(OBJECT_ID_INDEX_KEY), xo))
|| (MREF_LE(((struct OBJECT_ID_INDEX*)xo->entry)
->data.file_id) == ni->mft_no)) {
ntfs_index_ctx_reinit(xo);
res = add_object_id(ni, flags);
if (!res) {
/* update value and index */
res = update_object_id(ni,xo,
(const OBJECT_ID_ATTR*)value,
size);
}
} else {
/* GUID is present elsewhere */
res = -1;
errno = EEXIST;
}
xoni = xo->ni;
ntfs_index_entry_mark_dirty(xo);
NInoSetDirty(xoni);
ntfs_index_ctx_put(xo);
ntfs_inode_close(xoni);
} else {
res = -1;
}
} else {
errno = EINVAL;
res = -1;
}
return (res ? -1 : 0);
}
/*
* Remove the object id
*
* Returns 0, or -1 if there is a problem
*/
int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
{
int res;
int olderrno;
ntfs_attr *na;
ntfs_inode *xoni;
ntfs_index_context *xo;
int oldsize;
OBJECT_ID_ATTR old_attr;
res = 0;
if (ni) {
/*
* open and delete the object id
*/
na = ntfs_attr_open(ni, AT_OBJECT_ID,
AT_UNNAMED,0);
if (na) {
/* first remove index (old object id needed) */
xo = open_object_id_index(ni->vol);
if (xo) {
oldsize = remove_object_id_index(na,xo,
&old_attr);
if (oldsize < 0) {
res = -1;
} else {
/* now remove attribute */
res = ntfs_attr_rm(na);
if (res
&& (oldsize > (int)sizeof(GUID))) {
/*
* If we could not remove the
* attribute, try to restore the
* index and log the error. There
* will be an inconsistency if
* the reindexing fails.
*/
set_object_id_index(ni, xo,
&old_attr);
ntfs_log_error(
"Failed to remove object id."
" Possible corruption.\n");
}
}
xoni = xo->ni;
ntfs_index_entry_mark_dirty(xo);
NInoSetDirty(xoni);
ntfs_index_ctx_put(xo);
ntfs_inode_close(xoni);
}
olderrno = errno;
ntfs_attr_close(na);
/* avoid errno pollution */
if (errno == ENOENT)
errno = olderrno;
} else {
errno = ENODATA;
res = -1;
}
NInoSetDirty(ni);
} else {
errno = EINVAL;
res = -1;
}
return (res ? -1 : 0);
}

View File

@ -1,103 +0,0 @@
/*
* realpath.c - realpath() aware of device mapper
* Originated from the util-linux project.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include "param.h"
#include "realpath.h"
/* If there is no realpath() on the system, provide a dummy one. */
#ifndef HAVE_REALPATH
char *ntfs_realpath(const char *path, char *resolved_path)
{
strncpy(resolved_path, path, PATH_MAX);
resolved_path[PATH_MAX] = '\0';
return resolved_path;
}
#endif
#ifdef linux
/*
* Converts private "dm-N" names to "/dev/mapper/<name>"
*
* Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
* provides the real DM device names in /sys/block/<ptname>/dm/name
*/
static char *
canonicalize_dm_name(const char *ptname, char *canonical)
{
FILE *f;
size_t sz;
char name[MAPPERNAMELTH + 16];
char path[sizeof(name) + 16];
char *res = NULL;
snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
if (!(f = fopen(path, "r")))
return NULL;
/* read "<name>\n" from sysfs */
if (fgets(name, sizeof(name), f) && (sz = strlen(name)) > 1) {
name[sz - 1] = '\0';
snprintf(path, sizeof(path), "/dev/mapper/%s", name);
res = strcpy(canonical, path);
}
fclose(f);
return res;
}
/*
* Canonicalize a device path
*
* Workaround from "basinilya" for fixing device mapper paths.
*
* Background (Phillip Susi, 2011-04-09)
* - ntfs-3g canonicalizes the device name so that if you mount with
* /dev/mapper/foo, the device name listed in mtab is /dev/dm-n,
* so you can not umount /dev/mapper/foo
* - umount won't even recognize and translate /dev/dm-n to the mount
* point, apparently because of the '-' involved. Editing mtab and
* removing the '-' allows you to umount /dev/dmn successfully.
*
* This code restores the devmapper name after canonicalization,
* until a proper fix is implemented.
*/
char *ntfs_realpath_canonicalize(const char *path, char *canonical)
{
char *p;
if (path == NULL)
return NULL;
if (!ntfs_realpath(path, canonical))
return NULL;
p = strrchr(canonical, '/');
if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
p = canonicalize_dm_name(p+1, canonical);
if (p)
return p;
}
return canonical;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004 Yura Pakhuchiy
* Copyright (c) 2007-2022 Jean-Pierre Andre
* Copyright (c) 2007-2009 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
@ -117,34 +117,18 @@ static runlist_element *ntfs_rl_realloc(runlist_element *rl, int old_size,
*
* Returns the reallocated runlist
* or NULL if reallocation was not possible (with errno set)
* the runlist is left unchanged if the reallocation fails
*/
runlist_element *ntfs_rl_extend(ntfs_attr *na, runlist_element *rl,
int more_entries)
runlist_element *ntfs_rl_extend(runlist_element *rl, int more_entries)
{
runlist_element *newrl;
int last;
int irl;
if (na->rl && rl) {
irl = (int)(rl - na->rl);
last = irl;
while (na->rl[last].length)
last++;
newrl = ntfs_rl_realloc(na->rl,last+1,last+more_entries+1);
if (!newrl) {
errno = ENOMEM;
rl = (runlist_element*)NULL;
} else {
na->rl = newrl;
rl = &newrl[irl];
}
} else {
ntfs_log_error("Cannot extend unmapped runlist");
errno = EIO;
rl = (runlist_element*)NULL;
}
last = 0;
while (rl[last].length)
last++;
rl = ntfs_rl_realloc(rl,last+1,last+more_entries+1);
if (!rl)
errno = ENOMEM;
return (rl);
}
@ -780,7 +764,7 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl,
* two into one, if that is possible (we check for overlap and discard the new
* runlist if overlap present before returning NULL, with errno = ERANGE).
*/
static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
const ATTR_RECORD *attr, runlist_element *old_rl)
{
VCN vcn; /* Current vcn. */
@ -918,18 +902,11 @@ static runlist_element *ntfs_mapping_pairs_decompress_i(const ntfs_volume *vol,
"array.\n");
goto err_out;
}
/* chkdsk accepts zero-sized runs only for holes */
if ((lcn != (LCN)-1) && !rl[rlpos].length) {
ntfs_log_debug(
"Invalid zero-sized data run.\n");
goto err_out;
}
/* Enter the current lcn into the runlist element. */
rl[rlpos].lcn = lcn;
}
/* Get to the next runlist element, skipping zero-sized holes */
if (rl[rlpos].length)
rlpos++;
/* Get to the next runlist element. */
rlpos++;
/* Increment the buffer position to the next mapping pair. */
buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1;
}
@ -946,45 +923,40 @@ mpa_err:
"attribute.\n");
goto err_out;
}
/*
* If this is the base of runlist (if 'lowest_vcn' is 0), then
* 'allocated_size' is valid, and we can use it to compute the total
* number of clusters across all extents. If the runlist covers all
* clusters, then it fits into a single extent and we can terminate
* the runlist with LCN_NOENT. Otherwise, we must terminate the runlist
* with LCN_RL_NOT_MAPPED and let the caller look for more extents.
*/
/* Setup not mapped runlist element if this is the base extent. */
if (!attr->lowest_vcn) {
VCN num_clusters;
VCN max_cluster;
num_clusters = ((sle64_to_cpu(attr->allocated_size) +
max_cluster = ((sle64_to_cpu(attr->allocated_size) +
vol->cluster_size - 1) >>
vol->cluster_size_bits);
if (num_clusters > vcn) {
vol->cluster_size_bits) - 1;
/*
* A highest_vcn of zero means this is a single extent
* attribute so simply terminate the runlist with LCN_ENOENT).
*/
if (deltaxcn) {
/*
* The runlist doesn't cover all the clusters, so there
* must be more extents.
* If there is a difference between the highest_vcn and
* the highest cluster, the runlist is either corrupt
* or, more likely, there are more extents following
* this one.
*/
ntfs_log_debug("More extents to follow; vcn = 0x%llx, "
"num_clusters = 0x%llx\n",
(long long)vcn,
(long long)num_clusters);
rl[rlpos].vcn = vcn;
vcn += rl[rlpos].length = num_clusters - vcn;
rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
rlpos++;
} else if (vcn > num_clusters) {
/*
* There are more VCNs in the runlist than expected, so
* the runlist is corrupt.
*/
ntfs_log_error("Corrupt attribute. vcn = 0x%llx, "
"num_clusters = 0x%llx\n",
(long long)vcn,
(long long)num_clusters);
goto mpa_err;
if (deltaxcn < max_cluster) {
ntfs_log_debug("More extents to follow; deltaxcn = "
"0x%llx, max_cluster = 0x%llx\n",
(long long)deltaxcn,
(long long)max_cluster);
rl[rlpos].vcn = vcn;
vcn += rl[rlpos].length = max_cluster - deltaxcn;
rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED;
rlpos++;
} else if (deltaxcn > max_cluster) {
ntfs_log_debug("Corrupt attribute. deltaxcn = "
"0x%llx, max_cluster = 0x%llx\n",
(long long)deltaxcn,
(long long)max_cluster);
goto mpa_err;
}
}
rl[rlpos].lcn = (LCN)LCN_ENOENT;
} else /* Not the base extent. There may be more extents to follow. */
@ -994,18 +966,13 @@ mpa_err:
rl[rlpos].vcn = vcn;
rl[rlpos].length = (s64)0;
/* If no existing runlist was specified, we are done. */
if (!old_rl || !old_rl[0].length) {
if (!old_rl) {
ntfs_log_debug("Mapping pairs array successfully decompressed:\n");
ntfs_debug_runlist_dump(rl);
if (old_rl)
free(old_rl);
return rl;
}
/* Now combine the new and old runlists checking for overlaps. */
if (rl[0].length)
old_rl = ntfs_runlists_merge(old_rl, rl);
else
free(rl);
old_rl = ntfs_runlists_merge(old_rl, rl);
if (old_rl)
return old_rl;
err = errno;
@ -1436,18 +1403,28 @@ int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n)
{
s64 l = n;
int i;
s8 j;
i = 0;
if (dst > dst_max)
goto err_out;
*dst++ = l;
i++;
while ((l > 0x7f) || (l < -0x80)) {
do {
if (dst > dst_max)
goto err_out;
*dst++ = l & 0xffLL;
l >>= 8;
*dst++ = l;
i++;
} while (l != 0LL && l != -1LL);
j = (n >> 8 * (i - 1)) & 0xff;
/* If the sign bit is wrong, we need an extra byte. */
if (n < 0LL && j >= 0) {
if (dst > dst_max)
goto err_out;
i++;
*dst = (u8)-1;
} else if (n > 0LL && j < 0) {
if (dst > dst_max)
goto err_out;
i++;
*dst = 0;
}
return i;
err_out:
@ -1641,15 +1618,11 @@ errno_set:
int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
{
runlist *rl;
/* BOOL is_end = FALSE; */
BOOL is_end = FALSE;
if (!arl || !*arl) {
errno = EINVAL;
if (!arl)
ntfs_log_perror("rl_truncate error: arl: %p", arl);
else
ntfs_log_perror("rl_truncate error:"
" arl: %p *arl: %p", arl, *arl);
ntfs_log_perror("rl_truncate error: arl: %p *arl: %p", arl, *arl);
return -1;
}
@ -1684,10 +1657,8 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
*/
if (rl->length) {
++rl;
/*
if (!rl->length)
is_end = TRUE;
*/
rl->vcn = start_vcn;
rl->length = 0;
}
@ -1695,7 +1666,7 @@ int ntfs_rl_truncate(runlist **arl, const VCN start_vcn)
/**
* Reallocate memory if necessary.
* FIXME: Below code is broken, because runlist allocations must be
* a multiple of 4096. The code caused crashes and corruptions.
* a multiply of 4096. The code caused crashes and corruptions.
*/
/*
if (!is_end) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -53,9 +53,6 @@
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.h>
#endif
#include "types.h"
#include "mst.h"
@ -143,26 +140,8 @@ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
*(int*)dev->d_private = open(dev->d_name, flags);
if (*(int*)dev->d_private == -1) {
err = errno;
/* if permission error and rw, retry read-only */
if ((err == EACCES) && ((flags & O_RDWR) == O_RDWR))
err = EROFS;
goto err_out;
}
#ifdef HAVE_LINUX_FS_H
/* Check whether the device was forced read-only */
if (NDevBlock(dev) && ((flags & O_RDWR) == O_RDWR)) {
int r;
int state;
r = ioctl(DEV_FD(dev), BLKROGET, &state);
if (!r && state) {
err = EROFS;
if (close(DEV_FD(dev)))
err = errno;
goto err_out;
}
}
#endif
if ((flags & O_RDWR) != O_RDWR)
NDevSetReadOnly(dev);
@ -369,8 +348,8 @@ static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf)
*
* Returns:
*/
static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev,
unsigned long request, void *argp)
static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request,
void *argp)
{
return ioctl(DEV_FD(dev), request, argp);
}

View File

@ -4,7 +4,6 @@
* Copyright (c) 2000-2006 Anton Altaparmakov
* Copyright (c) 2002-2009 Szabolcs Szakacsits
* Copyright (c) 2004-2005 Richard Russon
* Copyright (c) 2010 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -54,11 +53,6 @@
#include <locale.h>
#endif
#if defined(__sun) && defined (__SVR4)
#include <sys/mnttab.h>
#endif
#include "param.h"
#include "compat.h"
#include "volume.h"
#include "attrib.h"
@ -71,13 +65,10 @@
#include "logfile.h"
#include "dir.h"
#include "logging.h"
#include "cache.h"
#include "realpath.h"
#include "misc.h"
#include "security.h"
const char *ntfs_home =
"News, support and information: https://github.com/tuxera/ntfs-3g/\n";
"Ntfs-3g news, support and information: http://ntfs-3g.org\n";
static const char *invalid_ntfs_msg =
"The device '%s' doesn't seem to have a valid NTFS.\n"
@ -94,14 +85,13 @@ static const char *corrupt_volume_msg =
"for more details.\n";
static const char *hibernated_volume_msg =
"The NTFS partition is in an unsafe state. Please resume and shutdown\n"
"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";
"The NTFS partition is hibernated. Please resume and shutdown Windows\n"
"properly, or mount the volume read-only with the 'ro' mount option, or\n"
"mount the volume read-write with the 'remove_hiberfile' mount option.\n"
"For example type on the command line:\n"
"\n"
" mount -t ntfs-3g -o remove_hiberfile %s %s\n"
"\n";
static const char *unclean_journal_msg =
"Write access is denied because the disk wasn't safely powered\n"
@ -121,7 +111,7 @@ static const char *fakeraid_msg =
static const char *access_denied_msg =
"Please check '%s' and the ntfs-3g binary permissions,\n"
"and the mounting user ID. More explanation is provided at\n"
"https://github.com/tuxera/ntfs-3g/wiki/NTFS-3G-FAQ\n";
"http://ntfs-3g.org/support.html#unprivileged\n";
/**
* ntfs_volume_alloc - Create an NTFS volume object and initialise it
@ -173,9 +163,6 @@ 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);
/*
@ -213,7 +200,6 @@ static int __ntfs_volume_release(ntfs_volume *v)
ntfs_free_lru_caches(v);
free(v->vol_name);
free(v->upcase);
if (v->locase) free(v->locase);
free(v->attrdef);
free(v);
@ -221,24 +207,15 @@ static int __ntfs_volume_release(ntfs_volume *v)
return errno ? -1 : 0;
}
static int ntfs_attr_setup_flag(ntfs_inode *ni)
static void ntfs_attr_setup_flag(ntfs_inode *ni)
{
STANDARD_INFORMATION *si;
s64 lth;
int r;
si = (STANDARD_INFORMATION*)ntfs_attr_readall(ni,
AT_STANDARD_INFORMATION, AT_UNNAMED, 0, &lth);
si = ntfs_attr_readall(ni, AT_STANDARD_INFORMATION, AT_UNNAMED, 0, NULL);
if (si) {
if ((u64)lth >= offsetof(STANDARD_INFORMATION, owner_id))
ni->flags = si->file_attributes;
ni->flags = si->file_attributes;
free(si);
r = 0;
} else {
ntfs_log_error("Failed to get standard information of $MFT\n");
r = -1;
}
return (r);
}
/**
@ -312,19 +289,16 @@ static int ntfs_mft_load(ntfs_volume *vol)
ntfs_log_error("Failed to get value of $MFT/$ATTR_LIST.\n");
goto io_error_exit;
}
if ((l != vol->mft_ni->attr_list_size)
|| (l < (s64)offsetof(ATTR_LIST_ENTRY, name))) {
if (l != vol->mft_ni->attr_list_size) {
ntfs_log_error("Partial read of $MFT/$ATTR_LIST (%lld != "
"%u or < %d).\n", (long long)l,
vol->mft_ni->attr_list_size,
(int)offsetof(ATTR_LIST_ENTRY, name));
"%u).\n", (long long)l,
vol->mft_ni->attr_list_size);
goto io_error_exit;
}
mft_has_no_attr_list:
if (ntfs_attr_setup_flag(vol->mft_ni))
goto error_exit;
ntfs_attr_setup_flag(vol->mft_ni);
/* We now have a fully setup ntfs inode for $MFT in vol->mft_ni. */
@ -367,11 +341,6 @@ mft_has_no_attr_list:
ntfs_log_perror("ntfs_mapping_pairs_decompress() failed");
goto error_exit;
}
/* Make sure $DATA is the MFT itself */
if (nrl->lcn != vol->mft_lcn) {
ntfs_log_perror("The MFT is not self-contained");
goto error_exit;
}
vol->mft_na->rl = nrl;
/* Get the lowest vcn for the next extent. */
@ -401,12 +370,6 @@ mft_has_no_attr_list:
/* Done with the $Mft mft record. */
ntfs_attr_put_search_ctx(ctx);
ctx = NULL;
/* Update the size fields in the inode. */
vol->mft_ni->data_size = vol->mft_na->data_size;
vol->mft_ni->allocated_size = vol->mft_na->allocated_size;
set_nino_flag(vol->mft_ni, KnownSize);
/*
* The volume is now setup so we can use all read access functions.
*/
@ -465,12 +428,6 @@ static int ntfs_mftmirr_load(ntfs_volume *vol)
ntfs_log_perror("Failed to map runlist of $MFTMirr/$DATA");
goto error_exit;
}
if (vol->mftmirr_na->rl->lcn != vol->mftmirr_lcn) {
ntfs_log_error("Bad $MFTMirr lcn 0x%llx, want 0x%llx\n",
(long long)vol->mftmirr_na->rl->lcn,
(long long)vol->mftmirr_lcn);
goto error_exit;
}
return 0;
@ -498,8 +455,7 @@ error_exit:
* Return the allocated volume structure on success and NULL on error with
* errno set to the error code.
*/
ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
ntfs_mount_flags flags)
ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev, unsigned long flags)
{
LCN mft_zone_size, mft_lcn;
s64 br;
@ -523,43 +479,21 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
goto error_exit;
/* Create the default upcase table. */
vol->upcase_len = ntfs_upcase_build_default(&vol->upcase);
if (!vol->upcase_len || !vol->upcase)
vol->upcase_len = 65536;
vol->upcase = ntfs_malloc(vol->upcase_len * sizeof(ntfschar));
if (!vol->upcase)
goto error_exit;
/* Default with no locase table and case sensitive file names */
vol->locase = (ntfschar*)NULL;
NVolSetCaseSensitive(vol);
/* by default, all files are shown and not marked hidden */
NVolSetShowSysFiles(vol);
NVolSetShowHidFiles(vol);
NVolClearHideDotFiles(vol);
/* set default compression */
#if DEFAULT_COMPRESSION
NVolSetCompression(vol);
#else
NVolClearCompression(vol);
#endif
if (flags & NTFS_MNT_RDONLY)
ntfs_upcase_table_build(vol->upcase,
vol->upcase_len * sizeof(ntfschar));
if (flags & MS_RDONLY)
NVolSetReadOnly(vol);
/* ...->open needs bracketing to compile with glibc 2.7 */
if ((dev->d_ops->open)(dev, NVolReadOnly(vol) ? O_RDONLY: O_RDWR)) {
if (!NVolReadOnly(vol) && (errno == EROFS)) {
if ((dev->d_ops->open)(dev, O_RDONLY)) {
ntfs_log_perror("Error opening read-only '%s'",
dev->d_name);
goto error_exit;
} else {
ntfs_log_info("Error opening '%s' read-write\n",
dev->d_name);
NVolSetReadOnly(vol);
}
} else {
ntfs_log_perror("Error opening '%s'", dev->d_name);
goto error_exit;
}
ntfs_log_perror("Error opening '%s'", dev->d_name);
goto error_exit;
}
/* Attach the device to the volume. */
vol->dev = dev;
@ -624,10 +558,6 @@ ntfs_volume *ntfs_volume_startup(struct ntfs_device *dev,
vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
while (vol->mft_zone_end >= vol->nr_clusters) {
mft_zone_size >>= 1;
if (!mft_zone_size) {
errno = EINVAL;
goto error_exit;
}
vol->mft_zone_end = vol->mft_lcn + mft_zone_size;
}
ntfs_log_debug("mft_zone_end = 0x%llx\n", (long long)vol->mft_zone_end);
@ -698,24 +628,6 @@ static int ntfs_volume_check_logfile(ntfs_volume *vol)
if (!ntfs_check_logfile(na, &rp) || !ntfs_is_logfile_clean(na, rp))
err = EOPNOTSUPP;
/*
* If the latest restart page was identified as version
* 2.0, then Windows may have kept a cached copy of
* metadata for fast restarting, and we should not mount.
* Hibernation will be seen the same way on a non
* Windows-system partition, so we have to use the same
* error code (EPERM).
* The restart page may also be identified as version 2.0
* when access to the file system is terminated abruptly
* by unplugging or power cut, so mounting is also rejected
* after such an event.
*/
if (rp
&& (rp->major_ver == const_cpu_to_le16(2))
&& (rp->minor_ver == const_cpu_to_le16(0))) {
ntfs_log_error("Metadata kept in Windows cache, refused to mount.\n");
err = EPERM;
}
free(rp);
ntfs_attr_close(na);
out:
@ -829,8 +741,7 @@ int ntfs_volume_check_hiberfile(ntfs_volume *vol, int verbose)
errno = EPERM;
goto out;
}
if ((memcmp(buf, "hibr", 4) == 0)
|| (memcmp(buf, "HIBR", 4) == 0)) {
if (memcmp(buf, "hibr", 4) == 0) {
if (verbose)
ntfs_log_error("Windows is hibernated, refused to mount.\n");
errno = EPERM;
@ -849,70 +760,6 @@ out:
return errno ? -1 : 0;
}
/*
* Make sure a LOGGED_UTILITY_STREAM attribute named "$TXF_DATA"
* on the root directory is resident.
* When it is non-resident, the partition cannot be mounted on Vista
* (see http://support.microsoft.com/kb/974729)
*
* We take care to avoid this situation, however this can be a
* consequence of having used an older version (including older
* Windows version), so we had better fix it.
*
* Returns 0 if unneeded or successful
* -1 if there was an error, explained by errno
*/
static int fix_txf_data(ntfs_volume *vol)
{
void *txf_data;
s64 txf_data_size;
ntfs_inode *ni;
ntfs_attr *na;
int res;
res = 0;
ntfs_log_debug("Loading root directory\n");
ni = ntfs_inode_open(vol, FILE_root);
if (!ni) {
ntfs_log_perror("Failed to open root directory");
res = -1;
} else {
/* Get the $TXF_DATA attribute */
na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM, TXF_DATA, 9);
if (na) {
if (NAttrNonResident(na)) {
/*
* Fix the attribute by truncating, then
* rewriting it.
*/
ntfs_log_debug("Making $TXF_DATA resident\n");
txf_data = ntfs_attr_readall(ni,
AT_LOGGED_UTILITY_STREAM,
TXF_DATA, 9, &txf_data_size);
if (txf_data) {
if (ntfs_attr_truncate(na, 0)
|| (ntfs_attr_pwrite(na, 0,
txf_data_size, txf_data)
!= txf_data_size))
res = -1;
free(txf_data);
}
if (res)
ntfs_log_error("Failed to make $TXF_DATA resident\n");
else
ntfs_log_error("$TXF_DATA made resident\n");
}
ntfs_attr_close(na);
}
if (ntfs_inode_close(ni)) {
ntfs_log_perror("Failed to close root");
res = -1;
}
}
return (res);
}
/**
* ntfs_device_mount - open ntfs volume
* @dev: device to open
@ -924,7 +771,7 @@ static int fix_txf_data(ntfs_volume *vol)
* @flags is an optional second parameter. The same flags are used as for
* the mount system call (man 2 mount). Currently only the following flag
* is implemented:
* NTFS_MNT_RDONLY - mount volume read-only
* MS_RDONLY - mount volume read-only
*
* The function opens the device @dev and verifies that it contains a valid
* bootsector. Then, it allocates an ntfs_volume structure and initializes
@ -935,7 +782,7 @@ static int fix_txf_data(ntfs_volume *vol)
* Return the allocated volume structure on success and NULL on error with
* errno set to the error code.
*/
ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, unsigned long flags)
{
s64 l;
ntfs_volume *vol;
@ -946,13 +793,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
ATTR_RECORD *a;
VOLUME_INFORMATION *vinf;
ntfschar *vname;
u32 record_size;
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;
@ -976,10 +819,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
}
goto error_exit;
}
for (i = 0; (i < l) && (i < FILE_first_user); ++i)
if (ntfs_mft_record_check(vol, FILE_MFT + i,
(MFT_RECORD*)(m + i*vol->mft_record_size)))
goto error_exit;
l = ntfs_attr_mst_pread(vol->mftmirr_na, 0, vol->mftmirr_size,
vol->mft_record_size, m2);
if (l != vol->mftmirr_size) {
@ -989,13 +828,8 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
}
vol->mftmirr_size = l;
}
for (i = 0; (i < l) && (i < FILE_first_user); ++i)
if (ntfs_mft_record_check(vol, FILE_MFT + i,
(MFT_RECORD*)(m2 + i*vol->mft_record_size)))
goto error_exit;
ntfs_log_debug("Comparing $MFTMirr to $MFT...\n");
/* Windows 10 does not update the full $MFTMirr any more */
for (i = 0; (i < vol->mftmirr_size) && (i < FILE_first_user); ++i) {
for (i = 0; i < vol->mftmirr_size; ++i) {
MFT_RECORD *mrec, *mrec2;
const char *ESTR[12] = { "$MFT", "$MFTMirr", "$LogFile",
"$Volume", "$AttrDef", "root directory", "$Bitmap",
@ -1011,13 +845,13 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
mrec = (MFT_RECORD*)(m + i * vol->mft_record_size);
if (mrec->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_record(mrec->magic)) {
if (ntfs_is_baad_recordp(mrec)) {
ntfs_log_error("$MFT error: Incomplete multi "
"sector transfer detected in "
"'%s'.\n", s);
goto io_error_exit;
}
if (!ntfs_is_mft_record(mrec->magic)) {
if (!ntfs_is_mft_recordp(mrec)) {
ntfs_log_error("$MFT error: Invalid mft "
"record for '%s'.\n", s);
goto io_error_exit;
@ -1025,22 +859,19 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
}
mrec2 = (MFT_RECORD*)(m2 + i * vol->mft_record_size);
if (mrec2->flags & MFT_RECORD_IN_USE) {
if (ntfs_is_baad_record(mrec2->magic)) {
if (ntfs_is_baad_recordp(mrec2)) {
ntfs_log_error("$MFTMirr error: Incomplete "
"multi sector transfer "
"detected in '%s'.\n", s);
goto io_error_exit;
}
if (!ntfs_is_mft_record(mrec2->magic)) {
if (!ntfs_is_mft_recordp(mrec2)) {
ntfs_log_error("$MFTMirr error: Invalid mft "
"record for '%s'.\n", s);
goto io_error_exit;
}
}
record_size = ntfs_mft_record_get_data_size(mrec);
if ((record_size <= sizeof(MFT_RECORD))
|| (record_size > vol->mft_record_size)
|| memcmp(mrec, mrec2, record_size)) {
if (memcmp(mrec, mrec2, ntfs_mft_record_get_data_size(mrec))) {
ntfs_log_error("$MFTMirr does not match $MFT (record "
"%d).\n", i);
goto io_error_exit;
@ -1083,19 +914,19 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
if (!na) {
ntfs_log_perror("Failed to open ntfs attribute");
ntfs_inode_close(ni);
goto error_exit;
}
/*
* Note: Normally, the upcase table has a length equal to 65536
* 2-byte Unicode characters. Anyway we currently can only process
* such characters.
* 2-byte Unicode characters but allow for different cases, so no
* checks done. Just check we don't overflow 32-bits worth of Unicode
* characters.
*/
if ((na->data_size - 2) & ~0x1fffeULL) {
ntfs_log_error("Error: Upcase table is invalid (want size even "
"<= 131072).\n");
if (na->data_size & ~0x1ffffffffULL) {
ntfs_log_error("Error: Upcase table is too big (max 32-bit "
"allowed).\n");
errno = EINVAL;
goto bad_upcase;
goto error_exit;
}
if (vol->upcase_len != na->data_size >> 1) {
vol->upcase_len = na->data_size >> 1;
@ -1103,7 +934,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
free(vol->upcase);
vol->upcase = ntfs_malloc(na->data_size);
if (!vol->upcase)
goto bad_upcase;
goto error_exit;
}
/* Read in the $DATA attribute value into the buffer. */
l = ntfs_attr_pread(na, 0, na->data_size, vol->upcase);
@ -1112,7 +943,7 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
"(%lld != %lld).\n", (long long)l,
(long long)na->data_size);
errno = EIO;
goto bad_upcase;
goto error_exit;
}
/* Done with the $UpCase mft record. */
ntfs_attr_close(na);
@ -1120,17 +951,6 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
ntfs_log_perror("Failed to close $UpCase");
goto error_exit;
}
/* Consistency check of $UpCase, restricted to plain ASCII chars */
k = 0x20;
while ((k < vol->upcase_len)
&& (k < 0x7f)
&& (le16_to_cpu(vol->upcase[k])
== ((k < 'a') || (k > 'z') ? k : k + 'A' - 'a')))
k++;
if (k < 0x7f) {
ntfs_log_error("Corrupted file $UpCase\n");
goto io_error_exit;
}
/*
* Now load $Volume and set the version information and flags in the
@ -1225,9 +1045,9 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
goto error_exit;
for (j = 0; j < (s32)u; j++) {
u16 uc = le16_to_cpu(vname[j]);
ntfschar uc = le16_to_cpu(vname[j]);
if (uc > 0xff)
uc = (u16)'_';
uc = (ntfschar)'_';
vol->vol_name[j] = (char)uc;
}
vol->vol_name[u] = '\0';
@ -1248,10 +1068,10 @@ ntfs_volume *ntfs_device_mount(struct ntfs_device *dev, ntfs_mount_flags flags)
ntfs_log_perror("Failed to open ntfs attribute");
goto error_exit;
}
/* Check we don't overflow 24-bits. */
if ((u64)na->data_size > 0xffffffLL) {
/* Check we don't overflow 32-bits. */
if (na->data_size > 0xffffffffLL) {
ntfs_log_error("Attribute definition table is too big (max "
"24-bit allowed).\n");
"32-bit allowed).\n");
errno = EINVAL;
goto error_exit;
}
@ -1274,53 +1094,25 @@ 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) {
if (flags & NTFS_MNT_MAY_RDONLY)
need_fallback_ro = TRUE;
else
goto error_exit;
}
if (!(flags & MS_RDONLY)) {
if (!(flags & MS_IGNORE_HIBERFILE) &&
ntfs_volume_check_hiberfile(vol, 1) < 0)
goto error_exit;
if (ntfs_volume_check_logfile(vol) < 0) {
/* Always reject cached metadata for now */
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 (!(flags & NTFS_MNT_RDONLY) && !need_fallback_ro) {
if (fix_txf_data(vol))
if (!(flags & MS_RECOVER))
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 (need_fallback_ro) {
NVolSetReadOnly(vol);
ntfs_log_error("%s", fallback_readonly_msg);
}
return vol;
bad_upcase :
ntfs_attr_close(na);
ntfs_inode_close(ni);
goto error_exit;
io_error_exit:
errno = EIO;
error_exit:
@ -1334,58 +1126,6 @@ error_exit:
return NULL;
}
/*
* Set appropriate flags for showing NTFS metafiles
* or files marked as hidden.
* Not set in ntfs_mount() to avoid breaking existing tools.
*/
int ntfs_set_shown_files(ntfs_volume *vol,
BOOL show_sys_files, BOOL show_hid_files,
BOOL hide_dot_files)
{
int res;
res = -1;
if (vol) {
NVolClearShowSysFiles(vol);
NVolClearShowHidFiles(vol);
NVolClearHideDotFiles(vol);
if (show_sys_files)
NVolSetShowSysFiles(vol);
if (show_hid_files)
NVolSetShowHidFiles(vol);
if (hide_dot_files)
NVolSetHideDotFiles(vol);
res = 0;
}
if (res)
ntfs_log_error("Failed to set file visibility\n");
return (res);
}
/*
* Set ignore case mode
*/
int ntfs_set_ignore_case(ntfs_volume *vol)
{
int res;
res = -1;
if (vol && vol->upcase) {
vol->locase = ntfs_locase_table_build(vol->upcase,
vol->upcase_len);
if (vol->locase) {
NVolClearCaseSensitive(vol);
res = 0;
}
}
if (res)
ntfs_log_error("Failed to set ignore_case mode\n");
return (res);
}
/**
* ntfs_mount - open ntfs volume
* @name: name of device/file to open
@ -1397,7 +1137,7 @@ int ntfs_set_ignore_case(ntfs_volume *vol)
* @flags is an optional second parameter. The same flags are used as for
* the mount system call (man 2 mount). Currently only the following flags
* is implemented:
* NTFS_MNT_RDONLY - mount volume read-only
* MS_RDONLY - mount volume read-only
*
* The function opens the device or file @name and verifies that it contains a
* valid bootsector. Then, it allocates an ntfs_volume structure and initializes
@ -1412,7 +1152,7 @@ int ntfs_set_ignore_case(ntfs_volume *vol)
* soon as the function returns.
*/
ntfs_volume *ntfs_mount(const char *name __attribute__((unused)),
ntfs_mount_flags flags __attribute__((unused)))
unsigned long flags __attribute__((unused)))
{
#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
struct ntfs_device *dev;
@ -1481,6 +1221,18 @@ int ntfs_umount(ntfs_volume *vol, const BOOL force __attribute__((unused)))
#ifdef HAVE_MNTENT_H
#ifndef HAVE_REALPATH
/**
* realpath - If there is no realpath on the system
*/
static char *realpath(const char *path, char *resolved_path)
{
strncpy(resolved_path, path, PATH_MAX);
resolved_path[PATH_MAX] = '\0';
return resolved_path;
}
#endif
/**
* ntfs_mntent_check - desc
*
@ -1504,17 +1256,16 @@ static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
err = errno;
goto exit;
}
if (!ntfs_realpath_canonicalize(file, real_file)) {
if (!realpath(file, real_file)) {
err = errno;
goto exit;
}
f = setmntent("/proc/mounts", "r");
if (!f && !(f = setmntent(MOUNTED, "r"))) {
if (!(f = setmntent(MOUNTED, "r"))) {
err = errno;
goto exit;
}
while ((mnt = getmntent(f))) {
if (!ntfs_realpath_canonicalize(mnt->mnt_fsname, real_fsname))
if (!realpath(mnt->mnt_fsname, real_fsname))
continue;
if (!strcmp(real_file, real_fsname))
break;
@ -1538,60 +1289,6 @@ exit:
}
return 0;
}
#else /* HAVE_MNTENT_H */
#if defined(__sun) && defined (__SVR4)
static int ntfs_mntent_check(const char *file, unsigned long *mnt_flags)
{
struct mnttab *mnt = NULL;
char *real_file = NULL, *real_fsname = NULL;
FILE *f;
int err = 0;
real_file = (char*)ntfs_malloc(PATH_MAX + 1);
if (!real_file)
return -1;
real_fsname = (char*)ntfs_malloc(PATH_MAX + 1);
mnt = (struct mnttab*)ntfs_malloc(MNT_LINE_MAX + 1);
if (!real_fsname || !mnt) {
err = errno;
goto exit;
}
if (!ntfs_realpath_canonicalize(file, real_file)) {
err = errno;
goto exit;
}
if (!(f = fopen(MNTTAB, "r"))) {
err = errno;
goto exit;
}
while (!getmntent(f, mnt)) {
if (!ntfs_realpath_canonicalize(mnt->mnt_special, real_fsname))
continue;
if (!strcmp(real_file, real_fsname)) {
*mnt_flags = NTFS_MF_MOUNTED;
if (!strcmp(mnt->mnt_mountp, "/"))
*mnt_flags |= NTFS_MF_ISROOT;
if (hasmntopt(mnt, "ro") && !hasmntopt(mnt, "rw"))
*mnt_flags |= NTFS_MF_READONLY;
break;
}
}
fclose(f);
exit:
free(mnt);
free(real_file);
free(real_fsname);
if (err) {
errno = err;
return -1;
}
return 0;
}
#endif /* defined(__sun) && defined (__SVR4) */
#endif /* HAVE_MNTENT_H */
/**
@ -1623,7 +1320,7 @@ int ntfs_check_if_mounted(const char *file __attribute__((unused)),
unsigned long *mnt_flags)
{
*mnt_flags = 0;
#if defined(HAVE_MNTENT_H) || (defined(__sun) && defined (__SVR4))
#ifdef HAVE_MNTENT_H
return ntfs_mntent_check(file, mnt_flags);
#else
return 0;
@ -1735,7 +1432,7 @@ error_exit:
*
* Return 0 if successful and -1 if not with errno set to the error code.
*/
int ntfs_volume_write_flags(ntfs_volume *vol, const le16 flags)
int ntfs_volume_write_flags(ntfs_volume *vol, const u16 flags)
{
ATTR_RECORD *a;
VOLUME_INFORMATION *c;
@ -1805,10 +1502,6 @@ int ntfs_volume_error(int err)
ret = NTFS_VOLUME_CORRUPT;
break;
case EPERM:
/*
* Hibernation and fast restarting are seen the
* same way on a non Windows-system partition.
*/
ret = NTFS_VOLUME_HIBERNATED;
break;
case EOPNOTSUPP:
@ -1894,120 +1587,8 @@ int ntfs_volume_get_free_space(ntfs_volume *vol)
if (vol->free_mft_records < 0)
ntfs_log_perror("Failed to calculate free MFT records");
else {
NVolSetFreeSpaceKnown(vol);
else
ret = 0;
}
}
return (ret);
}
/**
* ntfs_volume_rename - change the current label on a volume
* @vol: volume to change the label on
* @label: the new label
* @label_len: the length of @label in ntfschars including the terminating NULL
* character, which is mandatory (the value can not exceed 128)
*
* Change the label on the volume @vol to @label.
*/
int ntfs_volume_rename(ntfs_volume *vol, const ntfschar *label, int label_len)
{
ntfs_attr *na;
char *old_vol_name;
char *new_vol_name = NULL;
int new_vol_name_len;
int err;
if (NVolReadOnly(vol)) {
ntfs_log_error("Refusing to change label on read-only mounted "
"volume.\n");
errno = EROFS;
return -1;
}
label_len *= sizeof(ntfschar);
if (label_len > 0x100) {
ntfs_log_error("New label is too long. Maximum %u characters "
"allowed.\n",
(unsigned)(0x100 / sizeof(ntfschar)));
errno = ERANGE;
return -1;
}
na = ntfs_attr_open(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0);
if (!na) {
if (errno != ENOENT) {
err = errno;
ntfs_log_perror("Lookup of $VOLUME_NAME attribute "
"failed");
goto err_out;
}
/* The volume name attribute does not exist. Need to add it. */
if (ntfs_attr_add(vol->vol_ni, AT_VOLUME_NAME, AT_UNNAMED, 0,
(const u8*) label, label_len))
{
err = errno;
ntfs_log_perror("Encountered error while adding "
"$VOLUME_NAME attribute");
goto err_out;
}
}
else {
s64 written;
if (NAttrNonResident(na)) {
err = errno;
ntfs_log_error("Error: Attribute $VOLUME_NAME must be "
"resident.\n");
goto err_out;
}
if (na->data_size != label_len) {
if (ntfs_attr_truncate(na, label_len)) {
err = errno;
ntfs_log_perror("Error resizing resident "
"attribute");
goto err_out;
}
}
if (label_len) {
written = ntfs_attr_pwrite(na, 0, label_len, label);
if (written == -1) {
err = errno;
ntfs_log_perror("Error when writing "
"$VOLUME_NAME data");
goto err_out;
}
else if (written != label_len) {
err = EIO;
ntfs_log_error("Partial write when writing "
"$VOLUME_NAME data.");
goto err_out;
}
}
}
new_vol_name_len =
ntfs_ucstombs(label, label_len, &new_vol_name, 0);
if (new_vol_name_len == -1) {
err = errno;
ntfs_log_perror("Error while decoding new volume name");
goto err_out;
}
old_vol_name = vol->vol_name;
vol->vol_name = new_vol_name;
free(old_vol_name);
err = 0;
err_out:
if (na)
ntfs_attr_close(na);
if (err)
errno = err;
return err ? -1 : 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,808 +0,0 @@
/**
* xattrs.c : common functions to deal with system extended attributes
*
* Copyright (c) 2010-2014 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include "types.h"
#include "param.h"
#include "layout.h"
#include "attrib.h"
#include "index.h"
#include "dir.h"
#include "security.h"
#include "acls.h"
#include "efs.h"
#include "reparse.h"
#include "object_id.h"
#include "ea.h"
#include "misc.h"
#include "logging.h"
#include "xattrs.h"
#if POSIXACLS
#if __BYTE_ORDER == __BIG_ENDIAN
/*
* Posix ACL structures
*/
struct LE_POSIX_ACE {
le16 tag;
le16 perms;
le32 id;
} __attribute__((__packed__));
struct LE_POSIX_ACL {
u8 version;
u8 flags;
le16 filler;
struct LE_POSIX_ACE ace[0];
} __attribute__((__packed__));
#endif
#endif
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";
static const char nf_ns_xattr_efsinfo[] = "system.ntfs_efsinfo";
static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id";
static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
static const char nf_ns_xattr_times[] = "system.ntfs_times";
static const char nf_ns_xattr_times_be[] = "system.ntfs_times_be";
static const char nf_ns_xattr_crtime[] = "system.ntfs_crtime";
static const char nf_ns_xattr_crtime_be[] = "system.ntfs_crtime_be";
static const char nf_ns_xattr_ea[] = "system.ntfs_ea";
static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
struct XATTRNAME {
enum SYSTEMXATTRS xattr;
const char *name;
} ;
static struct XATTRNAME nf_ns_xattr_names[] = {
{ XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl },
{ XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib },
{ XATTR_NTFS_ATTRIB_BE, nf_ns_xattr_attrib_be },
{ XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo },
{ XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse },
{ XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id },
{ XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name },
{ XATTR_NTFS_TIMES, nf_ns_xattr_times },
{ XATTR_NTFS_TIMES_BE, nf_ns_xattr_times_be },
{ XATTR_NTFS_CRTIME, nf_ns_xattr_crtime },
{ XATTR_NTFS_CRTIME_BE, nf_ns_xattr_crtime_be },
{ XATTR_NTFS_EA, nf_ns_xattr_ea },
{ XATTR_POSIX_ACC, nf_ns_xattr_posix_access },
{ XATTR_POSIX_DEF, nf_ns_xattr_posix_default },
{ XATTR_UNMAPPED, (char*)NULL } /* terminator */
};
/*
* Make an integer big-endian
*
* Swap bytes on a small-endian computer and does nothing on a
* big-endian computer.
*/
static void fix_big_endian(char *p, int size)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
int i,j;
int c;
i = 0;
j = size - 1;
while (i < j) {
c = p[i];
p[i++] = p[j];
p[j--] = c;
}
#endif
}
#if POSIXACLS
#if __BYTE_ORDER == __BIG_ENDIAN
/*
* Make a Posix ACL CPU endian
*/
static int le_acl_to_cpu(const struct LE_POSIX_ACL *le_acl, size_t size,
struct POSIX_ACL *acl)
{
int i;
int cnt;
acl->version = le_acl->version;
acl->flags = le_acl->flags;
acl->filler = 0;
cnt = (size - sizeof(struct LE_POSIX_ACL)) / sizeof(struct LE_POSIX_ACE);
for (i=0; i<cnt; i++) {
acl->ace[i].tag = le16_to_cpu(le_acl->ace[i].tag);
acl->ace[i].perms = le16_to_cpu(le_acl->ace[i].perms);
acl->ace[i].id = le32_to_cpu(le_acl->ace[i].id);
}
return (0);
}
/*
* Make a Posix ACL little endian
*/
int cpu_to_le_acl(const struct POSIX_ACL *acl, size_t size,
struct LE_POSIX_ACL *le_acl)
{
int i;
int cnt;
le_acl->version = acl->version;
le_acl->flags = acl->flags;
le_acl->filler = const_cpu_to_le16(0);
cnt = (size - sizeof(struct POSIX_ACL)) / sizeof(struct POSIX_ACE);
for (i=0; i<cnt; i++) {
le_acl->ace[i].tag = cpu_to_le16(acl->ace[i].tag);
le_acl->ace[i].perms = cpu_to_le16(acl->ace[i].perms);
le_acl->ace[i].id = cpu_to_le32(acl->ace[i].id);
}
return (0);
}
#endif
#endif
/*
* Determine whether an extended attribute is mapped to
* internal data (original name in system namespace, or renamed)
*/
enum SYSTEMXATTRS ntfs_xattr_system_type(const char *name,
ntfs_volume *vol)
{
struct XATTRNAME *p;
enum SYSTEMXATTRS ret;
#ifdef XATTR_MAPPINGS
const struct XATTRMAPPING *q;
#endif /* XATTR_MAPPINGS */
p = nf_ns_xattr_names;
while (p->name && strcmp(p->name,name))
p++;
ret = p->xattr;
#ifdef XATTR_MAPPINGS
if (!p->name && vol && vol->xattr_mapping) {
q = vol->xattr_mapping;
while (q && strcmp(q->name,name))
q = q->next;
if (q)
ret = q->xattr;
}
#else /* XATTR_MAPPINGS */
if (!p->name
&& vol
&& vol->efs_raw
&& !strcmp(nf_ns_alt_xattr_efsinfo,name))
ret = XATTR_NTFS_EFSINFO;
#endif /* XATTR_MAPPINGS */
return (ret);
}
#ifdef XATTR_MAPPINGS
/*
* Basic read from a user mapping file on another volume
*/
static int basicread(void *fileid, char *buf, size_t size, off_t offs __attribute__((unused)))
{
return (read(*(int*)fileid, buf, size));
}
/*
* Read from a user mapping file on current NTFS partition
*/
static int localread(void *fileid, char *buf, size_t size, off_t offs)
{
return (ntfs_attr_data_read((ntfs_inode*)fileid,
AT_UNNAMED, 0, buf, size, offs));
}
/*
* Get a single mapping item from buffer
*
* Always reads a full line, truncating long lines
* Refills buffer when exhausted
* Returns pointer to item, or NULL when there is no more
* Note : errors are logged, but not returned
// TODO partially share with acls.c
*/
static struct XATTRMAPPING *getmappingitem(FILEREADER reader, void *fileid,
off_t *poffs, char *buf, int *psrc, s64 *psize)
{
int src;
int dst;
char *pe;
char *ps;
char *pu;
enum SYSTEMXATTRS xattr;
int gotend;
char maptext[LINESZ];
struct XATTRMAPPING *item;
src = *psrc;
dst = 0;
do {
gotend = 0;
while ((src < *psize)
&& (buf[src] != '\n')) {
/* ignore spaces */
if ((dst < LINESZ)
&& (buf[src] != '\r')
&& (buf[src] != '\t')
&& (buf[src] != ' '))
maptext[dst++] = buf[src];
src++;
}
if (src >= *psize) {
*poffs += *psize;
*psize = reader(fileid, buf, (size_t)BUFSZ, *poffs);
src = 0;
} else {
gotend = 1;
src++;
maptext[dst] = '\0';
dst = 0;
}
} while (*psize && ((maptext[0] == '#') || !gotend));
item = (struct XATTRMAPPING*)NULL;
if (gotend) {
/* decompose into system name and user name */
ps = maptext;
pu = strchr(maptext,':');
if (pu) {
*pu++ = 0;
pe = strchr(pu,':');
if (pe)
*pe = 0;
/* check name validity */
if ((strlen(pu) < 6) || strncmp(pu,"user.",5))
pu = (char*)NULL;
xattr = ntfs_xattr_system_type(ps,
(ntfs_volume*)NULL);
if (xattr == XATTR_UNMAPPED)
pu = (char*)NULL;
}
if (pu) {
item = (struct XATTRMAPPING*)ntfs_malloc(
sizeof(struct XATTRMAPPING)
+ strlen(pu));
if (item) {
item->xattr = xattr;
strcpy(item->name,pu);
item->next = (struct XATTRMAPPING*)NULL;
}
} else {
ntfs_log_early_error("Bad xattr mapping item, aborting\n");
}
}
*psrc = src;
return (item);
}
/*
* Read xattr mapping file and split into their attribute.
* Parameters are kept in a chained list.
* Returns the head of list, if any
* Errors are logged, but not returned
*
* If an absolute path is provided, the mapping file is assumed
* to be located in another mounted file system, and plain read()
* are used to get its contents.
* If a relative path is provided, the mapping file is assumed
* to be located on the current file system, and internal IO
* have to be used since we are still mounting and we have not
* entered the fuse loop yet.
*/
static struct XATTRMAPPING *ntfs_read_xattr_mapping(FILEREADER reader,
void *fileid)
{
char buf[BUFSZ];
struct XATTRMAPPING *item;
struct XATTRMAPPING *current;
struct XATTRMAPPING *firstitem;
struct XATTRMAPPING *lastitem;
BOOL duplicated;
int src;
off_t offs;
s64 size;
firstitem = (struct XATTRMAPPING*)NULL;
lastitem = (struct XATTRMAPPING*)NULL;
offs = 0;
size = reader(fileid, buf, (size_t)BUFSZ, (off_t)0);
if (size > 0) {
src = 0;
do {
item = getmappingitem(reader, fileid, &offs,
buf, &src, &size);
if (item) {
/* check no double mapping */
duplicated = FALSE;
for (current=firstitem; current; current=current->next)
if ((current->xattr == item->xattr)
|| !strcmp(current->name,item->name))
duplicated = TRUE;
if (duplicated) {
free(item);
ntfs_log_early_error("Conflicting xattr mapping ignored\n");
} else {
item->next = (struct XATTRMAPPING*)NULL;
if (lastitem)
lastitem->next = item;
else
firstitem = item;
lastitem = item;
}
}
} while (item);
}
return (firstitem);
}
/*
* Build the extended attribute mappings to user namespace
*
* Note : no error is returned. If we refused mounting when there
* is an error it would be too difficult to fix the offending file
*/
struct XATTRMAPPING *ntfs_xattr_build_mapping(ntfs_volume *vol,
const char *xattrmap_path)
{
struct XATTRMAPPING *firstmapping;
struct XATTRMAPPING *mapping;
BOOL user_efs;
BOOL notfound;
ntfs_inode *ni;
int fd;
firstmapping = (struct XATTRMAPPING*)NULL;
notfound = FALSE;
if (!xattrmap_path)
xattrmap_path = XATTRMAPPINGFILE;
if (xattrmap_path[0] == '/') {
fd = open(xattrmap_path,O_RDONLY);
if (fd > 0) {
firstmapping = ntfs_read_xattr_mapping(basicread, (void*)&fd);
close(fd);
} else
notfound = TRUE;
} else {
ni = ntfs_pathname_to_inode(vol, NULL, xattrmap_path);
if (ni) {
firstmapping = ntfs_read_xattr_mapping(localread, ni);
ntfs_inode_close(ni);
} else
notfound = TRUE;
}
if (notfound && strcmp(xattrmap_path, XATTRMAPPINGFILE)) {
ntfs_log_early_error("Could not open \"%s\"\n",xattrmap_path);
}
if (vol->efs_raw) {
user_efs = TRUE;
for (mapping=firstmapping; mapping; mapping=mapping->next)
if (mapping->xattr == XATTR_NTFS_EFSINFO)
user_efs = FALSE;
} else
user_efs = FALSE;
if (user_efs) {
mapping = (struct XATTRMAPPING*)ntfs_malloc(
sizeof(struct XATTRMAPPING)
+ strlen(nf_ns_alt_xattr_efsinfo));
if (mapping) {
mapping->next = firstmapping;
mapping->xattr = XATTR_NTFS_EFSINFO;
strcpy(mapping->name,nf_ns_alt_xattr_efsinfo);
firstmapping = mapping;
}
}
return (firstmapping);
}
void ntfs_xattr_free_mapping(struct XATTRMAPPING *mapping)
{
struct XATTRMAPPING *p, *q;
p = mapping;
while (p) {
q = p->next;
free(p);
p = q;
}
}
#endif /* XATTR_MAPPINGS */
/*
* Get an NTFS attribute into an extended attribute
*
* Returns the non-negative size of attribute if successful,
* or negative, with errno set, when fails
* Note : the size is returned even if no buffer is provided
* for returning the attribute, or if it is zero-sized.
*/
int ntfs_xattr_system_getxattr(struct SECURITY_CONTEXT *scx,
enum SYSTEMXATTRS attr,
ntfs_inode *ni, ntfs_inode *dir_ni,
char *value, size_t size)
{
int res;
int i;
#if POSIXACLS
#if __BYTE_ORDER == __BIG_ENDIAN
struct POSIX_ACL *acl;
#endif
#endif
switch (attr) {
case XATTR_NTFS_ACL :
res = ntfs_get_ntfs_acl(scx, ni, value, size);
break;
#if POSIXACLS
#if __BYTE_ORDER == __BIG_ENDIAN
case XATTR_POSIX_ACC :
acl = (struct POSIX_ACL*)ntfs_malloc(size);
if (acl) {
res = ntfs_get_posix_acl(scx, ni,
nf_ns_xattr_posix_access, (char*)acl, size);
if (res > 0) {
if (cpu_to_le_acl(acl,res,
(struct LE_POSIX_ACL*)value))
res = -errno;
}
free(acl);
} else
res = -errno;
break;
case XATTR_POSIX_DEF :
acl = (struct POSIX_ACL*)ntfs_malloc(size);
if (acl) {
res = ntfs_get_posix_acl(scx, ni,
nf_ns_xattr_posix_default, (char*)acl, size);
if (res > 0) {
if (cpu_to_le_acl(acl,res,
(struct LE_POSIX_ACL*)value))
res = -errno;
}
free(acl);
} else
res = -errno;
break;
#else
case XATTR_POSIX_ACC :
res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access,
value, size);
break;
case XATTR_POSIX_DEF :
res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default,
value, size);
break;
#endif
#endif
case XATTR_NTFS_ATTRIB :
res = ntfs_get_ntfs_attrib(ni, value, size);
break;
case XATTR_NTFS_ATTRIB_BE :
res = ntfs_get_ntfs_attrib(ni, value, size);
if ((res == 4) && value) {
if (size >= 4)
fix_big_endian(value,4);
else
res = -EINVAL;
}
break;
case XATTR_NTFS_EFSINFO :
if (ni->vol->efs_raw)
res = ntfs_get_efs_info(ni, value, size);
else
res = -EPERM;
break;
case XATTR_NTFS_REPARSE_DATA :
res = ntfs_get_ntfs_reparse_data(ni, value, size);
break;
case XATTR_NTFS_OBJECT_ID :
res = ntfs_get_ntfs_object_id(ni, value, size);
break;
case XATTR_NTFS_DOS_NAME:
if (dir_ni)
res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size);
else
res = -errno;
break;
case XATTR_NTFS_TIMES:
res = ntfs_inode_get_times(ni, value, size);
break;
case XATTR_NTFS_TIMES_BE:
res = ntfs_inode_get_times(ni, value, size);
if ((res > 0) && value) {
for (i=0; (i+1)*sizeof(u64)<=(unsigned int)res; i++)
fix_big_endian(&value[i*sizeof(u64)],
sizeof(u64));
}
break;
case XATTR_NTFS_CRTIME:
res = ntfs_inode_get_times(ni, value,
(size >= sizeof(u64) ? sizeof(u64) : size));
break;
case XATTR_NTFS_CRTIME_BE:
res = ntfs_inode_get_times(ni, value,
(size >= sizeof(u64) ? sizeof(u64) : size));
if ((res >= (int)sizeof(u64)) && value)
fix_big_endian(value,sizeof(u64));
break;
case XATTR_NTFS_EA :
res = ntfs_get_ntfs_ea(ni, value, size);
break;
default :
errno = EOPNOTSUPP;
res = -errno;
break;
}
return (res);
}
/*
* Set an NTFS attribute from an extended attribute
*
* Returns 0 if successful,
* non-zero, with errno set, when fails
*/
int ntfs_xattr_system_setxattr(struct SECURITY_CONTEXT *scx,
enum SYSTEMXATTRS attr,
ntfs_inode *ni, ntfs_inode *dir_ni,
const char *value, size_t size, int flags)
{
int res;
int i;
char buf[4*sizeof(u64)];
#if POSIXACLS
#if __BYTE_ORDER == __BIG_ENDIAN
struct POSIX_ACL *acl;
#endif
#endif
switch (attr) {
case XATTR_NTFS_ACL :
res = ntfs_set_ntfs_acl(scx, ni, value, size, flags);
break;
#if POSIXACLS
#if __BYTE_ORDER == __BIG_ENDIAN
case XATTR_POSIX_ACC :
acl = (struct POSIX_ACL*)ntfs_malloc(size);
if (acl) {
if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value,
size, acl)) {
res = ntfs_set_posix_acl(scx ,ni ,
nf_ns_xattr_posix_access,
(char*)acl, size, flags);
} else
res = -errno;
free(acl);
} else
res = -errno;
break;
case XATTR_POSIX_DEF :
acl = (struct POSIX_ACL*)ntfs_malloc(size);
if (acl) {
if (!le_acl_to_cpu((const struct LE_POSIX_ACL*)value,
size, acl)) {
res = ntfs_set_posix_acl(scx ,ni ,
nf_ns_xattr_posix_default,
(char*)acl, size, flags);
} else
res = -errno;
free(acl);
} else
res = -errno;
break;
#else
case XATTR_POSIX_ACC :
res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access,
value, size, flags);
break;
case XATTR_POSIX_DEF :
res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default,
value, size, flags);
break;
#endif
#endif
case XATTR_NTFS_ATTRIB :
res = ntfs_set_ntfs_attrib(ni, value, size, flags);
break;
case XATTR_NTFS_ATTRIB_BE :
if (value && (size >= 4)) {
memcpy(buf,value,4);
fix_big_endian(buf,4);
res = ntfs_set_ntfs_attrib(ni, buf, 4, flags);
} else
res = ntfs_set_ntfs_attrib(ni, value, size, flags);
break;
case XATTR_NTFS_EFSINFO :
if (ni->vol->efs_raw)
res = ntfs_set_efs_info(ni, value, size, flags);
else {
errno = EPERM;
res = -EPERM;
}
break;
case XATTR_NTFS_REPARSE_DATA :
res = ntfs_set_ntfs_reparse_data(ni, value, size, flags);
break;
case XATTR_NTFS_OBJECT_ID :
res = ntfs_set_ntfs_object_id(ni, value, size, flags);
break;
case XATTR_NTFS_DOS_NAME:
if (dir_ni)
/* warning : this closes both inodes */
res = ntfs_set_ntfs_dos_name(ni, dir_ni, value,
size, flags);
else {
errno = EINVAL;
res = -errno;
}
break;
case XATTR_NTFS_TIMES:
res = ntfs_inode_set_times(ni, value, size, flags);
break;
case XATTR_NTFS_TIMES_BE:
if (value && (size > 0) && (size <= 4*sizeof(u64))) {
memcpy(buf,value,size);
for (i=0; (i+1)*sizeof(u64)<=size; i++)
fix_big_endian(&buf[i*sizeof(u64)],
sizeof(u64));
res = ntfs_inode_set_times(ni, buf, size, flags);
} else
res = ntfs_inode_set_times(ni, value, size, flags);
break;
case XATTR_NTFS_CRTIME:
res = ntfs_inode_set_times(ni, value,
(size >= sizeof(u64) ? sizeof(u64) : size), flags);
break;
case XATTR_NTFS_CRTIME_BE:
if (value && (size >= sizeof(u64))) {
memcpy(buf,value,sizeof(u64));
fix_big_endian(buf,sizeof(u64));
res = ntfs_inode_set_times(ni, buf, sizeof(u64), flags);
} else
res = ntfs_inode_set_times(ni, value, size, flags);
break;
case XATTR_NTFS_EA :
res = ntfs_set_ntfs_ea(ni, value, size, flags);
break;
default :
errno = EOPNOTSUPP;
res = -errno;
break;
}
return (res);
}
int ntfs_xattr_system_removexattr(struct SECURITY_CONTEXT *scx,
enum SYSTEMXATTRS attr,
ntfs_inode *ni, ntfs_inode *dir_ni)
{
int res;
res = 0;
switch (attr) {
/*
* Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
* is never allowed
*/
case XATTR_NTFS_ACL :
case XATTR_NTFS_ATTRIB :
case XATTR_NTFS_ATTRIB_BE :
case XATTR_NTFS_EFSINFO :
case XATTR_NTFS_TIMES :
case XATTR_NTFS_TIMES_BE :
case XATTR_NTFS_CRTIME :
case XATTR_NTFS_CRTIME_BE :
res = -EPERM;
break;
#if POSIXACLS
case XATTR_POSIX_ACC :
case XATTR_POSIX_DEF :
if (ni) {
if (!ntfs_allowed_as_owner(scx, ni)
|| ntfs_remove_posix_acl(scx, ni,
(attr == XATTR_POSIX_ACC ?
nf_ns_xattr_posix_access :
nf_ns_xattr_posix_default)))
res = -errno;
} else
res = -errno;
break;
#endif
case XATTR_NTFS_REPARSE_DATA :
if (ni) {
if (!ntfs_allowed_as_owner(scx, ni)
|| ntfs_remove_ntfs_reparse_data(ni))
res = -errno;
} else
res = -errno;
break;
case XATTR_NTFS_OBJECT_ID :
if (ni) {
if (!ntfs_allowed_as_owner(scx, ni)
|| ntfs_remove_ntfs_object_id(ni))
res = -errno;
} else
res = -errno;
break;
case XATTR_NTFS_DOS_NAME:
if (ni && dir_ni) {
if (ntfs_remove_ntfs_dos_name(ni,dir_ni))
res = -errno;
/* ni and dir_ni have been closed */
} else
res = -errno;
break;
case XATTR_NTFS_EA :
res = ntfs_remove_ntfs_ea(ni);
break;
default :
errno = EOPNOTSUPP;
res = -errno;
break;
}
return (res);
}

View File

@ -1,195 +0,0 @@
if REALLYSTATIC
AM_LIBS = $(top_builddir)/libntfs-3g/.libs/libntfs-3g.a $(NTFSPROGS_STATIC_LIBS)
# older builds may need -static instead of newer -all-static
AM_LFLAGS = -static
STATIC_LINK = $(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
else
AM_LIBS = $(top_builddir)/libntfs-3g/libntfs-3g.la
AM_LFLAGS = $(all_libraries)
LIBTOOL_LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
endif
# Workaround to make REALLYSTATIC work with automake 1.5.
LINK=$(STATIC_LINK) $(LIBTOOL_LINK)
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 \
ntfsusermap ntfssecaudit
QUARANTINED_PROGRAM_NAMES = ntfsdump_logfile ntfsmftalloc ntfsmove ntfsck \
ntfsfallocate
man_MANS = mkntfs.8 \
ntfscat.8 \
ntfsclone.8 \
ntfscluster.8 \
ntfscmp.8 \
ntfscp.8 \
ntfsdecrypt.8 \
ntfsfallocate.8 \
ntfsfix.8 \
ntfsinfo.8 \
ntfslabel.8 \
ntfsls.8 \
ntfsprogs.8 \
ntfsresize.8 \
ntfsundelete.8
EXTRA_MANS = ntfsrecover.8 \
ntfssecaudit.8 \
ntfstruncate.8 \
ntfsusermap.8 \
ntfswipe.8
CLEANFILES = $(EXTRA_PROGRAMS)
MAINTAINERCLEANFILES = Makefile.in
if ENABLE_CRYPTO
EXTRA_PROGRAM_NAMES += ntfsdecrypt
endif
if ENABLE_EXTRAS
bin_PROGRAMS += $(EXTRA_PROGRAM_NAMES)
if ENABLE_QUARANTINED
bin_PROGRAMS += $(QUARANTINED_PROGRAM_NAMES)
endif
man_MANS += $(EXTRA_MANS)
else
EXTRA_PROGRAMS = $(EXTRA_PROGRAM_NAMES)
endif
# Set the include path.
AM_CPPFLAGS = -I$(top_srcdir)/include/ntfs-3g $(all_includes)
ntfsfix_SOURCES = ntfsfix.c utils.c utils.h
ntfsfix_LDADD = $(AM_LIBS)
ntfsfix_LDFLAGS = $(AM_LFLAGS)
mkntfs_CPPFLAGS = $(AM_CPPFLAGS) $(MKNTFS_CPPFLAGS)
mkntfs_SOURCES = attrdef.c attrdef.h boot.c boot.h sd.c sd.h mkntfs.c utils.c utils.h
mkntfs_LDADD = $(AM_LIBS) $(MKNTFS_LIBS)
mkntfs_LDFLAGS = $(AM_LFLAGS)
ntfslabel_SOURCES = ntfslabel.c utils.c utils.h
ntfslabel_LDADD = $(AM_LIBS)
ntfslabel_LDFLAGS = $(AM_LFLAGS)
ntfsinfo_SOURCES = ntfsinfo.c utils.c utils.h
ntfsinfo_LDADD = $(AM_LIBS)
ntfsinfo_LDFLAGS = $(AM_LFLAGS)
ntfsundelete_SOURCES = ntfsundelete.c ntfsundelete.h utils.c utils.h list.h
ntfsundelete_LDADD = $(AM_LIBS)
ntfsundelete_LDFLAGS = $(AM_LFLAGS)
ntfsresize_SOURCES = ntfsresize.c utils.c utils.h
ntfsresize_LDADD = $(AM_LIBS)
ntfsresize_LDFLAGS = $(AM_LFLAGS)
ntfsclone_SOURCES = ntfsclone.c utils.c utils.h
ntfsclone_LDADD = $(AM_LIBS)
ntfsclone_LDFLAGS = $(AM_LFLAGS)
ntfscluster_SOURCES = ntfscluster.c ntfscluster.h cluster.c cluster.h utils.c utils.h
ntfscluster_LDADD = $(AM_LIBS)
ntfscluster_LDFLAGS = $(AM_LFLAGS)
ntfsls_SOURCES = ntfsls.c utils.c utils.h list.h
ntfsls_LDADD = $(AM_LIBS)
ntfsls_LDFLAGS = $(AM_LFLAGS)
ntfscat_SOURCES = ntfscat.c ntfscat.h utils.c utils.h
ntfscat_LDADD = $(AM_LIBS)
ntfscat_LDFLAGS = $(AM_LFLAGS)
ntfscp_SOURCES = ntfscp.c utils.c utils.h
ntfscp_LDADD = $(AM_LIBS)
ntfscp_LDFLAGS = $(AM_LFLAGS)
ntfsck_SOURCES = ntfsck.c utils.c utils.h
ntfsck_LDADD = $(AM_LIBS)
ntfsck_LDFLAGS = $(AM_LFLAGS)
ntfscmp_SOURCES = ntfscmp.c utils.c utils.h
ntfscmp_LDADD = $(AM_LIBS)
ntfscmp_LDFLAGS = $(AM_LFLAGS)
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
ntfstruncate_LDADD = $(AM_LIBS)
ntfstruncate_LDFLAGS = $(AM_LFLAGS)
ntfsmftalloc_SOURCES = ntfsmftalloc.c utils.c utils.h
ntfsmftalloc_LDADD = $(AM_LIBS)
ntfsmftalloc_LDFLAGS = $(AM_LFLAGS)
ntfsmove_SOURCES = ntfsmove.c ntfsmove.h utils.c utils.h
ntfsmove_LDADD = $(AM_LIBS)
ntfsmove_LDFLAGS = $(AM_LFLAGS)
ntfswipe_SOURCES = ntfswipe.c ntfswipe.h utils.c utils.h
ntfswipe_LDADD = $(AM_LIBS)
ntfswipe_LDFLAGS = $(AM_LFLAGS)
ntfsdump_logfile_SOURCES= ntfsdump_logfile.c
ntfsdump_logfile_LDADD = $(AM_LIBS)
ntfsdump_logfile_LDFLAGS= $(AM_LFLAGS)
ntfsfallocate_SOURCES = ntfsfallocate.c utils.c utils.h
ntfsfallocate_LDADD = $(AM_LIBS)
ntfsfallocate_LDFLAGS = $(AM_LFLAGS)
if ENABLE_CRYPTO
ntfsdecrypt_SOURCES = ntfsdecrypt.c utils.c utils.h
ntfsdecrypt_LDADD = $(AM_LIBS) $(GNUTLS_LIBS) $(LIBGCRYPT_LIBS)
ntfsdecrypt_LDFLAGS = $(AM_LFLAGS)
ntfsdecrypt_CFLAGS = $(GNUTLS_CFLAGS) $(LIBGCRYPT_CFLAGS)
endif
# Extra targets
strip: $(bin_PROGRAMS) $(sbin_PROGRAMS)
$(STRIP) $^
libs:
(cd ../libntfs-3g && $(MAKE) libs) || exit 1;
extra: extras
extras: libs $(EXTRA_PROGRAMS)
# mkfs.ntfs[.8] hard link
if ENABLE_MOUNT_HELPER
install-exec-hook:
$(INSTALL) -d $(DESTDIR)/$(sbindir)
$(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)$(sbindir)/mkfs.ntfs
install-data-hook:
$(INSTALL) -d $(DESTDIR)$(man8dir)
$(LN_S) -f mkntfs.8 $(DESTDIR)$(man8dir)/mkfs.ntfs.8
uninstall-local:
$(RM) -f $(DESTDIR)/sbin/mkfs.ntfs
$(RM) -f $(DESTDIR)$(man8dir)/mkfs.ntfs.8
endif
endif

View File

@ -1,168 +0,0 @@
#include "attrdef.h"
/**
* attrdef_ntfs3x_array
*/
const unsigned char attrdef_ntfs3x_array[2560] = {
0x24, 0x00, 0x53, 0x00, 0x54, 0x00, 0x41, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x41, 0x00, 0x52, 0x00,
0x44, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00,
0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x41, 0x00, 0x54, 0x00, 0x54, 0x00, 0x52, 0x00, 0x49, 0x00, 0x42, 0x00, 0x55, 0x00,
0x54, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x53, 0x00, 0x54, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x46, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x45, 0x00, 0x5F, 0x00, 0x4E, 0x00, 0x41, 0x00,
0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00,
0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x4F, 0x00, 0x42, 0x00, 0x4A, 0x00, 0x45, 0x00, 0x43, 0x00, 0x54, 0x00, 0x5F, 0x00,
0x49, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x53, 0x00, 0x45, 0x00, 0x43, 0x00, 0x55, 0x00, 0x52, 0x00, 0x49, 0x00, 0x54, 0x00,
0x59, 0x00, 0x5F, 0x00, 0x44, 0x00, 0x45, 0x00, 0x53, 0x00, 0x43, 0x00, 0x52, 0x00, 0x49, 0x00,
0x50, 0x00, 0x54, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00,
0x4E, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x56, 0x00, 0x4F, 0x00, 0x4C, 0x00, 0x55, 0x00, 0x4D, 0x00, 0x45, 0x00, 0x5F, 0x00,
0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00,
0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x44, 0x00, 0x41, 0x00, 0x54, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x52, 0x00,
0x4F, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x45, 0x00, 0x58, 0x00, 0x5F, 0x00, 0x41, 0x00,
0x4C, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x43, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00,
0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x42, 0x00, 0x49, 0x00, 0x54, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x50, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x24, 0x00, 0x52, 0x00, 0x45, 0x00, 0x50, 0x00, 0x41, 0x00, 0x52, 0x00, 0x53, 0x00, 0x45, 0x00,
0x5F, 0x00, 0x50, 0x00, 0x4F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00,
0x52, 0x00, 0x4D, 0x00, 0x41, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x45, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x4C, 0x00, 0x4F, 0x00, 0x47, 0x00, 0x47, 0x00, 0x45, 0x00, 0x44, 0x00, 0x5F, 0x00,
0x55, 0x00, 0x54, 0x00, 0x49, 0x00, 0x4C, 0x00, 0x49, 0x00, 0x54, 0x00, 0x59, 0x00, 0x5F, 0x00,
0x53, 0x00, 0x54, 0x00, 0x52, 0x00, 0x45, 0x00, 0x41, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

View File

@ -1,7 +0,0 @@
#ifndef _NTFS_ATTRDEF_H_
#define _NTFS_ATTRDEF_H_
extern const unsigned char attrdef_ntfs3x_array[2560];
#endif /* _NTFS_ATTRDEF_H_ */

View File

@ -1,103 +0,0 @@
/*
* NTFS bootsector, adapted from the vfat one.
*/
/* mkfs.fat.c - utility to create FAT/MS-DOS filesystems
* Copyright (C) 1991 Linus Torvalds <torvalds@klaava.helsinki.fi>
* Copyright (C) 1992-1993 Remy Card <card@masi.ibp.fr>
* Copyright (C) 1993-1994 David Hudson <dave@humbug.demon.co.uk>
* Copyright (C) 1998 H. Peter Anvin <hpa@zytor.com>
* Copyright (C) 1998-2005 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
* Copyright (C) 2008-2014 Daniel Baumann <mail@daniel-baumann.ch>
* Copyright (C) 2015 Andreas Bombe <aeb@debian.org>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* The complete text of the GNU General Public License
* can be found in /usr/share/common-licenses/GPL-3 file.
*/
#include "boot.h"
#define BOOTCODE_SIZE 4136
/* The "boot code" we put into the filesystem... it writes a message and
* tells the user to try again */
#define MSG_OFFSET_OFFSET 3
const unsigned char boot_array[BOOTCODE_SIZE] =
"\xeb\x52\x90" /* jump to code at 0x54 (0x7c54) */
"NTFS \0" /* NTFS signature */
"\0\0\0\0\0\0\0\0\0\0\0\0" /* 72 bytes for device parameters */
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
/* Boot code run at location 0x7c54 */
"\x0e" /* push cs */
"\x1f" /* pop ds */
"\xbe\x71\x7c" /* mov si, offset message_txt (at location 0x7c71) */
/* write_msg: */
"\xac" /* lodsb */
"\x22\xc0" /* and al, al */
"\x74\x0b" /* jz key_press */
"\x56" /* push si */
"\xb4\x0e" /* mov ah, 0eh */
"\xbb\x07\x00" /* mov bx, 0007h */
"\xcd\x10" /* int 10h */
"\x5e" /* pop si */
"\xeb\xf0" /* jmp write_msg */
/* key_press: */
"\x32\xe4" /* xor ah, ah */
"\xcd\x16" /* int 16h */
"\xcd\x19" /* int 19h */
"\xeb\xfe" /* foo: jmp foo */
/* message_txt: */
"This is not a bootable disk. Please insert a bootable floppy and\r\n"
"press any key to try again ... \r\n"
/* At location 0xd4, 298 bytes to reach 0x1fe */
/* 298 = 4 blocks of 72 then 10 */
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0"
/* Boot signature at 0x1fe */
"\x55\xaa";

View File

@ -1,7 +0,0 @@
#ifndef _NTFS_BOOT_H_
#define _NTFS_BOOT_H_
extern const unsigned char boot_array[4136];
#endif /* _NTFS_BOOT_H_ */

View File

@ -1,132 +0,0 @@
/**
* cluster - Part of the Linux-NTFS project.
*
* Copyright (c) 2002-2003 Richard Russon
* Copyright (c) 2014 Jean-Pierre Andre
*
* This function will locate the owner of any given sector or cluster range.
*
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include "cluster.h"
#include "utils.h"
#include "logging.h"
/**
* cluster_find
*/
int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data)
{
int j;
int result = -1;
struct mft_search_ctx *m_ctx = NULL;
ntfs_attr_search_ctx *a_ctx = NULL;
s64 count;
BOOL found;
ATTR_RECORD *rec;
runlist *runs;
if (!vol || !cb)
return -1;
m_ctx = mft_get_search_ctx(vol);
m_ctx->flags_search = FEMR_IN_USE | FEMR_BASE_RECORD;
count = 0;
while (mft_next_record(m_ctx) == 0) {
if (!(m_ctx->flags_match & FEMR_BASE_RECORD))
continue;
ntfs_log_verbose("Inode: %llu\n", (unsigned long long)
m_ctx->inode->mft_no);
a_ctx = ntfs_attr_get_search_ctx(m_ctx->inode, NULL);
found = FALSE;
while ((rec = find_attribute(AT_UNUSED, a_ctx))) {
if (!rec->non_resident) {
ntfs_log_verbose("0x%02x skipped - attr is resident\n",
(int)le32_to_cpu(a_ctx->attr->type));
continue;
}
runs = ntfs_mapping_pairs_decompress(vol, a_ctx->attr, NULL);
if (!runs) {
ntfs_log_error("Couldn't read the data runs.\n");
goto done;
}
ntfs_log_verbose("\t[0x%02X]\n",
(int)le32_to_cpu(a_ctx->attr->type));
ntfs_log_verbose("\t\tVCN\tLCN\tLength\n");
for (j = 0; runs[j].length > 0; j++) {
LCN a_begin = runs[j].lcn;
LCN a_end = a_begin + runs[j].length - 1;
if (a_begin < 0)
continue; // sparse, discontiguous, etc
ntfs_log_verbose("\t\t%lld\t%lld-%lld (%lld)\n",
(long long)runs[j].vcn,
(long long)runs[j].lcn,
(long long)(runs[j].lcn +
runs[j].length - 1),
(long long)runs[j].length);
//dprint list
if ((a_begin > c_end) || (a_end < c_begin))
continue; // before or after search range
if ((*cb) (m_ctx->inode, a_ctx->attr, runs+j, data))
return 1;
found = TRUE;
}
}
ntfs_attr_put_search_ctx(a_ctx);
a_ctx = NULL;
if (found)
count++;
}
if (count > 1)
ntfs_log_info("* %lld inodes found\n",(long long)count);
else
ntfs_log_info("* %s inode found\n", (count ? "one" : "no"));
result = 0;
done:
ntfs_attr_put_search_ctx(a_ctx);
mft_put_search_ctx(m_ctx);
return result;
}

View File

@ -1,39 +0,0 @@
/*
* cluster - Part of the Linux-NTFS project.
*
* Copyright (c) 2003 Richard Russon
*
* This function will locate the owner of any given sector or cluster range.
*
* 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 Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CLUSTER_H_
#define _CLUSTER_H_
#include "types.h"
#include "volume.h"
typedef struct {
int x;
} ntfs_cluster;
typedef int (cluster_cb)(ntfs_inode *ino, ATTR_RECORD *attr, runlist_element *run, void *data);
int cluster_find(ntfs_volume *vol, LCN c_begin, LCN c_end, cluster_cb *cb, void *data);
#endif /* _CLUSTER_H_ */

View File

@ -1,194 +0,0 @@
/*
* list.h - Linked list implementation. Part of the Linux-NTFS project.
*
* Copyright (c) 2000-2002 Anton Altaparmakov and others
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _NTFS_LIST_H
#define _NTFS_LIST_H
/**
* struct ntfs_list_head - Simple doubly linked list implementation.
*
* Copied from Linux kernel 2.4.2-ac18 into Linux-NTFS (with minor
* modifications). - AIA
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct ntfs_list_head {
struct ntfs_list_head *next, *prev;
};
#define NTFS_LIST_HEAD_INIT(name) { &(name), &(name) }
#define NTFS_LIST_HEAD(name) \
struct ntfs_list_head name = NTFS_LIST_HEAD_INIT(name)
#define NTFS_INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/**
* __ntfs_list_add - Insert a new entry between two known consecutive entries.
* @new:
* @prev:
* @next:
*
* This is only for internal list manipulation where we know the prev/next
* entries already!
*/
static __inline__ void __ntfs_list_add(struct ntfs_list_head * new,
struct ntfs_list_head * prev, struct ntfs_list_head * next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/**
* ntfs_list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static __inline__ void ntfs_list_add(struct ntfs_list_head *new,
struct ntfs_list_head *head)
{
__ntfs_list_add(new, head, head->next);
}
/**
* ntfs_list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static __inline__ void ntfs_list_add_tail(struct ntfs_list_head *new,
struct ntfs_list_head *head)
{
__ntfs_list_add(new, head->prev, head);
}
/**
* __ntfs_list_del -
* @prev:
* @next:
*
* Delete a list entry by making the prev/next entries point to each other.
*
* This is only for internal list manipulation where we know the prev/next
* entries already!
*/
static __inline__ void __ntfs_list_del(struct ntfs_list_head * prev,
struct ntfs_list_head * next)
{
next->prev = prev;
prev->next = next;
}
/**
* ntfs_list_del - deletes entry from list.
* @entry: the element to delete from the list.
*
* Note: ntfs_list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
static __inline__ void ntfs_list_del(struct ntfs_list_head *entry)
{
__ntfs_list_del(entry->prev, entry->next);
}
/**
* ntfs_list_del_init - deletes entry from list and reinitialize it.
* @entry: the element to delete from the list.
*/
static __inline__ void ntfs_list_del_init(struct ntfs_list_head *entry)
{
__ntfs_list_del(entry->prev, entry->next);
NTFS_INIT_LIST_HEAD(entry);
}
/**
* ntfs_list_empty - tests whether a list is empty
* @head: the list to test.
*/
static __inline__ int ntfs_list_empty(struct ntfs_list_head *head)
{
return head->next == head;
}
/**
* ntfs_list_splice - join two lists
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
static __inline__ void ntfs_list_splice(struct ntfs_list_head *list,
struct ntfs_list_head *head)
{
struct ntfs_list_head *first = list->next;
if (first != list) {
struct ntfs_list_head *last = list->prev;
struct ntfs_list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
}
/**
* ntfs_list_entry - get the struct for this entry
* @ptr: the &struct ntfs_list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define ntfs_list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
/**
* ntfs_list_for_each - iterate over a list
* @pos: the &struct ntfs_list_head to use as a loop counter.
* @head: the head for your list.
*/
#define ntfs_list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* ntfs_list_for_each_safe - iterate over a list safe against removal of list entry
* @pos: the &struct ntfs_list_head to use as a loop counter.
* @n: another &struct ntfs_list_head to use as temporary storage
* @head: the head for your list.
*/
#define ntfs_list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
#endif /* defined _NTFS_LIST_H */

View File

@ -1,292 +0,0 @@
.\" Copyright (c) 2001\-2006 Anton Altaparmakov.
.\" Copyright (c) 2005 Richard Russon.
.\" Copyright (c) 2005\-2006 Szabolcs Szakacsits.
.\" This file may be copied under the terms of the GNU Public License.
.\"
.TH MKNTFS 8 "January 2006" "ntfs-3g @VERSION@"
.SH NAME
mkntfs \- create an NTFS file system
.SH SYNOPSIS
.B mkntfs
[\fIoptions\fR] \fIdevice \fR[\fInumber\-of\-sectors\fR]
.PP
.B mkntfs
[
.B \-C
]
[
.B \-c
.I cluster\-size
]
[
.B \-F
]
[
.B \-f
]
[
.B \-H
.I heads
]
[
.B \-h
]
[
.B \-I
]
[
.B \-L
.I volume\-label
]
[
.B \-l
]
[
.B \-n
]
[
.B \-p
.I part\-start\-sect
]
[
.B \-Q
]
[
.B \-q
]
[
.B \-S
.I sectors\-per\-track
]
[
.B \-s
.I sector\-size
]
[
.B \-T
]
[
.B \-U
]
[
.B \-V
]
[
.B \-v
]
[
.B \-z
.I mft\-zone\-multiplier
]
[
.B \-\-debug
]
.I device
[
.I number\-of\-sectors
]
.SH DESCRIPTION
.B mkntfs
is used to create an NTFS file system on a device (usually a disk partition)
or file.
.I device
is the special file corresponding to the device (e.g
.IR /dev/hdXX ).
.I number\-of\-sectors
is the number of sectors on the device. If omitted,
.B mkntfs
automagically figures the file system size.
.SH OPTIONS
Below is a summary of all the options that
.B mkntfs
accepts. Nearly all options have two equivalent names. The short name is
preceded by
.B \-
and the long name is preceded by
.BR \-\- .
Any single letter options, that don't take an argument, can be combined into a
single command, e.g.
.B \-fv
is equivalent to
.BR "\-f \-v" .
Long named options can be abbreviated to any unique prefix of their name.
.SS Basic options
.TP
\fB\-f\fR, \fB\-\-fast\fR, \fB\-Q\fR, \fB\-\-quick\fR
Perform quick (fast) format. This will skip both zeroing of the volume and bad
sector checking.
.TP
\fB\-L\fR, \fB\-\-label\fR STRING
Set the volume label for the filesystem.
.TP
\fB\-C\fR, \fB\-\-enable\-compression\fR
Enable compression on the volume.
.TP
\fB\-n\fR, \fB\-\-no\-action\fR
Causes
.B mkntfs
to not actually create a filesystem, but display what it would do if it were
to create a filesystem. All steps of the format are carried out except the
actual writing to the device.
.SS Advanced options
.TP
\fB\-c\fR, \fB\-\-cluster\-size\fR BYTES
Specify the size of clusters in bytes. Valid cluster size values are powers of
two, with at least 256, and at most 2097152 bytes (2MB) per cluster. If omitted,
.B mkntfs
uses 4096 bytes as the default cluster size.
.sp
Note that the default cluster size is set to be at least equal to the sector
size as a cluster cannot be smaller than a sector. Also, note that values
greater than 4096 have the side effect that compression is disabled on the
volume (due to limitations in the NTFS compression algorithm currently in use
by Windows).
.TP
\fB\-s\fR, \fB\-\-sector\-size\fR BYTES
Specify the size of sectors in bytes. Valid sector size values are 256, 512,
1024, 2048 and 4096 bytes per sector. If omitted,
.B mkntfs
attempts to determine the
.I sector\-size
automatically and if that fails a default of 512 bytes per sector is used.
.TP
\fB\-p\fR, \fB\-\-partition\-start\fR SECTOR
Specify the partition start sector. The maximum is 4294967295 (2^32\-1). If
omitted,
.B mkntfs
attempts to determine
.I part\-start\-sect
automatically and if that fails or the value is oversized, a
default of 0 is used. The partition is usable despite a wrong value,
however note that a correct
.I part\-start\-sect
is required for Windows to be able to boot from the created volume.
.TP
\fB\-H\fR, \fB\-\-heads\fR NUM
Specify the number of heads. The maximum is 65535 (0xffff). If omitted,
.B mkntfs
attempts to determine the number of
.I heads
automatically and if that fails a default of 0 is used. Note that
.I heads
is required for Windows to be able to boot from the created volume.
.TP
\fB\-S\fR, \fB\-\-sectors\-per\-track\fR NUM
Specify the number of sectors per track. The maximum is 65535 (0xffff). If
omitted,
.B mkntfs
attempts to determine the number of
.I sectors\-per\-track
automatically and if that fails a default of 0 is used. Note that
.I sectors\-per\-track
is required for Windows to be able to boot from the created volume.
.TP
\fB\-z\fR, \fB\-\-mft\-zone\-multiplier\fR NUM
Set the MFT zone multiplier, which determines the size of the MFT zone to use
on the volume. The MFT zone is the area at the beginning of the volume reserved
for the master file table (MFT), which stores the on disk inodes (MFT records).
It is noteworthy that small files are stored entirely within the inode;
thus, if you expect to use the volume for storing large numbers of very small
files, it is useful to set the zone multiplier to a higher value. Note, that
the MFT zone is resized on the fly as required during operation of the NTFS
driver but choosing a good value will reduce fragmentation. Valid values
are 1, 2, 3 and 4. The values have the following meaning:
.TS
box;
lB lB
lB lB
c l.
MFT zone MFT zone size
multiplier (% of volume size)
1 12.5% (default)
2 25.0%
3 37.5%
4 50.0%
.TE
.sp
.TP
\fB\-T\fR, \fB\-\-zero\-time\fR
Fake the time to be 00:00:00 UTC, Jan 1, 1970 instead of the current system
time. This is only really useful for debugging purposes.
.TP
\fB\-U\fR, \fB\-\-with\-uuid\fR
Generate a random volume UUID.
.TP
\fB\-I\fR, \fB\-\-no\-indexing\fR
Disable content indexing on the volume. (This is only meaningful on
Windows 2000 and later. Windows NT 4.0 and earlier ignore this as they do
not implement content indexing at all.)
.TP
\fB\-F\fR, \fB\-\-force\fR
Force
.B mkntfs
to run, even if the specified
.I device
is not a block special device, or appears to be mounted.
.SS Output options
.TP
\fB\-q\fR, \fB\-\-quiet\fR
Quiet execution; only errors are written to stderr, no output to stdout
occurs at all. Useful if
.B mkntfs
is run in a script.
.TP
\fB\-v\fR, \fB\-\-verbose\fR
Verbose execution.
.TP
\fB\-\-debug\fR
Really verbose execution; includes the verbose output from the
.B \-v
option as well as additional output useful for debugging
.B mkntfs.
.SS Help options
.TP
\fB\-V\fR, \fB\-\-version\fR
Print the version number of
.B mkntfs
and exit.
.TP
\fB\-l\fR, \fB\-\-license\fR
Print the licensing information of
.B mkntfs
and exit.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show a list of options with a brief description of each one.
.SH KNOWN ISSUES
When applying chkdsk to a file system, it sometimes throws a warning
"Correcting errors in the uppercase file." The uppercase file is created
while formatting and it defines the mapping of lower case characters to
upper case ones, as needed to sort file names in directories. The warning
means that the uppercase file defined on the file system is not the same as
the one used by the Windows OS on which chkdsk is running, and this may
happen because newer versions of Windows take into account new characters
defined by the Unicode consortium.
.P
Currently, mkntfs creates the uppercase table so that no warning is thrown
by Windows Vista, Windows 7 or Windows 8. A warning may be thrown by
other Windows versions, or if chkdsk is applied in succession on different
Windows versions.
.SH BUGS
If you find a bug please send an email describing the problem to the
development team:
.br
.nh
ntfs\-3g\-devel@lists.sf.net
.hy
.SH AUTHORS
.B mkntfs
was written by Anton Altaparmakov, Richard Russon, Erik Sornes and Szabolcs Szakacsits.
It was ported to ntfs-3g by Erik Larsson and Jean-Pierre Andre.
.SH AVAILABILITY
.B mkntfs
is part of the
.B ntfs-3g
package and is available from:
.br
.nh
https://github.com/tuxera/ntfs-3g/wiki/
.hy
.SH SEE ALSO
.BR badblocks (8),
.BR ntfsprogs (8)

Some files were not shown because too many files have changed in this diff Show More